Skip to main content

arrow_schema/extension/canonical/
uuid.rs

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