Skip to main content

arrow_schema/extension/canonical/
mod.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//! Canonical extension types.
6//!
7//! The Arrow columnar format allows defining extension types so as to extend
8//! standard Arrow data types with custom semantics. Often these semantics will
9//! be specific to a system or application. However, it is beneficial to share
10//! the definitions of well-known extension types so as to improve
11//! interoperability between different systems integrating Arrow columnar data.
12//!
13//! <https://arrow.apache.org/docs/format/CanonicalExtensions.html#format-canonical-extensions>
14
15mod bool8;
16pub use bool8::Bool8;
17mod fixed_shape_tensor;
18pub use fixed_shape_tensor::{FixedShapeTensor, FixedShapeTensorMetadata};
19mod json;
20pub use json::{Json, JsonMetadata};
21mod opaque;
22pub use opaque::{Opaque, OpaqueMetadata};
23mod timestamp_with_offset;
24pub use timestamp_with_offset::TimestampWithOffset;
25mod uuid;
26pub use uuid::Uuid;
27mod variable_shape_tensor;
28pub use variable_shape_tensor::{VariableShapeTensor, VariableShapeTensorMetadata};
29mod variant;
30pub use variant::VariantType;
31
32use crate::{ArrowError, Field};
33
34use super::ExtensionType;
35
36/// Canonical extension types.
37///
38/// <https://arrow.apache.org/docs/format/CanonicalExtensions.html#format-canonical-extensions>
39#[non_exhaustive]
40#[derive(Debug, Clone, PartialEq)]
41pub enum CanonicalExtensionType {
42    /// The extension type for `FixedShapeTensor`.
43    ///
44    /// <https://arrow.apache.org/docs/format/CanonicalExtensions.html#fixed-shape-tensor>
45    FixedShapeTensor(FixedShapeTensor),
46
47    /// The extension type for `VariableShapeTensor`.
48    ///
49    /// <https://arrow.apache.org/docs/format/CanonicalExtensions.html#variable-shape-tensor>
50    VariableShapeTensor(VariableShapeTensor),
51
52    /// The extension type for 'JSON'.
53    ///
54    /// <https://arrow.apache.org/docs/format/CanonicalExtensions.html#json>
55    Json(Json),
56
57    /// The extension type for `UUID`.
58    ///
59    /// <https://arrow.apache.org/docs/format/CanonicalExtensions.html#uuid>
60    Uuid(Uuid),
61
62    /// The extension type for `Opaque`.
63    ///
64    /// <https://arrow.apache.org/docs/format/CanonicalExtensions.html#opaque>
65    Opaque(Opaque),
66
67    /// The extension type for `Bool8`.
68    ///
69    /// <https://arrow.apache.org/docs/format/CanonicalExtensions.html#bit-boolean>
70    Bool8(Bool8),
71
72    /// The extension type for `TimestampWithOffset`.
73    ///
74    /// <https://arrow.apache.org/docs/format/CanonicalExtensions.html#timestamp-with-offset>
75    TimestampWithOffset(TimestampWithOffset),
76
77    /// The extension type for Parquet Variant.
78    ///
79    /// <https://arrow.apache.org/docs/format/CanonicalExtensions.html#parquet-variant>
80    Variant(VariantType),
81}
82
83impl TryFrom<&Field> for CanonicalExtensionType {
84    type Error = ArrowError;
85
86    fn try_from(value: &Field) -> Result<Self, Self::Error> {
87        // Canonical extension type names start with `arrow.`
88        match value.extension_type_name() {
89            // An extension type name with an `arrow.` prefix
90            Some(name) if name.starts_with("arrow.") => match name {
91                FixedShapeTensor::NAME => value
92                    .try_extension_type::<FixedShapeTensor>()
93                    .map(Into::into),
94                VariableShapeTensor::NAME => value
95                    .try_extension_type::<VariableShapeTensor>()
96                    .map(Into::into),
97                Json::NAME => value.try_extension_type::<Json>().map(Into::into),
98                Uuid::NAME => value.try_extension_type::<Uuid>().map(Into::into),
99                Opaque::NAME => value.try_extension_type::<Opaque>().map(Into::into),
100                Bool8::NAME => value.try_extension_type::<Bool8>().map(Into::into),
101                TimestampWithOffset::NAME => value
102                    .try_extension_type::<TimestampWithOffset>()
103                    .map(Into::into),
104                VariantType::NAME => value.try_extension_type::<VariantType>().map(Into::into),
105                _ => Err(ArrowError::InvalidArgumentError(format!(
106                    "Unsupported canonical extension type: {name}"
107                ))),
108            },
109            // Name missing the expected prefix
110            Some(name) => Err(ArrowError::InvalidArgumentError(format!(
111                "Field extension type name mismatch, expected a name with an `arrow.` prefix, found {name}"
112            ))),
113            // Name missing
114            None => Err(ArrowError::InvalidArgumentError(
115                "Field extension type name missing".to_owned(),
116            )),
117        }
118    }
119}
120
121impl From<FixedShapeTensor> for CanonicalExtensionType {
122    fn from(value: FixedShapeTensor) -> Self {
123        CanonicalExtensionType::FixedShapeTensor(value)
124    }
125}
126
127impl From<VariableShapeTensor> for CanonicalExtensionType {
128    fn from(value: VariableShapeTensor) -> Self {
129        CanonicalExtensionType::VariableShapeTensor(value)
130    }
131}
132
133impl From<Json> for CanonicalExtensionType {
134    fn from(value: Json) -> Self {
135        CanonicalExtensionType::Json(value)
136    }
137}
138
139impl From<Uuid> for CanonicalExtensionType {
140    fn from(value: Uuid) -> Self {
141        CanonicalExtensionType::Uuid(value)
142    }
143}
144
145impl From<Opaque> for CanonicalExtensionType {
146    fn from(value: Opaque) -> Self {
147        CanonicalExtensionType::Opaque(value)
148    }
149}
150
151impl From<Bool8> for CanonicalExtensionType {
152    fn from(value: Bool8) -> Self {
153        CanonicalExtensionType::Bool8(value)
154    }
155}
156
157impl From<TimestampWithOffset> for CanonicalExtensionType {
158    fn from(value: TimestampWithOffset) -> Self {
159        CanonicalExtensionType::TimestampWithOffset(value)
160    }
161}
162
163impl From<VariantType> for CanonicalExtensionType {
164    fn from(value: VariantType) -> Self {
165        CanonicalExtensionType::Variant(value)
166    }
167}