Skip to main content

polars_core/datatypes/
_serde.rs

1//! Having `Object<&;static> in [`DataType`] make serde tag the `Deserialize` trait bound 'static
2//! even though we skip serializing `Object`.
3//!
4//! We could use [serde_1712](https://github.com/serde-rs/serde/issues/1712), but that gave problems caused by
5//! [rust_96956](https://github.com/rust-lang/rust/issues/96956), so we make a dummy type without static
6
7use polars_dtype::categorical::CategoricalPhysical;
8use serde::{Deserialize, Serialize};
9
10use super::*;
11
12impl<'a> Deserialize<'a> for DataType {
13    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
14    where
15        D: Deserializer<'a>,
16    {
17        Ok(SerializableDataType::deserialize(deserializer)?.into())
18    }
19}
20
21impl Serialize for DataType {
22    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
23    where
24        S: Serializer,
25    {
26        let dt: SerializableDataType = self.into();
27        dt.serialize(serializer)
28    }
29}
30
31#[cfg(feature = "dsl-schema")]
32impl schemars::JsonSchema for DataType {
33    fn schema_name() -> std::borrow::Cow<'static, str> {
34        SerializableDataType::schema_name()
35    }
36
37    fn schema_id() -> std::borrow::Cow<'static, str> {
38        SerializableDataType::schema_id()
39    }
40
41    fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
42        SerializableDataType::json_schema(generator)
43    }
44}
45
46#[derive(Serialize, Deserialize)]
47#[cfg_attr(feature = "dsl-schema", derive(schemars::JsonSchema))]
48#[serde(rename = "DataType")]
49enum SerializableDataType {
50    Boolean,
51    UInt8,
52    UInt16,
53    UInt32,
54    UInt64,
55    UInt128,
56    Int8,
57    Int16,
58    Int32,
59    Int64,
60    Int128,
61    Float16,
62    Float32,
63    Float64,
64    String,
65    Binary,
66    BinaryOffset,
67    /// A 32-bit date representing the elapsed time since UNIX epoch (1970-01-01)
68    /// in days (32 bits).
69    Date,
70    /// A 64-bit date representing the elapsed time since UNIX epoch (1970-01-01)
71    /// in the given ms/us/ns TimeUnit (64 bits).
72    Datetime(TimeUnit, Option<TimeZone>),
73    // 64-bit integer representing difference between times in milli|micro|nano seconds
74    Duration(TimeUnit),
75    /// A 64-bit time representing elapsed time since midnight in the given TimeUnit.
76    Time,
77    List(Box<SerializableDataType>),
78    #[cfg(feature = "dtype-array")]
79    Array(Box<SerializableDataType>, usize),
80    Null,
81    #[cfg(feature = "dtype-struct")]
82    Struct(Vec<Field>),
83    #[cfg(feature = "dtype-map")]
84    Map(Box<SerializableDataType>, Box<SerializableDataType>),
85    // some logical types we cannot know statically, e.g. Datetime
86    Unknown(UnknownKind),
87    #[cfg(feature = "dtype-categorical")]
88    Categorical {
89        name: String,
90        namespace: String,
91        physical: CategoricalPhysical,
92    },
93    #[cfg(feature = "dtype-categorical")]
94    Enum {
95        strings: Series,
96    },
97    #[cfg(feature = "dtype-decimal")]
98    Decimal(usize, usize),
99    #[cfg(feature = "object")]
100    Object(String),
101    #[cfg(feature = "dtype-extension")]
102    Extension {
103        name: String,
104        metadata: Option<String>,
105        storage: Box<SerializableDataType>,
106    },
107}
108
109impl From<&DataType> for SerializableDataType {
110    fn from(dt: &DataType) -> Self {
111        use DataType::*;
112        match dt {
113            Boolean => Self::Boolean,
114            UInt8 => Self::UInt8,
115            UInt16 => Self::UInt16,
116            UInt32 => Self::UInt32,
117            UInt64 => Self::UInt64,
118            UInt128 => Self::UInt128,
119            Int8 => Self::Int8,
120            Int16 => Self::Int16,
121            Int32 => Self::Int32,
122            Int64 => Self::Int64,
123            Int128 => Self::Int128,
124            Float16 => Self::Float16,
125            Float32 => Self::Float32,
126            Float64 => Self::Float64,
127            String => Self::String,
128            Binary => Self::Binary,
129            BinaryOffset => Self::BinaryOffset,
130            Date => Self::Date,
131            Datetime(tu, tz) => Self::Datetime(*tu, tz.clone()),
132            Duration(tu) => Self::Duration(*tu),
133            Time => Self::Time,
134            List(dt) => Self::List(Box::new(dt.as_ref().into())),
135            #[cfg(feature = "dtype-array")]
136            Array(dt, width) => Self::Array(Box::new(dt.as_ref().into()), *width),
137            Null => Self::Null,
138            Unknown(kind) => Self::Unknown(*kind),
139            #[cfg(feature = "dtype-struct")]
140            Struct(flds) => Self::Struct(flds.clone()),
141            #[cfg(feature = "dtype-map")]
142            Map(key, value) => Self::Map(
143                Box::new(key.as_ref().into()),
144                Box::new(value.as_ref().into()),
145            ),
146            #[cfg(feature = "dtype-categorical")]
147            Categorical(cats, _) => Self::Categorical {
148                name: cats.name().to_string(),
149                namespace: cats.namespace().to_string(),
150                physical: cats.physical(),
151            },
152            #[cfg(feature = "dtype-categorical")]
153            Enum(fcats, _) => Self::Enum {
154                strings: StringChunked::with_chunk(
155                    PlSmallStr::from_static("categories"),
156                    fcats.categories().clone(),
157                )
158                .into_series(),
159            },
160            #[cfg(feature = "dtype-decimal")]
161            Decimal(precision, scale) => Self::Decimal(*precision, *scale),
162            #[cfg(feature = "object")]
163            Object(name) => Self::Object(name.to_string()),
164            #[cfg(feature = "dtype-extension")]
165            Extension(typ, storage) => Self::Extension {
166                name: typ.name().to_string(),
167                metadata: typ.serialize_metadata().map(|s| s.into_owned()),
168                storage: Box::new(SerializableDataType::from(storage.as_ref())),
169            },
170        }
171    }
172}
173impl From<SerializableDataType> for DataType {
174    fn from(dt: SerializableDataType) -> Self {
175        use SerializableDataType::*;
176        match dt {
177            Boolean => Self::Boolean,
178            UInt8 => Self::UInt8,
179            UInt16 => Self::UInt16,
180            UInt32 => Self::UInt32,
181            UInt64 => Self::UInt64,
182            UInt128 => Self::UInt128,
183            Int8 => Self::Int8,
184            Int16 => Self::Int16,
185            Int32 => Self::Int32,
186            Int64 => Self::Int64,
187            Int128 => Self::Int128,
188            Float16 => Self::Float16,
189            Float32 => Self::Float32,
190            Float64 => Self::Float64,
191            String => Self::String,
192            Binary => Self::Binary,
193            BinaryOffset => Self::BinaryOffset,
194            Date => Self::Date,
195            Datetime(tu, tz) => Self::Datetime(tu, tz),
196            Duration(tu) => Self::Duration(tu),
197            Time => Self::Time,
198            List(dt) => Self::List(Box::new((*dt).into())),
199            #[cfg(feature = "dtype-array")]
200            Array(dt, width) => Self::Array(Box::new((*dt).into()), width),
201            Null => Self::Null,
202            Unknown(kind) => Self::Unknown(kind),
203            #[cfg(feature = "dtype-struct")]
204            Struct(flds) => Self::Struct(flds),
205            #[cfg(feature = "dtype-map")]
206            Map(key, value) => Self::Map(Box::new((*key).into()), Box::new((*value).into())),
207            #[cfg(feature = "dtype-categorical")]
208            Categorical {
209                name,
210                namespace,
211                physical,
212            } => {
213                let cats = Categories::new(
214                    PlSmallStr::from(name),
215                    PlSmallStr::from(namespace),
216                    physical,
217                );
218                let mapping = cats.mapping();
219                Self::Categorical(cats, mapping)
220            },
221            #[cfg(feature = "dtype-categorical")]
222            Enum { strings } => {
223                let ca = strings.str().unwrap();
224                let fcats = FrozenCategories::new(ca.iter().flatten()).unwrap();
225                let mapping = fcats.mapping().clone();
226                Self::Enum(fcats, mapping)
227            },
228            #[cfg(feature = "dtype-decimal")]
229            Decimal(precision, scale) => Self::Decimal(precision, scale),
230            #[cfg(feature = "object")]
231            Object(_) => Self::Object("unknown"),
232            #[cfg(feature = "dtype-extension")]
233            Extension {
234                name,
235                metadata,
236                storage,
237            } => {
238                let storage = DataType::from(*storage);
239                let ext_type = crate::datatypes::extension::get_extension_type_or_generic(
240                    &name,
241                    &storage,
242                    metadata.as_deref(),
243                );
244                Self::Extension(ext_type, Box::new(storage))
245            },
246        }
247    }
248}