33
44use std:: fmt:: { Display , Formatter } ;
55use std:: hash:: Hash ;
6- use std:: ops:: Deref ;
76use std:: sync:: Arc ;
87
98use itertools:: Itertools as _;
109use vortex_dtype:: { DType , Nullability } ;
11- use vortex_error:: { VortexError , VortexExpect as _, VortexResult , vortex_bail, vortex_panic} ;
10+ use vortex_error:: {
11+ VortexError , VortexExpect as _, VortexResult , vortex_bail, vortex_err, vortex_panic,
12+ } ;
1213
1314use crate :: { InnerScalarValue , Scalar , ScalarValue } ;
1415
15- /// A scalar value representing a list (array) of elements.
16+ /// A scalar value representing a list or fixed-size list (array) of elements.
1617///
17- /// This type provides a view into a list scalar value, which can contain
18- /// zero or more elements of the same type, or be null.
18+ /// We use the same [`ListScalar`] to represent both variants since a single list scalar's data is
19+ /// identical to a single fixed-size list scalar.
20+ ///
21+ /// This type provides a view into a list or fixed-size list scalar value which can contain zero or
22+ /// more elements of the same type, or be null. If the `dtype` is a [`FixedSizeList`], then the
23+ /// number of `elements` is equal to the `size` field of the [`FixedSizeList`].
24+ ///
25+ /// [`FixedSizeList`]: DType::FixedSizeList
1926#[ derive( Debug ) ]
2027pub struct ListScalar < ' a > {
2128 dtype : & ' a DType ,
@@ -28,9 +35,16 @@ impl Display for ListScalar<'_> {
2835 match & self . elements {
2936 None => write ! ( f, "null" ) ,
3037 Some ( elems) => {
38+ let fixed_size_list_str: & dyn Display =
39+ if let DType :: FixedSizeList ( _, size, _) = self . dtype {
40+ & format ! ( "fixed_size<{size}>" )
41+ } else {
42+ & ""
43+ } ;
44+
3145 write ! (
3246 f,
33- "[{}]" ,
47+ "{fixed_size_list_str} [{}]" ,
3448 elems
3549 . iter( )
3650 . map( |e| Scalar :: new( self . element_dtype( ) . clone( ) , e. clone( ) ) )
@@ -101,10 +115,10 @@ impl<'a> ListScalar<'a> {
101115
102116 /// Returns the data type of the list's elements.
103117 pub fn element_dtype ( & self ) -> & DType {
104- let DType :: List ( element_type , _ ) = self . dtype ( ) else {
105- unreachable ! ( ) ;
106- } ;
107- ( * element_type ) . deref ( )
118+ self . dtype
119+ . as_list_element_opt ( )
120+ . unwrap_or_else ( || vortex_panic ! ( "`ListScalar` somehow had dtype {}" , self . dtype ) )
121+ . as_ref ( )
108122 }
109123
110124 /// Returns the element at the given index as a scalar.
@@ -129,14 +143,35 @@ impl<'a> ListScalar<'a> {
129143 } )
130144 }
131145
146+ /// Casts the list to the target [`DType`].
147+ ///
148+ /// # Panics
149+ ///
150+ /// Panics if the target [`DType`] is not a [`List`]: or [`FixedSizeList`], or if trying to cast
151+ /// to a [`FixedSizeList`] with the incorrect number of elements.
152+ ///
153+ /// [`List`]: DType::List
154+ /// [`FixedSizeList`]: DType::FixedSizeList
132155 pub ( crate ) fn cast ( & self , dtype : & DType ) -> VortexResult < Scalar > {
133- let DType :: List ( element_dtype, ..) = dtype else {
156+ let target_element_dtype = dtype
157+ . as_list_element_opt ( )
158+ . ok_or_else ( || {
159+ vortex_err ! (
160+ "Cannot cast {} to {}: list can only be cast to a list or fixed-size list" ,
161+ self . dtype( ) ,
162+ dtype
163+ )
164+ } ) ?
165+ . as_ref ( ) ;
166+
167+ if let DType :: FixedSizeList ( _, size, _) = dtype
168+ && * size as usize != self . len ( )
169+ {
134170 vortex_bail ! (
135- "Cannot cast {} to {}: list can only be cast to list" ,
136- self . dtype( ) ,
137- dtype
171+ "tried to cast to a `FixedSizeList[{size}]` but had {} elements" ,
172+ self . len( )
138173 )
139- } ;
174+ }
140175
141176 Ok ( Scalar :: new (
142177 dtype. clone ( ) ,
@@ -146,61 +181,101 @@ impl<'a> ListScalar<'a> {
146181 . vortex_expect ( "nullness handled in Scalar::cast" )
147182 . iter ( )
148183 . map ( |element| {
184+ // Recursively cast the elements of the list.
149185 Scalar :: new ( DType :: clone ( self . element_dtype ) , element. clone ( ) )
150- . cast ( element_dtype )
186+ . cast ( target_element_dtype )
151187 . map ( |x| x. value ( ) . clone ( ) )
152188 } )
153- . process_results ( |iter| iter . collect ( ) ) ?,
189+ . collect :: < VortexResult < Arc < [ ScalarValue ] > > > ( ) ?,
154190 ) ) ,
155191 ) )
156192 }
157193}
158194
195+ /// A helper enum for creating a [`ListScalar`].
196+ enum ListKind {
197+ Variable ,
198+ FixedSize ,
199+ }
200+
201+ /// Helper functions to create a [`ListScalar`] as a [`Scalar`].
159202impl Scalar {
203+ fn create_list (
204+ element_dtype : impl Into < Arc < DType > > ,
205+ children : Vec < Scalar > ,
206+ nullability : Nullability ,
207+ list_kind : ListKind ,
208+ ) -> Self {
209+ let element_dtype = element_dtype. into ( ) ;
210+
211+ let children: Arc < [ ScalarValue ] > = children
212+ . into_iter ( )
213+ . map ( |child| {
214+ if child. dtype ( ) != & * element_dtype {
215+ vortex_panic ! (
216+ "tried to create list of {} with values of type {}" ,
217+ element_dtype,
218+ child. dtype( )
219+ ) ;
220+ }
221+ child. value
222+ } )
223+ . collect ( ) ;
224+ let size: u32 = children
225+ . len ( )
226+ . try_into ( )
227+ . vortex_expect ( "tried to create a list that was too large" ) ;
228+
229+ let dtype = match list_kind {
230+ ListKind :: Variable => DType :: List ( element_dtype, nullability) ,
231+ ListKind :: FixedSize => DType :: FixedSizeList ( element_dtype, size, nullability) ,
232+ } ;
233+
234+ Self :: new ( dtype, ScalarValue ( InnerScalarValue :: List ( children) ) )
235+ }
236+
160237 /// Creates a new list scalar with the given element type and children.
161238 ///
162239 /// # Panics
163240 ///
164- /// Panics if any child scalar has a different type than the element type.
241+ /// Panics if any child scalar has a different type than the element type, or if there are too
242+ /// many children.
165243 pub fn list (
166244 element_dtype : impl Into < Arc < DType > > ,
167245 children : Vec < Scalar > ,
168246 nullability : Nullability ,
169247 ) -> Self {
170- let element_dtype = element_dtype. into ( ) ;
171- for child in & children {
172- if child. dtype ( ) != & * element_dtype {
173- vortex_panic ! (
174- "tried to create list of {} with values of type {}" ,
175- element_dtype,
176- child. dtype( )
177- ) ;
178- }
179- }
180- Self :: new (
181- DType :: List ( element_dtype, nullability) ,
182- ScalarValue ( InnerScalarValue :: List (
183- children. into_iter ( ) . map ( |x| x. value ) . collect ( ) ,
184- ) ) ,
185- )
248+ Self :: create_list ( element_dtype, children, nullability, ListKind :: Variable )
186249 }
187250
188251 /// Creates a new empty list scalar with the given element type.
189252 pub fn list_empty ( element_dtype : Arc < DType > , nullability : Nullability ) -> Self {
190- Self :: new (
191- DType :: List ( element_dtype, nullability) ,
192- ScalarValue ( InnerScalarValue :: List ( vec ! [ ] . into ( ) ) ) ,
193- )
253+ Self :: create_list ( element_dtype, vec ! [ ] , nullability, ListKind :: Variable )
254+ }
255+
256+ /// Creates a new fixed-size list scalar with the given element type and children.
257+ ///
258+ /// # Panics
259+ ///
260+ /// Panics if any child scalar has a different type than the element type, or if there are too
261+ /// many children.
262+ pub fn fixed_size_list (
263+ element_dtype : impl Into < Arc < DType > > ,
264+ children : Vec < Scalar > ,
265+ nullability : Nullability ,
266+ ) -> Self {
267+ Self :: create_list ( element_dtype, children, nullability, ListKind :: FixedSize )
194268 }
195269}
196270
197271impl < ' a > TryFrom < & ' a Scalar > for ListScalar < ' a > {
198272 type Error = VortexError ;
199273
200274 fn try_from ( value : & ' a Scalar ) -> Result < Self , Self :: Error > {
201- let DType :: List ( element_dtype, ..) = value. dtype ( ) else {
202- vortex_bail ! ( "Expected list scalar, found {}" , value. dtype( ) )
203- } ;
275+ let element_dtype = value
276+ . dtype ( )
277+ . as_list_element_opt ( )
278+ . ok_or_else ( || vortex_err ! ( "Expected list scalar, found {}" , value. dtype( ) ) ) ?;
204279
205280 Ok ( Self {
206281 dtype : value. dtype ( ) ,
0 commit comments