Skip to main content

vortex_array/scalar/
display.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4//! [`Display`] implementations for [`Scalar`].
5
6use std::fmt::Display;
7use std::fmt::Formatter;
8
9use crate::dtype::DType;
10use crate::scalar::Scalar;
11
12impl Display for Scalar {
13    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
14        match self.dtype() {
15            DType::Null => write!(f, "null"),
16            DType::Bool(_) => write!(f, "{}", self.as_bool()),
17            DType::Primitive(..) => write!(f, "{}", self.as_primitive()),
18            DType::Decimal(..) => write!(f, "{}", self.as_decimal()),
19            DType::Utf8(_) => write!(f, "{}", self.as_utf8()),
20            DType::Binary(_) => write!(f, "{}", self.as_binary()),
21            DType::List(..) | DType::FixedSizeList(..) => write!(f, "{}", self.as_list()),
22            DType::Struct(..) => write!(f, "{}", self.as_struct()),
23            DType::Union(..) => write!(f, "{}", self.as_union()),
24            DType::Variant(_) => write!(f, "{}", self.as_variant()),
25            DType::Extension(_) => write!(f, "{}", self.as_extension()),
26        }
27    }
28}
29
30#[cfg(test)]
31mod tests {
32    use vortex_buffer::ByteBuffer;
33    use vortex_error::VortexResult;
34
35    use crate::dtype::DType;
36    use crate::dtype::FieldName;
37    use crate::dtype::Nullability::NonNullable;
38    use crate::dtype::Nullability::Nullable;
39    use crate::dtype::PType;
40    use crate::dtype::StructFields;
41    use crate::dtype::UnionVariants;
42    use crate::extension::datetime::Date;
43    use crate::extension::datetime::Time;
44    use crate::extension::datetime::TimeUnit;
45    use crate::extension::datetime::Timestamp;
46    use crate::scalar::PValue;
47    use crate::scalar::Scalar;
48    use crate::scalar::ScalarValue;
49
50    const MINUTES: i32 = 60;
51    const HOURS: i32 = 60 * MINUTES;
52    const DAYS: i32 = 24 * HOURS;
53
54    #[test]
55    fn display_bool() {
56        assert_eq!(format!("{}", Scalar::from(false)), "false");
57        assert_eq!(format!("{}", Scalar::from(true)), "true");
58        assert_eq!(format!("{}", Scalar::null(DType::Bool(Nullable))), "null");
59    }
60
61    #[test]
62    fn display_primitive() {
63        assert_eq!(format!("{}", Scalar::from(0u8)), "0u8");
64        assert_eq!(format!("{}", Scalar::from(255u8)), "255u8");
65
66        assert_eq!(format!("{}", Scalar::from(0u16)), "0u16");
67        assert_eq!(format!("{}", Scalar::from(!0u16)), "65535u16");
68
69        assert_eq!(format!("{}", Scalar::from(0u32)), "0u32");
70        assert_eq!(format!("{}", Scalar::from(!0u32)), "4294967295u32");
71
72        assert_eq!(format!("{}", Scalar::from(0u64)), "0u64");
73        assert_eq!(
74            format!("{}", Scalar::from(!0u64)),
75            "18446744073709551615u64"
76        );
77
78        assert_eq!(
79            format!("{}", Scalar::null(DType::Primitive(PType::U8, Nullable))),
80            "null"
81        );
82    }
83
84    #[test]
85    fn display_union() -> VortexResult<()> {
86        let variants = UnionVariants::new(
87            ["int", "string"].into(),
88            vec![
89                DType::Primitive(PType::I32, Nullable),
90                DType::Utf8(NonNullable),
91            ],
92        )?;
93
94        let scalar = Scalar::union(
95            variants.clone(),
96            0,
97            Scalar::primitive(42_i32, Nullable),
98            Nullable,
99        )?;
100
101        assert_eq!(format!("{scalar}"), "int(42i32)");
102        let inner_null = Scalar::union(
103            variants.clone(),
104            0,
105            Scalar::null(DType::Primitive(PType::I32, Nullable)),
106            Nullable,
107        )?;
108        assert_eq!(format!("{inner_null}"), "int(null)");
109        assert_eq!(
110            format!("{}", Scalar::null(DType::Union(variants, Nullable))),
111            "null"
112        );
113
114        let struct_dtype = DType::struct_(
115            [("field", DType::Primitive(PType::I32, NonNullable))],
116            NonNullable,
117        );
118        let struct_scalar = Scalar::struct_(
119            struct_dtype.clone(),
120            [Scalar::primitive(42_i32, NonNullable)],
121        );
122        let struct_variants = UnionVariants::new(["record"].into(), vec![struct_dtype])?;
123        let struct_union = Scalar::union(struct_variants, 0, struct_scalar, NonNullable)?;
124        assert_eq!(format!("{struct_union}"), "record({field: 42i32})");
125
126        Ok(())
127    }
128
129    #[test]
130    fn display_utf8() {
131        assert_eq!(
132            format!("{}", Scalar::from("Hello World!")),
133            "\"Hello World!\""
134        );
135        assert_eq!(format!("{}", Scalar::null(DType::Utf8(Nullable))), "null");
136    }
137
138    #[test]
139    fn display_binary() {
140        assert_eq!(
141            format!(
142                "{}",
143                Scalar::binary(
144                    ByteBuffer::from("Hello World!".as_bytes().to_vec()),
145                    NonNullable
146                )
147            ),
148            "\"48 65 6c 6c 6f 20 57 6f 72 6c 64 21\""
149        );
150        assert_eq!(format!("{}", Scalar::null(DType::Binary(Nullable))), "null");
151    }
152
153    #[test]
154    fn display_empty_struct() {
155        fn dtype() -> DType {
156            DType::Struct(StructFields::new(Default::default(), vec![]), Nullable)
157        }
158
159        assert_eq!(format!("{}", Scalar::null(dtype())), "null");
160
161        assert_eq!(format!("{}", Scalar::struct_(dtype(), vec![])), "{}");
162    }
163
164    #[test]
165    fn display_one_field_struct() {
166        fn dtype() -> DType {
167            DType::Struct(
168                StructFields::new(
169                    [FieldName::from("foo")].into(),
170                    vec![DType::Primitive(PType::U32, Nullable)],
171                ),
172                Nullable,
173            )
174        }
175
176        assert_eq!(format!("{}", Scalar::null(dtype())), "null");
177
178        assert_eq!(
179            format!(
180                "{}",
181                Scalar::struct_(dtype(), vec![Scalar::null_native::<u32>()])
182            ),
183            "{foo: null}"
184        );
185
186        assert_eq!(
187            format!(
188                "{}",
189                Scalar::struct_(dtype(), vec![Scalar::from(Some(32_u32))])
190            ),
191            "{foo: 32u32}"
192        );
193    }
194
195    #[test]
196    fn display_two_field_struct() {
197        // fn dtype() -> (DType, DType, DType) {
198        let f1 = DType::Bool(Nullable);
199        let f2 = DType::Primitive(PType::U32, Nullable);
200        let dtype = DType::Struct(
201            StructFields::new(
202                [FieldName::from("foo"), FieldName::from("bar")].into(),
203                vec![f1.clone(), f2.clone()],
204            ),
205            Nullable,
206        );
207        // }
208
209        assert_eq!(format!("{}", Scalar::null(dtype.clone())), "null");
210
211        assert_eq!(
212            format!(
213                "{}",
214                Scalar::struct_(
215                    dtype.clone(),
216                    vec![Scalar::null(f1), Scalar::null(f2.clone())]
217                )
218            ),
219            "{foo: null, bar: null}"
220        );
221
222        assert_eq!(
223            format!(
224                "{}",
225                Scalar::struct_(dtype.clone(), vec![Some(true).into(), Scalar::null(f2)])
226            ),
227            "{foo: true, bar: null}"
228        );
229
230        assert_eq!(
231            format!(
232                "{}",
233                Scalar::struct_(dtype, vec![Some(true).into(), Some(32_u32).into()])
234            ),
235            "{foo: true, bar: 32u32}"
236        );
237    }
238
239    #[test]
240    fn display_time() {
241        fn dtype() -> DType {
242            DType::Extension(Time::new(TimeUnit::Seconds, Nullable).erased())
243        }
244
245        assert_eq!(format!("{}", Scalar::null(dtype())), "null");
246
247        assert_eq!(
248            format!(
249                "{}",
250                Scalar::new(
251                    dtype(),
252                    Some(ScalarValue::Primitive(PValue::I32(3 * MINUTES + 25)))
253                )
254            ),
255            "00:03:25"
256        );
257    }
258
259    #[test]
260    fn display_date() {
261        fn dtype() -> DType {
262            DType::Extension(Date::new(TimeUnit::Days, Nullable).erased())
263        }
264
265        assert_eq!(format!("{}", Scalar::null(dtype())), "null");
266
267        assert_eq!(
268            format!(
269                "{}",
270                Scalar::new(dtype(), Some(ScalarValue::Primitive(PValue::I32(25))))
271            ),
272            "1970-01-26"
273        );
274
275        assert_eq!(
276            format!(
277                "{}",
278                Scalar::new(dtype(), Some(ScalarValue::Primitive(PValue::I32(365))))
279            ),
280            "1971-01-01"
281        );
282
283        assert_eq!(
284            format!(
285                "{}",
286                Scalar::new(dtype(), Some(ScalarValue::Primitive(PValue::I32(365 * 4))))
287            ),
288            "1973-12-31"
289        );
290    }
291
292    #[test]
293    fn display_variant_values() {
294        assert_eq!(
295            format!("{}", Scalar::null(DType::Variant(Nullable))),
296            "null"
297        );
298        assert_eq!(
299            format!("{}", Scalar::variant(Scalar::null(DType::Null))),
300            "variant(null)"
301        );
302        assert_eq!(
303            format!("{}", Scalar::variant(Scalar::from(42_u32))),
304            "variant(42u32)"
305        );
306    }
307
308    #[test]
309    fn display_local_timestamp() {
310        fn dtype() -> DType {
311            DType::Extension(Timestamp::new(TimeUnit::Seconds, Nullable).erased())
312        }
313
314        assert_eq!(format!("{}", Scalar::null(dtype())), "null");
315
316        assert_eq!(
317            format!(
318                "{}",
319                Scalar::new(
320                    dtype(),
321                    Some(ScalarValue::Primitive(PValue::I64(
322                        (3 * DAYS + 2 * HOURS + 5 * MINUTES + 10) as i64
323                    )))
324                )
325            ),
326            "1970-01-04T02:05:10Z"
327        );
328    }
329
330    #[cfg_attr(miri, ignore)]
331    #[test]
332    fn display_zoned_timestamp() {
333        fn dtype() -> DType {
334            DType::Extension(
335                Timestamp::new_with_tz(TimeUnit::Seconds, Some("Pacific/Guam".into()), Nullable)
336                    .erased(),
337            )
338        }
339
340        assert_eq!(format!("{}", Scalar::null(dtype())), "null");
341
342        assert_eq!(
343            format!(
344                "{}",
345                Scalar::new(dtype(), Some(ScalarValue::Primitive(PValue::I64(0i64))))
346            ),
347            "1970-01-01T10:00:00+10:00[Pacific/Guam]"
348        );
349
350        assert_eq!(
351            format!(
352                "{}",
353                Scalar::new(
354                    dtype(),
355                    Some(ScalarValue::Primitive(PValue::I64(
356                        (3 * DAYS + 2 * HOURS + 5 * MINUTES + 10) as i64
357                    )))
358                )
359            ),
360            "1970-01-04T12:05:10+10:00[Pacific/Guam]"
361        );
362    }
363}