Skip to main content

arrow_schema/extension/canonical/
bool8.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//! 8-bit Boolean
19//!
20//! <https://arrow.apache.org/docs/format/CanonicalExtensions.html#bit-boolean>
21
22use crate::{ArrowError, DataType, extension::ExtensionType};
23
24/// The extension type for `8-bit Boolean`.
25///
26/// Extension name: `arrow.bool8`.
27///
28/// The storage type of the extension is `Int8` where:
29/// - false is denoted by the value 0.
30/// - true can be specified using any non-zero value. Preferably 1.
31///
32/// <https://arrow.apache.org/docs/format/CanonicalExtensions.html#bit-boolean>
33#[derive(Debug, Default, Clone, Copy, PartialEq)]
34pub struct Bool8;
35
36impl ExtensionType for Bool8 {
37    const NAME: &'static str = "arrow.bool8";
38
39    type Metadata = &'static str;
40
41    fn metadata(&self) -> &Self::Metadata {
42        &""
43    }
44
45    fn serialize_metadata(&self) -> Option<String> {
46        Some(String::default())
47    }
48
49    fn deserialize_metadata(metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
50        if metadata.is_some_and(str::is_empty) {
51            Ok("")
52        } else {
53            Err(ArrowError::InvalidArgumentError(
54                "Bool8 extension type expects an empty string as metadata".to_owned(),
55            ))
56        }
57    }
58
59    fn supports_data_type(&self, data_type: &DataType) -> Result<(), ArrowError> {
60        match data_type {
61            DataType::Int8 => Ok(()),
62            data_type => Err(ArrowError::InvalidArgumentError(format!(
63                "Bool8 data type mismatch, expected Int8, found {data_type}"
64            ))),
65        }
66    }
67
68    fn try_new(data_type: &DataType, _metadata: Self::Metadata) -> Result<Self, ArrowError> {
69        Self.supports_data_type(data_type).map(|_| Self)
70    }
71
72    fn validate(data_type: &DataType, _metadata: Self::Metadata) -> Result<(), ArrowError> {
73        Self.supports_data_type(data_type)
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    #[cfg(feature = "canonical_extension_types")]
80    use crate::extension::CanonicalExtensionType;
81    use crate::{
82        Field,
83        extension::{EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY},
84    };
85
86    use super::*;
87
88    #[test]
89    fn valid() -> Result<(), ArrowError> {
90        let mut field = Field::new("", DataType::Int8, false);
91        field.try_with_extension_type(Bool8)?;
92        field.try_extension_type::<Bool8>()?;
93        #[cfg(feature = "canonical_extension_types")]
94        assert_eq!(
95            field.try_canonical_extension_type()?,
96            CanonicalExtensionType::Bool8(Bool8)
97        );
98
99        Ok(())
100    }
101
102    #[test]
103    #[should_panic(expected = "Extension type name missing")]
104    fn missing_name() {
105        let field = Field::new("", DataType::Int8, false).with_metadata(
106            [(EXTENSION_TYPE_METADATA_KEY.to_owned(), "".to_owned())]
107                .into_iter()
108                .collect(),
109        );
110        field.extension_type::<Bool8>();
111    }
112
113    #[test]
114    #[should_panic(expected = "expected Int8, found Boolean")]
115    fn invalid_type() {
116        Field::new("", DataType::Boolean, false).with_extension_type(Bool8);
117    }
118
119    #[test]
120    #[should_panic(expected = "Bool8 extension type expects an empty string as metadata")]
121    fn missing_metadata() {
122        let field = Field::new("", DataType::Int8, false).with_metadata(
123            [(EXTENSION_TYPE_NAME_KEY.to_owned(), Bool8::NAME.to_owned())]
124                .into_iter()
125                .collect(),
126        );
127        field.extension_type::<Bool8>();
128    }
129
130    #[test]
131    #[should_panic(expected = "Bool8 extension type expects an empty string as metadata")]
132    fn invalid_metadata() {
133        let field = Field::new("", DataType::Int8, false).with_metadata(
134            [
135                (EXTENSION_TYPE_NAME_KEY.to_owned(), Bool8::NAME.to_owned()),
136                (
137                    EXTENSION_TYPE_METADATA_KEY.to_owned(),
138                    "non-empty".to_owned(),
139                ),
140            ]
141            .into_iter()
142            .collect(),
143        );
144        field.extension_type::<Bool8>();
145    }
146}