Skip to main content

arrow_schema/extension/canonical/
opaque.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//! Opaque
6//!
7//! <https://arrow.apache.org/docs/format/CanonicalExtensions.html#opaque>
8
9use serde_core::ser::SerializeStruct;
10use serde_core::{
11    Deserialize, Deserializer, Serialize, Serializer,
12    de::{MapAccess, Visitor},
13};
14
15use crate::{ArrowError, DataType, extension::ExtensionType};
16
17/// The extension type for `Opaque`.
18///
19/// Extension name: `arrow.opaque`.
20///
21/// Opaque represents a type that an Arrow-based system received from an
22/// external (often non-Arrow) system, but that it cannot interpret. In this
23/// case, it can pass on Opaque to its clients to at least show that a field
24/// exists and preserve metadata about the type from the other system.
25///
26/// The storage type of this extension is any type. If there is no underlying
27/// data, the storage type should be Null.
28#[derive(Debug, Clone, PartialEq)]
29pub struct Opaque(OpaqueMetadata);
30
31impl Opaque {
32    /// Returns a new `Opaque` extension type.
33    pub fn new(type_name: impl Into<String>, vendor_name: impl Into<String>) -> Self {
34        Self(OpaqueMetadata::new(type_name, vendor_name))
35    }
36
37    /// Returns the name of the unknown type in the external system.
38    pub fn type_name(&self) -> &str {
39        self.0.type_name()
40    }
41
42    /// Returns the name of the external system.
43    pub fn vendor_name(&self) -> &str {
44        self.0.vendor_name()
45    }
46}
47
48impl From<OpaqueMetadata> for Opaque {
49    fn from(value: OpaqueMetadata) -> Self {
50        Self(value)
51    }
52}
53
54/// Extension type metadata for [`Opaque`].
55#[derive(Debug, Clone, PartialEq)]
56pub struct OpaqueMetadata {
57    /// Name of the unknown type in the external system.
58    type_name: String,
59
60    /// Name of the external system.
61    vendor_name: String,
62}
63
64impl Serialize for OpaqueMetadata {
65    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
66    where
67        S: Serializer,
68    {
69        let mut state = serializer.serialize_struct("OpaqueMetadata", 2)?;
70        state.serialize_field("type_name", &self.type_name)?;
71        state.serialize_field("vendor_name", &self.vendor_name)?;
72        state.end()
73    }
74}
75
76#[derive(Debug)]
77enum MetadataField {
78    TypeName,
79    VendorName,
80}
81
82struct MetadataFieldVisitor;
83
84impl Visitor<'_> for MetadataFieldVisitor {
85    type Value = MetadataField;
86
87    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
88        formatter.write_str("`type_name` or `vendor_name`")
89    }
90
91    fn visit_str<E>(self, value: &str) -> Result<MetadataField, E>
92    where
93        E: serde_core::de::Error,
94    {
95        match value {
96            "type_name" => Ok(MetadataField::TypeName),
97            "vendor_name" => Ok(MetadataField::VendorName),
98            _ => Err(serde_core::de::Error::unknown_field(
99                value,
100                &["type_name", "vendor_name"],
101            )),
102        }
103    }
104}
105
106impl<'de> Deserialize<'de> for MetadataField {
107    fn deserialize<D>(deserializer: D) -> Result<MetadataField, D::Error>
108    where
109        D: Deserializer<'de>,
110    {
111        deserializer.deserialize_identifier(MetadataFieldVisitor)
112    }
113}
114
115struct OpaqueMetadataVisitor;
116
117impl<'de> Visitor<'de> for OpaqueMetadataVisitor {
118    type Value = OpaqueMetadata;
119
120    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
121        formatter.write_str("struct OpaqueMetadata")
122    }
123
124    fn visit_seq<V>(self, mut seq: V) -> Result<OpaqueMetadata, V::Error>
125    where
126        V: serde_core::de::SeqAccess<'de>,
127    {
128        let type_name = seq
129            .next_element()?
130            .ok_or_else(|| serde_core::de::Error::invalid_length(0, &self))?;
131        let vendor_name = seq
132            .next_element()?
133            .ok_or_else(|| serde_core::de::Error::invalid_length(1, &self))?;
134        Ok(OpaqueMetadata {
135            type_name,
136            vendor_name,
137        })
138    }
139
140    fn visit_map<V>(self, mut map: V) -> Result<OpaqueMetadata, V::Error>
141    where
142        V: MapAccess<'de>,
143    {
144        let mut type_name = None;
145        let mut vendor_name = None;
146
147        while let Some(key) = map.next_key()? {
148            match key {
149                MetadataField::TypeName => {
150                    if type_name.is_some() {
151                        return Err(serde_core::de::Error::duplicate_field("type_name"));
152                    }
153                    type_name = Some(map.next_value()?);
154                }
155                MetadataField::VendorName => {
156                    if vendor_name.is_some() {
157                        return Err(serde_core::de::Error::duplicate_field("vendor_name"));
158                    }
159                    vendor_name = Some(map.next_value()?);
160                }
161            }
162        }
163
164        let type_name =
165            type_name.ok_or_else(|| serde_core::de::Error::missing_field("type_name"))?;
166        let vendor_name =
167            vendor_name.ok_or_else(|| serde_core::de::Error::missing_field("vendor_name"))?;
168
169        Ok(OpaqueMetadata {
170            type_name,
171            vendor_name,
172        })
173    }
174}
175
176impl<'de> Deserialize<'de> for OpaqueMetadata {
177    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
178    where
179        D: Deserializer<'de>,
180    {
181        deserializer.deserialize_struct(
182            "OpaqueMetadata",
183            &["type_name", "vendor_name"],
184            OpaqueMetadataVisitor,
185        )
186    }
187}
188
189impl OpaqueMetadata {
190    /// Returns a new `OpaqueMetadata`.
191    pub fn new(type_name: impl Into<String>, vendor_name: impl Into<String>) -> Self {
192        OpaqueMetadata {
193            type_name: type_name.into(),
194            vendor_name: vendor_name.into(),
195        }
196    }
197
198    /// Returns the name of the unknown type in the external system.
199    pub fn type_name(&self) -> &str {
200        &self.type_name
201    }
202
203    /// Returns the name of the external system.
204    pub fn vendor_name(&self) -> &str {
205        &self.vendor_name
206    }
207}
208
209impl ExtensionType for Opaque {
210    const NAME: &'static str = "arrow.opaque";
211
212    type Metadata = OpaqueMetadata;
213
214    fn metadata(&self) -> &Self::Metadata {
215        &self.0
216    }
217
218    fn serialize_metadata(&self) -> Option<String> {
219        Some(serde_json::to_string(self.metadata()).expect("metadata serialization"))
220    }
221
222    fn deserialize_metadata(metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
223        metadata.map_or_else(
224            || {
225                Err(ArrowError::InvalidArgumentError(
226                    "Opaque extension types requires metadata".to_owned(),
227                ))
228            },
229            |value| {
230                serde_json::from_str(value).map_err(|e| {
231                    ArrowError::InvalidArgumentError(format!(
232                        "Opaque metadata deserialization failed: {e}"
233                    ))
234                })
235            },
236        )
237    }
238
239    fn supports_data_type(&self, _data_type: &DataType) -> Result<(), ArrowError> {
240        // Any type
241        Ok(())
242    }
243
244    fn try_new(_data_type: &DataType, metadata: Self::Metadata) -> Result<Self, ArrowError> {
245        Ok(Self::from(metadata))
246    }
247
248    fn validate(_data_type: &DataType, _metadata: Self::Metadata) -> Result<(), ArrowError> {
249        Ok(())
250    }
251}
252
253#[cfg(test)]
254mod tests {
255    #[cfg(feature = "canonical_extension_types")]
256    use crate::extension::CanonicalExtensionType;
257    use crate::{
258        Field,
259        extension::{EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY},
260    };
261
262    use super::*;
263
264    #[test]
265    fn valid() -> Result<(), ArrowError> {
266        let opaque = Opaque::new("name", "vendor");
267        let mut field = Field::new("", DataType::Null, false);
268        field.try_with_extension_type(opaque.clone())?;
269        assert_eq!(field.try_extension_type::<Opaque>()?, opaque);
270        #[cfg(feature = "canonical_extension_types")]
271        assert_eq!(
272            field.try_canonical_extension_type()?,
273            CanonicalExtensionType::Opaque(opaque)
274        );
275        Ok(())
276    }
277
278    #[test]
279    #[should_panic(expected = "Extension type name missing")]
280    fn missing_name() {
281        let field = Field::new("", DataType::Null, false).with_metadata([(
282            EXTENSION_TYPE_METADATA_KEY,
283            r#"{ "type_name": "type", "vendor_name": "vendor" }"#,
284        )]);
285        field.extension_type::<Opaque>();
286    }
287
288    #[test]
289    #[should_panic(expected = "Opaque extension types requires metadata")]
290    fn missing_metadata() {
291        let field = Field::new("", DataType::Null, false)
292            .with_metadata([(EXTENSION_TYPE_NAME_KEY, Opaque::NAME)]);
293        field.extension_type::<Opaque>();
294    }
295
296    #[test]
297    #[should_panic(
298        expected = "Opaque metadata deserialization failed: missing field `vendor_name`"
299    )]
300    fn invalid_metadata() {
301        let field = Field::new("", DataType::Null, false).with_metadata([
302            (EXTENSION_TYPE_NAME_KEY, Opaque::NAME),
303            (
304                EXTENSION_TYPE_METADATA_KEY,
305                r#"{ "type_name": "no-vendor" }"#,
306            ),
307        ]);
308        field.extension_type::<Opaque>();
309    }
310}