1use serde_core::de::{self, MapAccess, Visitor};
10use serde_core::{Deserialize, Deserializer, Serialize, Serializer};
11use std::fmt;
12
13use crate::{ArrowError, DataType, Field, extension::ExtensionType};
14
15#[derive(Debug, Clone, PartialEq)]
62pub struct VariableShapeTensor {
63 value_type: DataType,
65
66 dimensions: usize,
68
69 metadata: VariableShapeTensorMetadata,
71}
72
73impl VariableShapeTensor {
74 pub fn try_new(
81 value_type: DataType,
82 dimensions: usize,
83 dimension_names: Option<Vec<String>>,
84 permutations: Option<Vec<usize>>,
85 uniform_shapes: Option<Vec<Option<i32>>>,
86 ) -> Result<Self, ArrowError> {
87 VariableShapeTensorMetadata::try_new(
89 dimensions,
90 dimension_names,
91 permutations,
92 uniform_shapes,
93 )
94 .map(|metadata| Self {
95 value_type,
96 dimensions,
97 metadata,
98 })
99 }
100
101 pub fn value_type(&self) -> &DataType {
103 &self.value_type
104 }
105
106 pub fn dimensions(&self) -> usize {
108 self.dimensions
109 }
110
111 pub fn dimension_names(&self) -> Option<&[String]> {
114 self.metadata.dimension_names()
115 }
116
117 pub fn permutations(&self) -> Option<&[usize]> {
120 self.metadata.permutations()
121 }
122
123 pub fn uniform_shapes(&self) -> Option<&[Option<i32>]> {
127 self.metadata.uniform_shapes()
128 }
129}
130
131#[derive(Debug, Clone, PartialEq)]
133pub struct VariableShapeTensorMetadata {
134 dim_names: Option<Vec<String>>,
136
137 permutations: Option<Vec<usize>>,
139
140 uniform_shape: Option<Vec<Option<i32>>>,
143}
144
145impl Serialize for VariableShapeTensorMetadata {
146 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
147 where
148 S: Serializer,
149 {
150 use serde_core::ser::SerializeStruct;
151 let mut state = serializer.serialize_struct("VariableShapeTensorMetadata", 3)?;
152 state.serialize_field("dim_names", &self.dim_names)?;
153 state.serialize_field("permutations", &self.permutations)?;
154 state.serialize_field("uniform_shape", &self.uniform_shape)?;
155 state.end()
156 }
157}
158
159#[derive(Debug)]
160enum MetadataField {
161 DimNames,
162 Permutations,
163 UniformShape,
164}
165
166struct MetadataFieldVisitor;
167
168impl Visitor<'_> for MetadataFieldVisitor {
169 type Value = MetadataField;
170
171 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
172 formatter.write_str("`dim_names`, `permutations`, or `uniform_shape`")
173 }
174
175 fn visit_str<E>(self, value: &str) -> Result<MetadataField, E>
176 where
177 E: de::Error,
178 {
179 match value {
180 "dim_names" => Ok(MetadataField::DimNames),
181 "permutations" => Ok(MetadataField::Permutations),
182 "uniform_shape" => Ok(MetadataField::UniformShape),
183 _ => Err(de::Error::unknown_field(
184 value,
185 &["dim_names", "permutations", "uniform_shape"],
186 )),
187 }
188 }
189}
190
191impl<'de> Deserialize<'de> for MetadataField {
192 fn deserialize<D>(deserializer: D) -> Result<MetadataField, D::Error>
193 where
194 D: Deserializer<'de>,
195 {
196 deserializer.deserialize_identifier(MetadataFieldVisitor)
197 }
198}
199
200struct VariableShapeTensorMetadataVisitor;
201
202impl<'de> Visitor<'de> for VariableShapeTensorMetadataVisitor {
203 type Value = VariableShapeTensorMetadata;
204
205 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
206 formatter.write_str("struct VariableShapeTensorMetadata")
207 }
208
209 fn visit_seq<V>(self, mut seq: V) -> Result<VariableShapeTensorMetadata, V::Error>
210 where
211 V: de::SeqAccess<'de>,
212 {
213 let dim_names = seq
214 .next_element()?
215 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
216 let permutations = seq
217 .next_element()?
218 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
219 let uniform_shape = seq
220 .next_element()?
221 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
222 Ok(VariableShapeTensorMetadata {
223 dim_names,
224 permutations,
225 uniform_shape,
226 })
227 }
228
229 fn visit_map<V>(self, mut map: V) -> Result<VariableShapeTensorMetadata, V::Error>
230 where
231 V: MapAccess<'de>,
232 {
233 let mut dim_names = None;
234 let mut permutations = None;
235 let mut uniform_shape = None;
236
237 while let Some(key) = map.next_key()? {
238 match key {
239 MetadataField::DimNames => {
240 if dim_names.is_some() {
241 return Err(de::Error::duplicate_field("dim_names"));
242 }
243 dim_names = Some(map.next_value()?);
244 }
245 MetadataField::Permutations => {
246 if permutations.is_some() {
247 return Err(de::Error::duplicate_field("permutations"));
248 }
249 permutations = Some(map.next_value()?);
250 }
251 MetadataField::UniformShape => {
252 if uniform_shape.is_some() {
253 return Err(de::Error::duplicate_field("uniform_shape"));
254 }
255 uniform_shape = Some(map.next_value()?);
256 }
257 }
258 }
259
260 Ok(VariableShapeTensorMetadata {
261 dim_names,
262 permutations,
263 uniform_shape,
264 })
265 }
266}
267
268impl<'de> Deserialize<'de> for VariableShapeTensorMetadata {
269 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
270 where
271 D: Deserializer<'de>,
272 {
273 deserializer.deserialize_struct(
274 "VariableShapeTensorMetadata",
275 &["dim_names", "permutations", "uniform_shape"],
276 VariableShapeTensorMetadataVisitor,
277 )
278 }
279}
280
281impl VariableShapeTensorMetadata {
282 pub fn try_new(
289 dimensions: usize,
290 dimension_names: Option<Vec<String>>,
291 permutations: Option<Vec<usize>>,
292 uniform_shapes: Option<Vec<Option<i32>>>,
293 ) -> Result<Self, ArrowError> {
294 let dim_names = dimension_names.map(|dimension_names| {
295 if dimension_names.len() != dimensions {
296 Err(ArrowError::InvalidArgumentError(format!(
297 "VariableShapeTensor dimension names size mismatch, expected {dimensions}, found {}", dimension_names.len()
298 )))
299 } else {
300 Ok(dimension_names)
301 }
302 }).transpose()?;
303
304 let permutations = permutations
305 .map(|permutations| {
306 if permutations.len() != dimensions {
307 Err(ArrowError::InvalidArgumentError(format!(
308 "VariableShapeTensor permutations size mismatch, expected {dimensions}, found {}",
309 permutations.len()
310 )))
311 } else {
312 let mut sorted_permutations = permutations.clone();
313 sorted_permutations.sort_unstable();
314 if (0..dimensions).zip(sorted_permutations).any(|(a, b)| a != b) {
315 Err(ArrowError::InvalidArgumentError(format!(
316 "VariableShapeTensor permutations invalid, expected a permutation of [0, 1, .., N-1], where N is the number of dimensions: {dimensions}"
317 )))
318 } else {
319 Ok(permutations)
320 }
321 }
322 })
323 .transpose()?;
324
325 let uniform_shape = uniform_shapes
326 .map(|uniform_shapes| {
327 if uniform_shapes.len() != dimensions {
328 Err(ArrowError::InvalidArgumentError(format!(
329 "VariableShapeTensor uniform shapes size mismatch, expected {dimensions}, found {}",
330 uniform_shapes.len()
331 )))
332 } else {
333 Ok(uniform_shapes)
334 }
335 })
336 .transpose()?;
337
338 Ok(Self {
339 dim_names,
340 permutations,
341 uniform_shape,
342 })
343 }
344
345 pub fn dimension_names(&self) -> Option<&[String]> {
348 self.dim_names.as_ref().map(AsRef::as_ref)
349 }
350
351 pub fn permutations(&self) -> Option<&[usize]> {
354 self.permutations.as_ref().map(AsRef::as_ref)
355 }
356
357 pub fn uniform_shapes(&self) -> Option<&[Option<i32>]> {
361 self.uniform_shape.as_ref().map(AsRef::as_ref)
362 }
363}
364
365impl ExtensionType for VariableShapeTensor {
366 const NAME: &'static str = "arrow.variable_shape_tensor";
367
368 type Metadata = VariableShapeTensorMetadata;
369
370 fn metadata(&self) -> &Self::Metadata {
371 &self.metadata
372 }
373
374 fn serialize_metadata(&self) -> Option<String> {
375 Some(serde_json::to_string(self.metadata()).expect("metadata serialization"))
376 }
377
378 fn deserialize_metadata(metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
379 metadata.map_or_else(
380 || {
381 Err(ArrowError::InvalidArgumentError(
382 "VariableShapeTensor extension types requires metadata".to_owned(),
383 ))
384 },
385 |value| {
386 serde_json::from_str(value).map_err(|e| {
387 ArrowError::InvalidArgumentError(format!(
388 "VariableShapeTensor metadata deserialization failed: {e}"
389 ))
390 })
391 },
392 )
393 }
394
395 fn supports_data_type(&self, data_type: &DataType) -> Result<(), ArrowError> {
396 let expected = DataType::Struct(
397 [
398 Field::new_list(
399 "data",
400 Field::new_list_field(self.value_type.clone(), false),
401 false,
402 ),
403 Field::new(
404 "shape",
405 DataType::new_fixed_size_list(
406 DataType::Int32,
407 i32::try_from(self.dimensions()).expect("overflow"),
408 false,
409 ),
410 false,
411 ),
412 ]
413 .into_iter()
414 .collect(),
415 );
416 data_type
417 .equals_datatype(&expected)
418 .then_some(())
419 .ok_or_else(|| {
420 ArrowError::InvalidArgumentError(format!(
421 "VariableShapeTensor data type mismatch, expected {expected}, found {data_type}"
422 ))
423 })
424 }
425
426 fn try_new(data_type: &DataType, metadata: Self::Metadata) -> Result<Self, ArrowError> {
427 match data_type {
428 DataType::Struct(fields)
429 if fields.len() == 2
430 && matches!(fields.find("data"), Some((0, _)))
431 && matches!(fields.find("shape"), Some((1, _))) =>
432 {
433 let shape_field = &fields[1];
434 match shape_field.data_type() {
435 DataType::FixedSizeList(_, list_size) => {
436 let dimensions = usize::try_from(*list_size).expect("conversion failed");
437 let metadata = VariableShapeTensorMetadata::try_new(
439 dimensions,
440 metadata.dim_names,
441 metadata.permutations,
442 metadata.uniform_shape,
443 )?;
444 let data_field = &fields[0];
445 match data_field.data_type() {
446 DataType::List(field) => Ok(Self {
447 value_type: field.data_type().clone(),
448 dimensions,
449 metadata,
450 }),
451 data_type => Err(ArrowError::InvalidArgumentError(format!(
452 "VariableShapeTensor data type mismatch, expected List for data field, found {data_type}"
453 ))),
454 }
455 }
456 data_type => Err(ArrowError::InvalidArgumentError(format!(
457 "VariableShapeTensor data type mismatch, expected FixedSizeList for shape field, found {data_type}"
458 ))),
459 }
460 }
461 data_type => Err(ArrowError::InvalidArgumentError(format!(
462 "VariableShapeTensor data type mismatch, expected Struct with 2 fields (data and shape), found {data_type}"
463 ))),
464 }
465 }
466}
467
468#[cfg(test)]
469mod tests {
470 #[cfg(feature = "canonical_extension_types")]
471 use crate::extension::CanonicalExtensionType;
472 use crate::{
473 Field,
474 extension::{EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY},
475 };
476
477 use super::*;
478
479 #[test]
480 fn valid() -> Result<(), ArrowError> {
481 let variable_shape_tensor = VariableShapeTensor::try_new(
482 DataType::Float32,
483 3,
484 Some(vec!["C".to_owned(), "H".to_owned(), "W".to_owned()]),
485 Some(vec![2, 0, 1]),
486 Some(vec![Some(400), None, Some(3)]),
487 )?;
488 let mut field = Field::new_struct(
489 "",
490 vec![
491 Field::new_list(
492 "data",
493 Field::new_list_field(DataType::Float32, false),
494 false,
495 ),
496 Field::new_fixed_size_list(
497 "shape",
498 Field::new("", DataType::Int32, false),
499 3,
500 false,
501 ),
502 ],
503 false,
504 );
505 field.try_with_extension_type(variable_shape_tensor.clone())?;
506 assert_eq!(
507 field.try_extension_type::<VariableShapeTensor>()?,
508 variable_shape_tensor
509 );
510 #[cfg(feature = "canonical_extension_types")]
511 assert_eq!(
512 field.try_canonical_extension_type()?,
513 CanonicalExtensionType::VariableShapeTensor(variable_shape_tensor)
514 );
515 Ok(())
516 }
517
518 #[test]
519 #[should_panic(expected = "Extension type name missing")]
520 fn missing_name() {
521 let field = Field::new_struct(
522 "",
523 vec![
524 Field::new_list(
525 "data",
526 Field::new_list_field(DataType::Float32, false),
527 false,
528 ),
529 Field::new_fixed_size_list(
530 "shape",
531 Field::new("", DataType::Int32, false),
532 3,
533 false,
534 ),
535 ],
536 false,
537 )
538 .with_metadata([(EXTENSION_TYPE_METADATA_KEY, "{}")]);
539 field.extension_type::<VariableShapeTensor>();
540 }
541
542 #[test]
543 #[should_panic(expected = "VariableShapeTensor data type mismatch, expected Struct")]
544 fn invalid_type() {
545 let variable_shape_tensor =
546 VariableShapeTensor::try_new(DataType::Int32, 3, None, None, None).unwrap();
547 let field = Field::new_struct(
548 "",
549 vec![
550 Field::new_list(
551 "data",
552 Field::new_list_field(DataType::Float32, false),
553 false,
554 ),
555 Field::new_fixed_size_list(
556 "shape",
557 Field::new("", DataType::Int32, false),
558 3,
559 false,
560 ),
561 ],
562 false,
563 );
564 field.with_extension_type(variable_shape_tensor);
565 }
566
567 #[test]
568 #[should_panic(expected = "VariableShapeTensor extension types requires metadata")]
569 fn missing_metadata() {
570 let field = Field::new_struct(
571 "",
572 vec![
573 Field::new_list(
574 "data",
575 Field::new_list_field(DataType::Float32, false),
576 false,
577 ),
578 Field::new_fixed_size_list(
579 "shape",
580 Field::new("", DataType::Int32, false),
581 3,
582 false,
583 ),
584 ],
585 false,
586 )
587 .with_metadata([(EXTENSION_TYPE_NAME_KEY, VariableShapeTensor::NAME)]);
588 field.extension_type::<VariableShapeTensor>();
589 }
590
591 #[test]
592 #[should_panic(expected = "VariableShapeTensor metadata deserialization failed: invalid type:")]
593 fn invalid_metadata() {
594 let field = Field::new_struct(
595 "",
596 vec![
597 Field::new_list(
598 "data",
599 Field::new_list_field(DataType::Float32, false),
600 false,
601 ),
602 Field::new_fixed_size_list(
603 "shape",
604 Field::new("", DataType::Int32, false),
605 3,
606 false,
607 ),
608 ],
609 false,
610 )
611 .with_metadata([
612 (EXTENSION_TYPE_NAME_KEY, VariableShapeTensor::NAME),
613 (
614 EXTENSION_TYPE_METADATA_KEY,
615 r#"{ "dim_names": [1, null, 3, 4] }"#,
616 ),
617 ]);
618 field.extension_type::<VariableShapeTensor>();
619 }
620
621 #[test]
622 #[should_panic(
623 expected = "VariableShapeTensor dimension names size mismatch, expected 3, found 2"
624 )]
625 fn invalid_metadata_dimension_names() {
626 VariableShapeTensor::try_new(
627 DataType::Float32,
628 3,
629 Some(vec!["a".to_owned(), "b".to_owned()]),
630 None,
631 None,
632 )
633 .unwrap();
634 }
635
636 #[test]
637 #[should_panic(
638 expected = "VariableShapeTensor permutations size mismatch, expected 3, found 2"
639 )]
640 fn invalid_metadata_permutations_len() {
641 VariableShapeTensor::try_new(DataType::Float32, 3, None, Some(vec![1, 0]), None).unwrap();
642 }
643
644 #[test]
645 #[should_panic(
646 expected = "VariableShapeTensor permutations invalid, expected a permutation of [0, 1, .., N-1], where N is the number of dimensions: 3"
647 )]
648 fn invalid_metadata_permutations_values() {
649 VariableShapeTensor::try_new(DataType::Float32, 3, None, Some(vec![4, 3, 2]), None)
650 .unwrap();
651 }
652
653 #[test]
654 #[should_panic(
655 expected = "VariableShapeTensor uniform shapes size mismatch, expected 3, found 2"
656 )]
657 fn invalid_metadata_uniform_shapes() {
658 VariableShapeTensor::try_new(DataType::Float32, 3, None, None, Some(vec![None, Some(1)]))
659 .unwrap();
660 }
661}