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