Skip to main content

arrow_schema/extension/canonical/
uuid.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5//! UUID
6//!
7//! <https://arrow.apache.org/docs/format/CanonicalExtensions.html#uuid>
8
9use crate::{ArrowError, DataType, extension::ExtensionType};
10
11/// The extension type for `UUID`.
12///
13/// Extension name: `arrow.uuid`.
14///
15/// The storage type of the extension is `FixedSizeBinary` with a length of
16/// 16 bytes.
17///
18/// Note:
19/// A specific UUID version is not required or guaranteed. This extension
20/// represents UUIDs as `FixedSizeBinary(16)` with big-endian notation and
21/// does not interpret the bytes in any way.
22///
23/// <https://arrow.apache.org/docs/format/CanonicalExtensions.html#uuid>
24#[derive(Debug, Default, Clone, Copy, PartialEq)]
25pub struct Uuid;
26
27impl ExtensionType for Uuid {
28    const NAME: &'static str = "arrow.uuid";
29
30    type Metadata = ();
31
32    fn metadata(&self) -> &Self::Metadata {
33        &()
34    }
35
36    fn serialize_metadata(&self) -> Option<String> {
37        None
38    }
39
40    fn deserialize_metadata(metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
41        metadata.map_or_else(
42            || Ok(()),
43            |v| {
44                if !v.is_empty() {
45                    Err(ArrowError::InvalidArgumentError(
46                        "Uuid extension type expects no metadata".to_owned(),
47                    ))
48                } else {
49                    Ok(())
50                }
51            },
52        )
53    }
54
55    fn supports_data_type(&self, data_type: &DataType) -> Result<(), ArrowError> {
56        match data_type {
57            DataType::FixedSizeBinary(16) => Ok(()),
58            data_type => Err(ArrowError::InvalidArgumentError(format!(
59                "Uuid data type mismatch, expected FixedSizeBinary(16), found {data_type}"
60            ))),
61        }
62    }
63
64    fn try_new(data_type: &DataType, _metadata: Self::Metadata) -> Result<Self, ArrowError> {
65        Self.supports_data_type(data_type).map(|()| Self)
66    }
67
68    fn validate(data_type: &DataType, _metadata: Self::Metadata) -> Result<(), ArrowError> {
69        Self.supports_data_type(data_type)
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    #[cfg(feature = "canonical_extension_types")]
76    use crate::extension::CanonicalExtensionType;
77    use crate::{
78        Field,
79        extension::{EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY},
80    };
81
82    use super::*;
83
84    #[test]
85    fn valid() -> Result<(), ArrowError> {
86        let mut field = Field::new("", DataType::FixedSizeBinary(16), false);
87        field.try_with_extension_type(Uuid)?;
88        field.try_extension_type::<Uuid>()?;
89        #[cfg(feature = "canonical_extension_types")]
90        assert_eq!(
91            field.try_canonical_extension_type()?,
92            CanonicalExtensionType::Uuid(Uuid)
93        );
94        Ok(())
95    }
96
97    #[test]
98    #[should_panic(expected = "Extension type name missing")]
99    fn missing_name() {
100        let field = Field::new("", DataType::FixedSizeBinary(16), false);
101        field.extension_type::<Uuid>();
102    }
103
104    #[test]
105    #[should_panic(expected = "expected FixedSizeBinary(16), found FixedSizeBinary(8)")]
106    fn invalid_type() {
107        Field::new("", DataType::FixedSizeBinary(8), false).with_extension_type(Uuid);
108    }
109
110    #[test]
111    #[should_panic(expected = "Uuid extension type expects no metadata")]
112    fn with_metadata() {
113        let field = Field::new("", DataType::FixedSizeBinary(16), false).with_metadata([
114            (EXTENSION_TYPE_NAME_KEY, Uuid::NAME),
115            (EXTENSION_TYPE_METADATA_KEY, "unexpected"),
116        ]);
117        field.extension_type::<Uuid>();
118    }
119
120    #[test]
121    fn empty_metadata_string_is_treated_as_none() -> Result<(), ArrowError> {
122        let field = Field::new("", DataType::FixedSizeBinary(16), false).with_metadata([
123            (EXTENSION_TYPE_NAME_KEY, Uuid::NAME),
124            (EXTENSION_TYPE_METADATA_KEY, ""),
125        ]);
126        field.try_extension_type::<Uuid>()?;
127        Ok(())
128    }
129}