datafusion_common/types/
logical.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
18use super::NativeType;
19use crate::error::Result;
20use arrow::datatypes::DataType;
21use core::fmt;
22use std::{cmp::Ordering, hash::Hash, sync::Arc};
23
24/// Signature that uniquely identifies a type among other types.
25#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
26pub enum TypeSignature<'a> {
27    /// Represents a built-in native type.
28    Native(&'a NativeType),
29    /// Represents an arrow-compatible extension type.
30    /// (<https://arrow.apache.org/docs/format/Columnar.html#extension-types>)
31    ///
32    /// The `name` should contain the same value as 'ARROW:extension:name'.
33    Extension {
34        name: &'a str,
35        parameters: &'a [TypeParameter<'a>],
36    },
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
40pub enum TypeParameter<'a> {
41    Type(TypeSignature<'a>),
42    Number(i128),
43}
44
45/// A reference counted [`LogicalType`].
46pub type LogicalTypeRef = Arc<dyn LogicalType>;
47
48/// Representation of a logical type with its signature and its native backing
49/// type.
50///
51/// The logical type is meant to be used during the DataFusion logical planning
52/// phase in order to reason about logical types without worrying about their
53/// underlying physical implementation.
54///
55/// ### Extension types
56///
57/// [`LogicalType`] is a trait in order to allow the possibility of declaring
58/// extension types:
59///
60/// ```
61/// use datafusion_common::types::{LogicalType, NativeType, TypeSignature};
62///
63/// struct JSON {}
64///
65/// impl LogicalType for JSON {
66///     fn native(&self) -> &NativeType {
67///         &NativeType::String
68///     }
69///
70///    fn signature(&self) -> TypeSignature<'_> {
71///        TypeSignature::Extension {
72///            name: "JSON",
73///            parameters: &[],
74///        }
75///    }
76/// }
77/// ```
78pub trait LogicalType: Sync + Send {
79    /// Get the native backing type of this logical type.
80    fn native(&self) -> &NativeType;
81    /// Get the unique type signature for this logical type. Logical types with identical
82    /// signatures are considered equal.
83    fn signature(&self) -> TypeSignature<'_>;
84
85    /// Get the default physical type to cast `origin` to in order to obtain a physical type
86    /// that is logically compatible with this logical type.
87    fn default_cast_for(&self, origin: &DataType) -> Result<DataType> {
88        self.native().default_cast_for(origin)
89    }
90}
91
92impl fmt::Debug for dyn LogicalType {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        f.debug_tuple("LogicalType")
95            .field(&self.signature())
96            .field(&self.native())
97            .finish()
98    }
99}
100
101impl std::fmt::Display for dyn LogicalType {
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        write!(f, "{self:?}")
104    }
105}
106
107impl PartialEq for dyn LogicalType {
108    fn eq(&self, other: &Self) -> bool {
109        self.signature().eq(&other.signature())
110    }
111}
112
113impl Eq for dyn LogicalType {}
114
115impl PartialOrd for dyn LogicalType {
116    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
117        Some(self.cmp(other))
118    }
119}
120
121impl Ord for dyn LogicalType {
122    fn cmp(&self, other: &Self) -> Ordering {
123        self.signature()
124            .cmp(&other.signature())
125            .then(self.native().cmp(other.native()))
126    }
127}
128
129impl Hash for dyn LogicalType {
130    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
131        self.signature().hash(state);
132        self.native().hash(state);
133    }
134}