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}