1use core::f32;
2
3use alloc::format;
4use alloc::string::String;
5use alloc::vec::Vec;
6use bytemuck::checked::CheckedCastError;
7use rand::Rng;
8use thiserror::Error;
9
10use crate::Scalar;
11use crate::distribution::Distribution;
12use crate::element::{Element, ElementConversion};
13use crate::tensor::DType;
14use crate::{
15 AccessError, BoolStore, Bytes, ExecutionError, QuantMode, QuantScheme, QuantValue,
16 QuantizedBytes, Reader, Shape, Writer, bf16, f16,
17};
18
19use serde::{Deserialize, Serialize};
20
21#[derive(Debug, Error, PartialEq, Eq)]
23pub enum DataError {
24 #[error("Failed to access TensorData storage: {0}")]
26 StorageAccess(#[from] AccessError),
27
28 #[error("TensorData storage is invalid for the requested element type: {0}")]
30 InvalidRepresentation(CheckedCastError),
31
32 #[error("Expected data type {expected:?}, but got {actual:?}")]
34 DTypeMismatch {
35 expected: DType,
37
38 actual: DType,
40 },
41
42 #[error("Unsupported data conversion from {from:?} to {to:?}")]
44 UnsupportedConversion {
45 from: DType,
47
48 to: DType,
50 },
51
52 #[error("TensorData shape describes {expected} element(s), but storage contains {actual}")]
54 ElementCountMismatch {
55 expected: usize,
57
58 actual: usize,
60 },
61}
62
63#[derive(Debug, Error)]
65pub enum TensorReadError {
66 #[error(transparent)]
68 Execution(#[from] ExecutionError),
69
70 #[error(transparent)]
72 Data(#[from] DataError),
73
74 #[error("Expected {expected} tensor element(s), but got {actual}")]
76 InvalidShape {
77 expected: usize,
79
80 actual: usize,
82 },
83}
84
85impl DataError {
86 pub(super) fn dtype_mismatch_as<E: Element>(actual: DType) -> Self {
88 Self::DTypeMismatch {
89 expected: E::dtype(),
90 actual,
91 }
92 }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
97#[serde(try_from = "TensorDataDe")]
98pub struct TensorData {
99 pub bytes: Bytes,
101
102 #[serde(with = "shape_inner")]
104 pub shape: Shape,
105
106 pub dtype: DType,
108}
109
110#[derive(Deserialize)]
113struct TensorDataDe {
114 bytes: Bytes,
115 #[serde(with = "shape_inner")]
116 shape: Shape,
117 dtype: DType,
118}
119
120impl TryFrom<TensorDataDe> for TensorData {
121 type Error = String;
122
123 fn try_from(data: TensorDataDe) -> Result<Self, Self::Error> {
124 let expected = data
129 .shape
130 .iter()
131 .try_fold(1usize, |numel, dim| numel.checked_mul(*dim))
132 .and_then(|numel| numel.checked_mul(data.dtype.size()));
133
134 if !matches!(data.dtype, DType::QFloat(_)) && expected != Some(data.bytes.len()) {
135 return Err(format!(
136 "Shape {:?} is invalid for input of size {:?} bytes",
137 data.shape,
138 data.bytes.len(),
139 ));
140 }
141
142 Ok(Self {
143 bytes: data.bytes,
144 shape: data.shape,
145 dtype: data.dtype,
146 })
147 }
148}
149
150mod shape_inner {
152 use crate::SmallVec;
153
154 use super::*;
155
156 pub fn serialize<S: serde::Serializer>(
157 shape: &Shape,
158 serializer: S,
159 ) -> Result<S::Ok, S::Error> {
160 shape.as_slice().serialize(serializer)
161 }
162
163 pub fn deserialize<'de, D: serde::Deserializer<'de>>(
164 deserializer: D,
165 ) -> Result<Shape, D::Error> {
166 let dims = SmallVec::<[usize; _]>::deserialize(deserializer)?;
167 Ok(Shape::new_raw(dims))
168 }
169}
170
171impl TensorData {
172 pub fn new<E: Element, S: Into<Shape>>(value: Vec<E>, shape: S) -> Self {
174 let shape = shape.into();
176 Self::check_data_len(&value, &shape);
177
178 Self {
179 bytes: Bytes::from_elems(value),
180 shape,
181 dtype: E::dtype(),
182 }
183 }
184
185 pub fn quantized<E: Element, S: Into<Shape>>(
187 value: Vec<E>,
188 shape: S,
189 scheme: QuantScheme,
190 qparams: &[f32],
191 global: Option<f32>,
192 ) -> Self {
193 let shape = shape.into();
194 Self::check_data_len(&value, &shape);
195
196 let q_bytes = QuantizedBytes::new(value, shape.clone(), scheme, qparams, global);
197
198 Self {
199 bytes: q_bytes.bytes,
200 shape,
201 dtype: DType::QFloat(q_bytes.scheme),
202 }
203 }
204
205 pub fn from_bytes<S: Into<Shape>>(bytes: Bytes, shape: S, dtype: DType) -> Self {
207 Self {
208 bytes,
209 shape: shape.into(),
210 dtype,
211 }
212 }
213
214 pub fn from_bytes_vec<S: Into<Shape>>(bytes: Vec<u8>, shape: S, dtype: DType) -> Self {
219 Self {
220 bytes: Bytes::from_bytes_vec(bytes),
221 shape: shape.into(),
222 dtype,
223 }
224 }
225
226 fn check_data_len<E: Element>(data: &[E], shape: &Shape) {
228 let expected_data_len = numel(shape);
229 let num_data = data.len();
230 assert_eq!(
231 expected_data_len, num_data,
232 "Shape {shape:?} is invalid for input of size {num_data:?}",
233 );
234 }
235
236 pub fn as_slice<E: Element>(&self) -> Result<&[E], DataError> {
245 if self.matches_target_dtype::<E>() {
246 bytemuck::checked::try_cast_slice(self.bytes.read(Reader::new())?)
247 .map_err(DataError::InvalidRepresentation)
248 } else {
249 Err(DataError::dtype_mismatch_as::<E>(self.dtype))
250 }
251 }
252
253 pub fn as_mut_slice<E: Element>(&mut self) -> Result<&mut [E], DataError> {
262 if self.matches_target_dtype::<E>() {
263 bytemuck::checked::try_cast_slice_mut(self.bytes.write(Writer::new())?)
264 .map_err(DataError::InvalidRepresentation)
265 } else {
266 Err(DataError::dtype_mismatch_as::<E>(self.dtype))
267 }
268 }
269
270 pub(super) fn matches_target_dtype<E: Element>(&self) -> bool {
271 let target_dtype = E::dtype();
272 match self.dtype {
273 DType::Bool(BoolStore::U8) => {
274 matches!(target_dtype, DType::U8 | DType::Bool(BoolStore::U8))
275 }
276 DType::Bool(BoolStore::U32) => {
277 matches!(target_dtype, DType::U32 | DType::Bool(BoolStore::U32))
278 }
279 dtype => dtype == target_dtype,
280 }
281 }
282
283 pub fn rank(&self) -> usize {
285 self.shape.len()
286 }
287
288 pub fn num_elements(&self) -> usize {
290 numel(&self.shape)
291 }
292
293 pub fn random<E: Element, R: Rng, S: Into<Shape>>(
295 shape: S,
296 distribution: Distribution,
297 rng: &mut R,
298 ) -> Self {
299 let shape = shape.into();
300 let num_elements = numel(&shape);
301 let mut data = Vec::with_capacity(num_elements);
302
303 for _ in 0..num_elements {
304 data.push(E::random(distribution, rng));
305 }
306
307 TensorData::new(data, shape)
308 }
309
310 pub fn zeros<E: Element, S: Into<Shape>>(shape: S) -> TensorData {
312 let shape = shape.into();
313 let num_elements = numel(&shape);
314 let mut data = Vec::<E>::with_capacity(num_elements);
315
316 for _ in 0..num_elements {
317 data.push(0.elem());
318 }
319
320 TensorData::new(data, shape)
321 }
322
323 pub fn ones<E: Element, S: Into<Shape>>(shape: S) -> TensorData {
325 let shape = shape.into();
326 let num_elements = numel(&shape);
327 let mut data = Vec::<E>::with_capacity(num_elements);
328
329 for _ in 0..num_elements {
330 data.push(1.elem());
331 }
332
333 TensorData::new(data, shape)
334 }
335
336 pub fn full<E: Element, S: Into<Shape>>(shape: S, fill_value: E) -> TensorData {
338 let shape = shape.into();
339 let num_elements = numel(&shape);
340 let mut data = Vec::<E>::with_capacity(num_elements);
341 for _ in 0..num_elements {
342 data.push(fill_value)
343 }
344
345 TensorData::new(data, shape)
346 }
347
348 pub fn full_dtype<E: Into<Scalar>, S: Into<Shape>>(
350 shape: S,
351 fill_value: E,
352 dtype: DType,
353 ) -> TensorData {
354 let fill_value = fill_value.into();
355 match dtype {
356 DType::F64 => Self::full::<f64, _>(shape, fill_value.elem()),
357 DType::F32 | DType::Flex32 => Self::full::<f32, _>(shape, fill_value.elem()),
358 DType::F16 => Self::full::<f16, _>(shape, fill_value.elem()),
359 DType::BF16 => Self::full::<bf16, _>(shape, fill_value.elem()),
360 DType::I64 => Self::full::<i64, _>(shape, fill_value.elem()),
361 DType::I32 => Self::full::<i32, _>(shape, fill_value.elem()),
362 DType::I16 => Self::full::<i16, _>(shape, fill_value.elem()),
363 DType::I8 => Self::full::<i8, _>(shape, fill_value.elem()),
364 DType::U64 => Self::full::<u64, _>(shape, fill_value.elem()),
365 DType::U32 => Self::full::<u32, _>(shape, fill_value.elem()),
366 DType::U16 => Self::full::<u16, _>(shape, fill_value.elem()),
367 DType::U8 => Self::full::<u8, _>(shape, fill_value.elem()),
368 DType::Bool(BoolStore::Native) => Self::full::<bool, _>(shape, fill_value.elem()),
369 DType::Bool(BoolStore::U8) => {
370 Self::full::<u8, _>(shape, fill_value.elem()).into_bool_u8()
371 }
372 DType::Bool(BoolStore::U32) => {
373 Self::full::<u32, _>(shape, fill_value.elem()).into_bool_u32()
374 }
375 DType::QFloat(_) => unreachable!(),
376 }
377 }
378
379 pub(super) fn into_bool_u8(mut self) -> Self {
381 self.dtype = DType::Bool(BoolStore::U8);
382 self
383 }
384
385 pub(super) fn into_bool_u32(mut self) -> Self {
387 self.dtype = DType::Bool(BoolStore::U32);
388 self
389 }
390
391 pub fn as_bytes(&self) -> &[u8] {
393 &self.bytes
394 }
395
396 pub fn into_bytes(self) -> Bytes {
398 self.bytes
399 }
400}
401
402fn numel(shape: &[usize]) -> usize {
403 shape.iter().product()
404}
405
406impl<E: Element, const A: usize> From<[E; A]> for TensorData {
407 fn from(elems: [E; A]) -> Self {
408 TensorData::new(elems.to_vec(), [A])
409 }
410}
411
412impl<const A: usize> From<[usize; A]> for TensorData {
413 fn from(elems: [usize; A]) -> Self {
414 TensorData::new(elems.iter().map(|&e| e as i64).collect(), [A])
415 }
416}
417
418impl From<&[usize]> for TensorData {
419 fn from(elems: &[usize]) -> Self {
420 let mut data = Vec::with_capacity(elems.len());
421 for elem in elems.iter() {
422 data.push(*elem as i64);
423 }
424
425 TensorData::new(data, [elems.len()])
426 }
427}
428
429impl<E: Element> From<&[E]> for TensorData {
430 fn from(elems: &[E]) -> Self {
431 let mut data = Vec::with_capacity(elems.len());
432 for elem in elems.iter() {
433 data.push(*elem);
434 }
435
436 TensorData::new(data, [elems.len()])
437 }
438}
439
440impl<E: Element, const A: usize, const B: usize> From<[[E; B]; A]> for TensorData {
441 fn from(elems: [[E; B]; A]) -> Self {
442 let mut data = Vec::with_capacity(A * B);
443 for elem in elems.into_iter().take(A) {
444 for elem in elem.into_iter().take(B) {
445 data.push(elem);
446 }
447 }
448
449 TensorData::new(data, [A, B])
450 }
451}
452
453impl<E: Element, const A: usize, const B: usize, const C: usize> From<[[[E; C]; B]; A]>
454 for TensorData
455{
456 fn from(elems: [[[E; C]; B]; A]) -> Self {
457 let mut data = Vec::with_capacity(A * B * C);
458
459 for elem in elems.into_iter().take(A) {
460 for elem in elem.into_iter().take(B) {
461 for elem in elem.into_iter().take(C) {
462 data.push(elem);
463 }
464 }
465 }
466
467 TensorData::new(data, [A, B, C])
468 }
469}
470
471impl<E: Element, const A: usize, const B: usize, const C: usize, const D: usize>
472 From<[[[[E; D]; C]; B]; A]> for TensorData
473{
474 fn from(elems: [[[[E; D]; C]; B]; A]) -> Self {
475 let mut data = Vec::with_capacity(A * B * C * D);
476
477 for elem in elems.into_iter().take(A) {
478 for elem in elem.into_iter().take(B) {
479 for elem in elem.into_iter().take(C) {
480 for elem in elem.into_iter().take(D) {
481 data.push(elem);
482 }
483 }
484 }
485 }
486
487 TensorData::new(data, [A, B, C, D])
488 }
489}
490
491impl<Elem: Element, const A: usize, const B: usize, const C: usize, const D: usize, const E: usize>
492 From<[[[[[Elem; E]; D]; C]; B]; A]> for TensorData
493{
494 fn from(elems: [[[[[Elem; E]; D]; C]; B]; A]) -> Self {
495 let mut data = Vec::with_capacity(A * B * C * D * E);
496
497 for elem in elems.into_iter().take(A) {
498 for elem in elem.into_iter().take(B) {
499 for elem in elem.into_iter().take(C) {
500 for elem in elem.into_iter().take(D) {
501 for elem in elem.into_iter().take(E) {
502 data.push(elem);
503 }
504 }
505 }
506 }
507 }
508
509 TensorData::new(data, [A, B, C, D, E])
510 }
511}
512impl core::fmt::Display for TensorData {
513 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
514 let fmt = match self.dtype {
515 DType::F64 => format!("{:?}", self.as_slice::<f64>().unwrap()),
516 DType::F32 | DType::Flex32 => format!("{:?}", self.as_slice::<f32>().unwrap()),
517 DType::F16 => format!("{:?}", self.as_slice::<f16>().unwrap()),
518 DType::BF16 => format!("{:?}", self.as_slice::<bf16>().unwrap()),
519 DType::I64 => format!("{:?}", self.as_slice::<i64>().unwrap()),
520 DType::I32 => format!("{:?}", self.as_slice::<i32>().unwrap()),
521 DType::I16 => format!("{:?}", self.as_slice::<i16>().unwrap()),
522 DType::I8 => format!("{:?}", self.as_slice::<i8>().unwrap()),
523 DType::U64 => format!("{:?}", self.as_slice::<u64>().unwrap()),
524 DType::U32 => format!("{:?}", self.as_slice::<u32>().unwrap()),
525 DType::U16 => format!("{:?}", self.as_slice::<u16>().unwrap()),
526 DType::U8 => format!("{:?}", self.as_slice::<u8>().unwrap()),
527 DType::Bool(BoolStore::Native) => format!("{:?}", self.as_slice::<bool>().unwrap()),
528 DType::Bool(BoolStore::U8) => format!("{:?}", self.as_slice::<u8>().unwrap()),
529 DType::Bool(BoolStore::U32) => format!("{:?}", self.as_slice::<u32>().unwrap()),
530 DType::QFloat(scheme) => match scheme {
531 QuantScheme {
532 mode: QuantMode::Symmetric,
533 value:
534 QuantValue::Q8F
535 | QuantValue::Q8S
536 | QuantValue::Q4F
538 | QuantValue::Q4S
539 | QuantValue::Q2F
540 | QuantValue::Q2S,
541 ..
542 } => {
543 format!("{:?} {scheme:?}", self.iter::<i8>().collect::<Vec<_>>())
544 },
545 QuantScheme {
546 mode: QuantMode::Symmetric,
547 value:
548 QuantValue::E4M3 | QuantValue::E5M2 | QuantValue::E2M1,
549 ..
550 } => {
551 unimplemented!("Can't format yet");
552 }
553 QuantScheme {
554 mode: QuantMode::Lookup,
555 ..
556 } => {
557 format!("<lookup-quantized> {scheme:?}")
558 }
559 },
560 };
561 f.write_str(fmt.as_str())
562 }
563}
564
565#[cfg(test)]
566mod tests {
567 use super::*;
568 use crate::*;
569 use ::rand::{
570 SeedableRng,
571 rngs::{StdRng, SysRng},
572 };
573 use alloc::string::ToString;
574 use alloc::vec;
575 use core::mem::{MaybeUninit, align_of, size_of};
576
577 #[test]
578 fn should_have_rank() {
579 let shape = [3, 5, 6];
580 let data = TensorData::random::<f32, _, _>(
581 shape,
582 Distribution::Default,
583 &mut StdRng::try_from_rng(&mut SysRng).unwrap(),
584 );
585
586 assert_eq!(data.rank(), 3);
587 }
588
589 #[test]
590 fn into_vec_should_yield_same_value_as_iter() {
591 let shape = [3, 5, 6];
592 let data = TensorData::random::<f32, _, _>(
593 shape,
594 Distribution::Default,
595 &mut StdRng::try_from_rng(&mut SysRng).unwrap(),
596 );
597
598 let expected = data.iter::<f32>().collect::<Vec<f32>>();
599 let actual = data.try_into_vec::<f32>().unwrap();
600
601 assert_eq!(expected, actual);
602 }
603
604 #[test]
605 #[should_panic]
606 fn into_vec_should_assert_wrong_dtype() {
607 let shape = [3, 5, 6];
608 let data = TensorData::random::<f32, _, _>(
609 shape,
610 Distribution::Default,
611 &mut StdRng::try_from_rng(&mut SysRng).unwrap(),
612 );
613
614 data.try_into_vec::<i32>().unwrap();
615 }
616
617 #[test]
618 fn should_have_right_num_elements() {
619 let shape = [3, 5, 6];
620 let num_elements: usize = shape.iter().product();
621 let data = TensorData::random::<f32, _, _>(
622 shape,
623 Distribution::Default,
624 &mut StdRng::try_from_rng(&mut SysRng).unwrap(),
625 );
626
627 assert_eq!(num_elements, data.bytes.len() / 4); assert_eq!(num_elements, data.as_slice::<f32>().unwrap().len());
629 }
630
631 #[test]
632 fn should_have_right_shape() {
633 let data = TensorData::from([[3.0, 5.0, 6.0]]);
634 assert_eq!(data.shape, shape![1, 3]);
635
636 let data = TensorData::from([[4.0, 5.0, 8.0], [3.0, 5.0, 6.0]]);
637 assert_eq!(data.shape, shape![2, 3]);
638
639 let data = TensorData::from([3.0, 5.0, 6.0]);
640 assert_eq!(data.shape, shape![3]);
641 }
642
643 #[test]
644 fn should_convert_bytes_correctly() {
645 let mut vector: Vec<f32> = Vec::with_capacity(5);
646 vector.push(2.0);
647 vector.push(3.0);
648 let data1 = TensorData::new(vector, vec![2]);
649
650 let factor = size_of::<f32>() / size_of::<u8>();
651 assert_eq!(data1.bytes.len(), 2 * factor);
652 assert_eq!(data1.bytes.capacity(), 5 * factor);
653 }
654
655 #[test]
656 fn should_convert_bytes_correctly_inplace() {
657 fn test_precision<E: Element>() {
658 let data = TensorData::new((0..32).collect(), [32]);
659 let self1 = data.clone().convert::<E>();
660 for (i, val) in self1.try_into_vec::<E>().unwrap().into_iter().enumerate() {
661 assert_eq!(i as u32, val.elem::<u32>())
662 }
663 }
664 test_precision::<f32>();
665 test_precision::<f16>();
666 test_precision::<i64>();
667 test_precision::<i32>();
668 }
669
670 #[test]
671 fn should_convert_negative_values_to_bool_store() {
672 for store in [BoolStore::U8, BoolStore::U32, BoolStore::Native] {
673 let data = TensorData::from([-1i32, 0, 1, -12]).convert_dtype(DType::Bool(store));
674 assert_eq!(data.dtype, DType::Bool(store));
675 assert_eq!(
676 data.iter::<bool>().collect::<Vec<_>>(),
677 [true, false, true, true]
678 );
679
680 let data = TensorData::from([-1.5f32, 0.0, 0.5]).convert_dtype(DType::Bool(store));
681 assert_eq!(data.iter::<bool>().collect::<Vec<_>>(), [true, false, true]);
682 }
683 }
684
685 macro_rules! test_dtypes {
686 ($test_name:ident, $($dtype:ty),*) => {
687 $(
688 paste::paste! {
689 #[test]
690 fn [<$test_name _ $dtype:snake>]() {
691 let full_dtype = TensorData::full_dtype([2, 16], 4, <$dtype>::dtype());
692 let full = TensorData::full::<$dtype, _>([2, 16], 4.elem());
693 assert_eq!(full_dtype, full);
694 }
695 }
696 )*
697 };
698}
699
700 test_dtypes!(
701 should_create_with_dtype,
702 bool,
703 i8,
704 i16,
705 i32,
706 i64,
707 u8,
708 u16,
709 u32,
710 u64,
711 f16,
712 bf16,
713 f32,
714 f64
715 );
716
717 #[test]
718 fn should_serialize_deserialize_tensor_data() {
719 let data = TensorData::new(vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0], [2, 3]);
720 assert_eq!(
721 data.as_bytes(),
722 [
723 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 128, 64, 0, 0, 160, 64, 0, 0, 192,
724 64
725 ]
726 );
727 let serialized = serde_json::to_string(&data).unwrap();
728 let deserialized: TensorData = serde_json::from_str(&serialized).unwrap();
729 assert_eq!(data, deserialized);
730 }
731
732 #[test]
733 fn should_deserialize_tensor_data_with_shape_inner() {
734 let serialized = r#"{
736 "bytes": [0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 128, 64, 0, 0, 160, 64, 0, 0, 192, 64],
737 "shape": [2, 3],
738 "dtype": "F32"
739 }"#;
740
741 let data: TensorData = serde_json::from_str(serialized).unwrap();
742 assert_eq!(data.shape, shape![2, 3]);
743 assert_eq!(
744 data.as_slice::<f32>().unwrap(),
745 &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
746 );
747 }
748
749 #[test]
750 fn should_not_deserialize_tensor_data_with_shape_larger_than_bytes() {
751 let serialized = r#"{"bytes": [0, 0, 128, 63], "shape": [1000], "dtype": "F32"}"#;
754
755 let err = serde_json::from_str::<TensorData>(serialized).unwrap_err();
756 assert!(
757 err.to_string().contains("is invalid for input of size"),
758 "unexpected error: {err}"
759 );
760 }
761
762 #[test]
763 fn should_not_deserialize_tensor_data_with_overflowing_shape() {
764 let serialized = r#"{"bytes": [0, 0, 128, 63, 0, 0, 0, 64], "shape": [9223372036854775809, 2], "dtype": "F32"}"#;
767
768 let err = serde_json::from_str::<TensorData>(serialized).unwrap_err();
769 assert!(
770 err.to_string().contains("is invalid for input of size"),
771 "unexpected error: {err}"
772 );
773 }
774
775 #[test]
776 fn should_serialize_shape_as_flat_array() {
777 let data = TensorData::new(vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0], [2, 3]);
780 let serialized = serde_json::to_string(&data).unwrap();
781 let json: serde_json::Value = serde_json::from_str(&serialized).unwrap();
782 assert_eq!(json["shape"], serde_json::json!([2, 3]));
783 }
784
785 #[test]
786 fn test_tensor_data_try_view_dtype_mismatch() {
787 let data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
788 let dtype = data.dtype;
789
790 assert_eq!(
791 data.try_view::<i32>().unwrap_err(),
792 DataError::DTypeMismatch {
793 expected: <i32 as Element>::dtype(),
794 actual: dtype,
795 }
796 );
797 }
798
799 #[test]
800 #[should_panic(expected = "Expected data type")]
801 fn test_tensor_data_expect_view_dtype_mismatch() {
802 let data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
803 let _view = data.view::<i32>();
804 }
805
806 #[test]
807 fn test_tensor_data_try_mut_view_dtype_mismatch() {
808 let mut data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
809
810 let result = data.try_mut_view::<i32>();
811 assert_eq!(
812 result.unwrap_err(),
813 DataError::DTypeMismatch {
814 actual: data.dtype,
815 expected: <i32 as Element>::dtype(),
816 }
817 );
818 }
819
820 #[test]
821 fn try_view_validates_storage() {
822 let invalid_representation = TensorData::from_bytes_vec(vec![0; 3], [1], DType::F32);
823 assert!(matches!(
824 invalid_representation.try_view::<f32>(),
825 Err(DataError::InvalidRepresentation(_))
826 ));
827
828 let invalid_count = TensorData::from_bytes_vec(vec![0; 8], [1], DType::F32);
829 assert!(matches!(
830 invalid_count.try_view::<f32>(),
831 Err(DataError::ElementCountMismatch {
832 expected: 1,
833 actual: 2
834 })
835 ));
836
837 let invalid_bool = TensorData::from_bytes_vec(vec![2], [1], DType::Bool(BoolStore::Native));
838 assert!(matches!(
839 invalid_bool.try_view::<bool>(),
840 Err(DataError::InvalidRepresentation(_))
841 ));
842 }
843
844 #[test]
845 fn try_view_propagates_storage_access_failure() {
846 use alloc::boxed::Box;
847
848 #[derive(Debug)]
849 struct FailingController;
850
851 impl AllocationController for FailingController {
852 fn alloc_align(&self) -> usize {
853 align_of::<f32>()
854 }
855
856 fn property(&self) -> AllocationProperty {
857 AllocationProperty::Other
858 }
859
860 fn capacity(&self) -> usize {
861 size_of::<f32>()
862 }
863
864 fn memory(&self, _policy: AccessPolicy) -> Result<&[MaybeUninit<u8>], AccessError> {
865 Err(AccessError::Read("test read failure".into()))
866 }
867
868 unsafe fn memory_mut(
869 &mut self,
870 _policy: AccessPolicy,
871 ) -> Result<&mut [MaybeUninit<u8>], AccessError> {
872 Err(AccessError::Read("test write failure".into()))
873 }
874 }
875
876 let bytes =
878 unsafe { Bytes::from_controller(Box::new(FailingController), size_of::<f32>()) };
879 let data = TensorData::from_bytes(bytes, [1], DType::F32);
880
881 assert!(matches!(
882 data.try_view::<f32>(),
883 Err(DataError::StorageAccess(AccessError::Read(reason))) if reason == "test read failure"
884 ));
885 }
886
887 #[test]
888 fn try_mut_view_validates_storage() {
889 let mut invalid_representation = TensorData::from_bytes_vec(vec![0; 3], [1], DType::F32);
890 assert!(matches!(
891 invalid_representation.try_mut_view::<f32>(),
892 Err(DataError::InvalidRepresentation(_))
893 ));
894 }
895
896 #[test]
897 fn try_cast_propagates_invalid_storage() {
898 let invalid_inplace = TensorData::from_bytes_vec(vec![0; 3], [1], DType::F32);
899 assert!(matches!(
900 invalid_inplace.try_cast(DType::I32),
901 Err(DataError::InvalidRepresentation(_))
902 ));
903
904 let invalid_clone = TensorData::from_bytes_vec(vec![0; 3], [1], DType::F32);
905 assert!(matches!(
906 invalid_clone.try_cast(DType::F64),
907 Err(DataError::InvalidRepresentation(_))
908 ));
909
910 let invalid_count = TensorData::from_bytes_vec(vec![0; 8], [1], DType::F32);
911 assert!(matches!(
912 invalid_count.try_cast(DType::F64),
913 Err(DataError::ElementCountMismatch {
914 expected: 1,
915 actual: 2
916 })
917 ));
918 }
919
920 #[test]
921 fn try_cast_reports_unsupported_quantized_conversion() {
922 let scheme = QuantScheme::default();
923 let target = DType::QFloat(scheme);
924
925 assert_eq!(
926 TensorData::from([1.0f32]).try_cast(target),
927 Err(DataError::UnsupportedConversion {
928 from: DType::F32,
929 to: target,
930 })
931 );
932
933 let quantized = TensorData::quantized(vec![0i8], [1], scheme, &[1.0], None);
934 assert_eq!(
935 quantized.try_cast(DType::F32),
936 Err(DataError::UnsupportedConversion {
937 from: target,
938 to: DType::F32,
939 })
940 );
941 }
942
943 #[test]
944 #[should_panic(expected = "Expected data type")]
945 fn test_tensor_data_expect_mut_view_dtype_mismatch() {
946 let mut data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
947 let _view = data.mut_view::<i32>();
948 }
949
950 #[test]
951 fn test_tensor_data_index_view() {
952 let data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
953 let view = data.view::<f64>();
954
955 assert_eq!(view.shape(), &data.shape);
956
957 assert_eq!(view[&[0, 0]], 1.0);
958 assert_eq!(view[&[0, 1]], 2.0);
959 assert_eq!(view[&[1, 0]], 3.0);
960 assert_eq!(view[&[1, 1]], 4.0);
961 }
962
963 #[test]
964 fn test_tensor_data_index_mut_view() {
965 let mut data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
966 let shape = data.shape.clone();
967
968 let mut view = data.mut_view::<f64>();
969
970 assert_eq!(view.shape(), &shape);
971
972 assert_eq!(view[&[0, 0]], 1.0);
973 assert_eq!(view[&[0, 1]], 2.0);
974 assert_eq!(view[&[1, 0]], 3.0);
975 assert_eq!(view[&[1, 1]], 4.0);
976
977 view[&[0, 0]] = 10.0;
978 assert_eq!(view[&[0, 0]], 10.0);
979 }
980
981 #[test]
982 fn test_to_vec_as() {
983 let data = TensorData::from([0.0f32, 1.0, 2.5]);
984
985 assert_eq!(data.try_to_vec_as::<f32>().unwrap(), vec![0.0f32, 1.0, 2.5]);
987
988 assert_eq!(data.try_to_vec_as::<f64>().unwrap(), vec![0.0f64, 1.0, 2.5]);
990
991 assert_eq!(data.try_to_vec_as::<i32>().unwrap(), vec![0i32, 1, 2]);
993
994 data.assert_eq(&TensorData::from([0.0f32, 1.0, 2.5]), true);
996 }
997
998 #[test]
999 fn test_into_vec_as() {
1000 let data = TensorData::from([0i32, 1, 2, 3]);
1001
1002 assert_eq!(
1004 data.clone().try_into_vec_as::<i32>().unwrap(),
1005 vec![0i32, 1, 2, 3]
1006 );
1007
1008 assert_eq!(
1010 data.clone().try_into_vec_as::<f32>().unwrap(),
1011 vec![0.0f32, 1.0, 2.0, 3.0]
1012 );
1013
1014 assert_eq!(data.try_into_vec_as::<u8>().unwrap(), vec![0u8, 1, 2, 3]);
1016 }
1017}