1use core::f32;
2
3use alloc::format;
4use alloc::vec::Vec;
5use bytemuck::checked::CheckedCastError;
6use rand::Rng;
7use thiserror::Error;
8
9use crate::Scalar;
10use crate::distribution::Distribution;
11use crate::element::{Element, ElementConversion};
12use crate::tensor::DType;
13use crate::{
14 AccessError, BoolStore, Bytes, ExecutionError, QuantMode, QuantScheme, QuantValue,
15 QuantizedBytes, Reader, Shape, Writer, bf16, f16, flex32,
16};
17
18use serde::{Deserialize, Serialize};
19
20#[derive(Debug, Error, PartialEq, Eq)]
22pub enum DataError {
23 #[error("Failed to access TensorData storage: {0}")]
25 StorageAccess(#[from] AccessError),
26
27 #[error("TensorData storage is invalid for the requested element type: {0}")]
29 InvalidRepresentation(CheckedCastError),
30
31 #[error("Expected data type {expected:?}, but got {actual:?}")]
33 DTypeMismatch {
34 expected: DType,
36
37 actual: DType,
39 },
40
41 #[error("Unsupported data conversion from {from:?} to {to:?}")]
43 UnsupportedConversion {
44 from: DType,
46
47 to: DType,
49 },
50
51 #[error("TensorData shape describes {expected} element(s), but storage contains {actual}")]
53 ElementCountMismatch {
54 expected: usize,
56
57 actual: usize,
59 },
60
61 #[error(
63 "Shape {:?} with dtype {dtype:?} is invalid for input of size {len} bytes",
64 shape.as_slice()
65 )]
66 InvalidByteLength {
67 shape: Shape,
69
70 dtype: DType,
72
73 len: usize,
75 },
76
77 #[error("Quantized layout for shape {:?} and dtype {dtype:?} is invalid", shape.as_slice())]
79 InvalidQuantizedLayout {
80 shape: Shape,
82
83 dtype: DType,
85 },
86}
87
88#[derive(Debug, Error)]
90pub enum TensorReadError {
91 #[error(transparent)]
93 Execution(#[from] ExecutionError),
94
95 #[error(transparent)]
97 Data(#[from] DataError),
98
99 #[error("Expected {expected} tensor element(s), but got {actual}")]
101 InvalidShape {
102 expected: usize,
104
105 actual: usize,
107 },
108}
109
110impl DataError {
111 pub(super) fn dtype_mismatch_as<E: Element>(actual: DType) -> Self {
113 Self::DTypeMismatch {
114 expected: E::dtype(),
115 actual,
116 }
117 }
118}
119
120#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
125#[serde(try_from = "TensorDataDe")]
126pub struct TensorData {
127 pub(in crate::data) bytes: Bytes,
129
130 #[serde(with = "shape_inner")]
132 pub(in crate::data) shape: Shape,
133
134 pub(in crate::data) dtype: DType,
136}
137
138#[derive(Deserialize)]
141struct TensorDataDe {
142 bytes: Bytes,
143 #[serde(with = "shape_inner")]
144 shape: Shape,
145 dtype: DType,
146}
147
148impl TryFrom<TensorDataDe> for TensorData {
149 type Error = DataError;
150
151 fn try_from(data: TensorDataDe) -> Result<Self, Self::Error> {
152 TensorData::try_from_bytes(data.bytes, data.shape, data.dtype)
153 }
154}
155
156mod shape_inner {
158 use crate::SmallVec;
159
160 use super::*;
161
162 pub fn serialize<S: serde::Serializer>(
163 shape: &Shape,
164 serializer: S,
165 ) -> Result<S::Ok, S::Error> {
166 shape.as_slice().serialize(serializer)
167 }
168
169 pub fn deserialize<'de, D: serde::Deserializer<'de>>(
170 deserializer: D,
171 ) -> Result<Shape, D::Error> {
172 let dims = SmallVec::<[usize; _]>::deserialize(deserializer)?;
173 Ok(Shape::new_raw(dims))
174 }
175}
176
177impl TensorData {
178 pub fn new<E: Element, S: Into<Shape>>(value: Vec<E>, shape: S) -> Self {
180 let shape = shape.into();
182 Self::check_data_len(&value, &shape);
183
184 Self {
185 bytes: Bytes::from_elems(value),
186 shape,
187 dtype: E::dtype(),
188 }
189 }
190
191 pub fn quantized<E: Element, S: Into<Shape>>(
193 value: Vec<E>,
194 shape: S,
195 scheme: QuantScheme,
196 qparams: &[f32],
197 global: Option<f32>,
198 ) -> Self {
199 let shape = shape.into();
200 Self::check_data_len(&value, &shape);
201
202 let q_bytes = QuantizedBytes::new(value, shape.clone(), scheme, qparams, global);
203
204 Self {
205 bytes: q_bytes.bytes,
206 shape,
207 dtype: DType::QFloat(q_bytes.scheme),
208 }
209 }
210
211 #[track_caller]
218 pub fn from_bytes<S: Into<Shape>>(bytes: Bytes, shape: S, dtype: DType) -> Self {
219 match Self::try_from_bytes(bytes, shape, dtype) {
220 Ok(data) => data,
221 Err(err) => panic!("{err}"),
222 }
223 }
224
225 #[track_caller]
235 pub fn from_bytes_vec<S: Into<Shape>>(bytes: Vec<u8>, shape: S, dtype: DType) -> Self {
236 Self::from_bytes(Bytes::from_bytes_vec(bytes), shape, dtype)
237 }
238
239 pub fn try_from_bytes<S: Into<Shape>>(
252 bytes: Bytes,
253 shape: S,
254 dtype: DType,
255 ) -> Result<Self, DataError> {
256 let shape = shape.into();
257 let expected = match dtype {
261 DType::QFloat(scheme) => {
262 match crate::tensor::quantization::try_quantized_data_len(&scheme, &shape) {
263 Some(expected) => Some(expected),
264 None => return Err(DataError::InvalidQuantizedLayout { shape, dtype }),
265 }
266 }
267 _ => checked_numel(&shape).and_then(|numel| numel.checked_mul(dtype.size())),
268 };
269
270 if expected != Some(bytes.len()) {
271 return Err(DataError::InvalidByteLength {
272 shape,
273 dtype,
274 len: bytes.len(),
275 });
276 }
277
278 Ok(Self {
279 bytes,
280 shape,
281 dtype,
282 })
283 }
284
285 pub fn try_from_bytes_vec<S: Into<Shape>>(
291 bytes: Vec<u8>,
292 shape: S,
293 dtype: DType,
294 ) -> Result<Self, DataError> {
295 Self::try_from_bytes(Bytes::from_bytes_vec(bytes), shape, dtype)
296 }
297
298 #[cfg(test)]
301 pub(crate) fn from_bytes_unchecked<S: Into<Shape>>(
302 bytes: Bytes,
303 shape: S,
304 dtype: DType,
305 ) -> Self {
306 Self {
307 bytes,
308 shape: shape.into(),
309 dtype,
310 }
311 }
312
313 pub fn shape(&self) -> &Shape {
315 &self.shape
316 }
317
318 pub fn dtype(&self) -> DType {
320 self.dtype
321 }
322
323 pub fn bytes(&self) -> &Bytes {
325 &self.bytes
326 }
327
328 pub fn into_parts(self) -> (Bytes, Shape, DType) {
330 (self.bytes, self.shape, self.dtype)
331 }
332
333 #[track_caller]
342 pub fn with_bytes_mut<'a, R>(
343 data: impl IntoIterator<Item = &'a mut TensorData>,
344 f: impl FnOnce(Vec<&mut Bytes>) -> R,
345 ) -> R {
346 let mut guard = LengthGuard::new(data.into_iter().collect());
347 let out = f(guard.data.iter_mut().map(|data| &mut data.bytes).collect());
348 let changed = guard.reset_changed();
349 assert!(!changed, "TensorData byte storage length must not change");
350 out
351 }
352
353 fn check_data_len<E: Element>(data: &[E], shape: &Shape) {
355 let expected_data_len = numel(shape);
356 let num_data = data.len();
357 assert_eq!(
358 expected_data_len, num_data,
359 "Shape {shape:?} is invalid for input of size {num_data:?}",
360 );
361 }
362
363 pub fn as_slice<E: Element>(&self) -> Result<&[E], DataError> {
372 if self.matches_target_dtype::<E>() {
373 bytemuck::checked::try_cast_slice(self.bytes.read(Reader::new())?)
374 .map_err(DataError::InvalidRepresentation)
375 } else {
376 Err(DataError::dtype_mismatch_as::<E>(self.dtype))
377 }
378 }
379
380 pub fn as_mut_slice<E: Element>(&mut self) -> Result<&mut [E], DataError> {
389 if self.matches_target_dtype::<E>() {
390 bytemuck::checked::try_cast_slice_mut(self.bytes.write(Writer::new())?)
391 .map_err(DataError::InvalidRepresentation)
392 } else {
393 Err(DataError::dtype_mismatch_as::<E>(self.dtype))
394 }
395 }
396
397 pub(super) fn matches_target_dtype<E: Element>(&self) -> bool {
398 let target_dtype = E::dtype();
399 match self.dtype {
400 DType::Bool(BoolStore::U8) => {
401 matches!(target_dtype, DType::U8 | DType::Bool(BoolStore::U8))
402 }
403 DType::Bool(BoolStore::U32) => {
404 matches!(target_dtype, DType::U32 | DType::Bool(BoolStore::U32))
405 }
406 dtype => dtype == target_dtype,
407 }
408 }
409
410 pub fn rank(&self) -> usize {
412 self.shape.len()
413 }
414
415 pub fn num_elements(&self) -> usize {
417 numel(&self.shape)
418 }
419
420 pub fn random<E: Element, R: Rng, S: Into<Shape>>(
422 shape: S,
423 distribution: Distribution,
424 rng: &mut R,
425 ) -> Self {
426 let shape = shape.into();
427 let num_elements = numel(&shape);
428 let mut data = Vec::with_capacity(num_elements);
429
430 for _ in 0..num_elements {
431 data.push(E::random(distribution, rng));
432 }
433
434 TensorData::new(data, shape)
435 }
436
437 pub fn random_dtype<R: Rng, S: Into<Shape>>(
445 shape: S,
446 distribution: Distribution,
447 rng: &mut R,
448 dtype: DType,
449 ) -> Self {
450 match dtype {
451 DType::F64 => Self::random::<f64, _, _>(shape, distribution, rng),
452 DType::F32 => Self::random::<f32, _, _>(shape, distribution, rng),
453 DType::Flex32 => Self::random::<flex32, _, _>(shape, distribution, rng),
454 DType::F16 => Self::random::<f16, _, _>(shape, distribution, rng),
455 DType::BF16 => Self::random::<bf16, _, _>(shape, distribution, rng),
456 DType::I64 => Self::random::<i64, _, _>(shape, distribution, rng),
457 DType::I32 => Self::random::<i32, _, _>(shape, distribution, rng),
458 DType::I16 => Self::random::<i16, _, _>(shape, distribution, rng),
459 DType::I8 => Self::random::<i8, _, _>(shape, distribution, rng),
460 DType::U64 => Self::random::<u64, _, _>(shape, distribution, rng),
461 DType::U32 => Self::random::<u32, _, _>(shape, distribution, rng),
462 DType::U16 => Self::random::<u16, _, _>(shape, distribution, rng),
463 DType::U8 => Self::random::<u8, _, _>(shape, distribution, rng),
464 DType::Bool(_) => {
465 Self::random::<bool, _, _>(shape, distribution, rng).convert_dtype(dtype)
466 }
467 DType::QFloat(_) => {
468 panic!("Cannot create random tensor data with quantized dtype {dtype:?}")
469 }
470 }
471 }
472
473 pub fn zeros<E: Element, S: Into<Shape>>(shape: S) -> TensorData {
475 Self::full(shape, 0.elem::<E>())
476 }
477
478 pub fn zeros_dtype<S: Into<Shape>>(shape: S, dtype: DType) -> Self {
484 Self::full_dtype(shape, 0, dtype)
485 }
486
487 pub fn ones<E: Element, S: Into<Shape>>(shape: S) -> TensorData {
489 Self::full(shape, 1.elem::<E>())
490 }
491
492 pub fn ones_dtype<S: Into<Shape>>(shape: S, dtype: DType) -> Self {
498 Self::full_dtype(shape, 1, dtype)
499 }
500
501 pub fn full<E: Element, S: Into<Shape>>(shape: S, fill_value: E) -> TensorData {
503 let shape = shape.into();
504 let num_elements = numel(&shape);
505 let mut data = Vec::<E>::with_capacity(num_elements);
506 for _ in 0..num_elements {
507 data.push(fill_value)
508 }
509
510 TensorData::new(data, shape)
511 }
512
513 pub fn full_dtype<E: Into<Scalar>, S: Into<Shape>>(
519 shape: S,
520 fill_value: E,
521 dtype: DType,
522 ) -> TensorData {
523 let fill_value = fill_value.into();
524 match dtype {
525 DType::F64 => Self::full::<f64, _>(shape, fill_value.elem()),
526 DType::F32 => Self::full::<f32, _>(shape, fill_value.elem()),
527 DType::Flex32 => Self::full::<flex32, _>(shape, fill_value.elem()),
528 DType::F16 => Self::full::<f16, _>(shape, fill_value.elem()),
529 DType::BF16 => Self::full::<bf16, _>(shape, fill_value.elem()),
530 DType::I64 => Self::full::<i64, _>(shape, fill_value.elem()),
531 DType::I32 => Self::full::<i32, _>(shape, fill_value.elem()),
532 DType::I16 => Self::full::<i16, _>(shape, fill_value.elem()),
533 DType::I8 => Self::full::<i8, _>(shape, fill_value.elem()),
534 DType::U64 => Self::full::<u64, _>(shape, fill_value.elem()),
535 DType::U32 => Self::full::<u32, _>(shape, fill_value.elem()),
536 DType::U16 => Self::full::<u16, _>(shape, fill_value.elem()),
537 DType::U8 => Self::full::<u8, _>(shape, fill_value.elem()),
538 DType::Bool(BoolStore::Native) => Self::full::<bool, _>(shape, fill_value.elem()),
539 DType::Bool(BoolStore::U8) => {
540 Self::full::<u8, _>(shape, fill_value.elem()).into_bool_u8()
541 }
542 DType::Bool(BoolStore::U32) => {
543 Self::full::<u32, _>(shape, fill_value.elem()).into_bool_u32()
544 }
545 DType::QFloat(_) => {
546 panic!("Cannot create full tensor data with quantized dtype {dtype:?}")
547 }
548 }
549 }
550
551 pub(super) fn into_bool_u8(mut self) -> Self {
553 self.dtype = DType::Bool(BoolStore::U8);
554 self
555 }
556
557 pub(super) fn into_bool_u32(mut self) -> Self {
559 self.dtype = DType::Bool(BoolStore::U32);
560 self
561 }
562
563 pub fn as_bytes(&self) -> &[u8] {
565 &self.bytes
566 }
567
568 pub fn into_bytes(self) -> Bytes {
570 self.bytes
571 }
572}
573
574struct LengthGuard<'a> {
577 data: Vec<&'a mut TensorData>,
578 lens: Vec<usize>,
579}
580
581impl<'a> LengthGuard<'a> {
582 fn new(data: Vec<&'a mut TensorData>) -> Self {
583 let lens = data.iter().map(|data| data.bytes.len()).collect();
584 Self { data, lens }
585 }
586
587 fn reset_changed(&mut self) -> bool {
589 let mut changed = false;
590 for (data, len) in self.data.iter_mut().zip(&self.lens) {
591 if data.bytes.len() != *len {
592 **data = TensorData::new(Vec::<u8>::new(), [0]);
593 changed = true;
594 }
595 }
596 changed
597 }
598}
599
600impl Drop for LengthGuard<'_> {
601 fn drop(&mut self) {
602 self.reset_changed();
603 }
604}
605
606fn checked_numel(shape: &[usize]) -> Option<usize> {
608 shape
609 .iter()
610 .try_fold(1usize, |numel, dim| numel.checked_mul(*dim))
611}
612
613fn numel(shape: &[usize]) -> usize {
618 match checked_numel(shape) {
619 Some(numel) => numel,
620 None => panic!("Shape {shape:?} has more elements than fit in usize"),
621 }
622}
623
624impl<E: Element, const A: usize> From<[E; A]> for TensorData {
625 fn from(elems: [E; A]) -> Self {
626 TensorData::new(elems.to_vec(), [A])
627 }
628}
629
630impl<const A: usize> From<[usize; A]> for TensorData {
631 fn from(elems: [usize; A]) -> Self {
632 TensorData::new(elems.iter().map(|&e| e as i64).collect(), [A])
633 }
634}
635
636impl From<&[usize]> for TensorData {
637 fn from(elems: &[usize]) -> Self {
638 let mut data = Vec::with_capacity(elems.len());
639 for elem in elems.iter() {
640 data.push(*elem as i64);
641 }
642
643 TensorData::new(data, [elems.len()])
644 }
645}
646
647impl<E: Element> From<&[E]> for TensorData {
648 fn from(elems: &[E]) -> Self {
649 let mut data = Vec::with_capacity(elems.len());
650 for elem in elems.iter() {
651 data.push(*elem);
652 }
653
654 TensorData::new(data, [elems.len()])
655 }
656}
657
658impl<E: Element, const A: usize, const B: usize> From<[[E; B]; A]> for TensorData {
659 fn from(elems: [[E; B]; A]) -> Self {
660 let mut data = Vec::with_capacity(A * B);
661 for elem in elems.into_iter().take(A) {
662 for elem in elem.into_iter().take(B) {
663 data.push(elem);
664 }
665 }
666
667 TensorData::new(data, [A, B])
668 }
669}
670
671impl<E: Element, const A: usize, const B: usize, const C: usize> From<[[[E; C]; B]; A]>
672 for TensorData
673{
674 fn from(elems: [[[E; C]; B]; A]) -> Self {
675 let mut data = Vec::with_capacity(A * B * C);
676
677 for elem in elems.into_iter().take(A) {
678 for elem in elem.into_iter().take(B) {
679 for elem in elem.into_iter().take(C) {
680 data.push(elem);
681 }
682 }
683 }
684
685 TensorData::new(data, [A, B, C])
686 }
687}
688
689impl<E: Element, const A: usize, const B: usize, const C: usize, const D: usize>
690 From<[[[[E; D]; C]; B]; A]> for TensorData
691{
692 fn from(elems: [[[[E; D]; C]; B]; A]) -> Self {
693 let mut data = Vec::with_capacity(A * B * C * D);
694
695 for elem in elems.into_iter().take(A) {
696 for elem in elem.into_iter().take(B) {
697 for elem in elem.into_iter().take(C) {
698 for elem in elem.into_iter().take(D) {
699 data.push(elem);
700 }
701 }
702 }
703 }
704
705 TensorData::new(data, [A, B, C, D])
706 }
707}
708
709impl<Elem: Element, const A: usize, const B: usize, const C: usize, const D: usize, const E: usize>
710 From<[[[[[Elem; E]; D]; C]; B]; A]> for TensorData
711{
712 fn from(elems: [[[[[Elem; E]; D]; C]; B]; A]) -> Self {
713 let mut data = Vec::with_capacity(A * B * C * D * E);
714
715 for elem in elems.into_iter().take(A) {
716 for elem in elem.into_iter().take(B) {
717 for elem in elem.into_iter().take(C) {
718 for elem in elem.into_iter().take(D) {
719 for elem in elem.into_iter().take(E) {
720 data.push(elem);
721 }
722 }
723 }
724 }
725 }
726
727 TensorData::new(data, [A, B, C, D, E])
728 }
729}
730impl core::fmt::Display for TensorData {
731 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
732 let fmt = match self.dtype {
733 DType::F64 => format!("{:?}", self.as_slice::<f64>().unwrap()),
734 DType::F32 | DType::Flex32 => format!("{:?}", self.as_slice::<f32>().unwrap()),
735 DType::F16 => format!("{:?}", self.as_slice::<f16>().unwrap()),
736 DType::BF16 => format!("{:?}", self.as_slice::<bf16>().unwrap()),
737 DType::I64 => format!("{:?}", self.as_slice::<i64>().unwrap()),
738 DType::I32 => format!("{:?}", self.as_slice::<i32>().unwrap()),
739 DType::I16 => format!("{:?}", self.as_slice::<i16>().unwrap()),
740 DType::I8 => format!("{:?}", self.as_slice::<i8>().unwrap()),
741 DType::U64 => format!("{:?}", self.as_slice::<u64>().unwrap()),
742 DType::U32 => format!("{:?}", self.as_slice::<u32>().unwrap()),
743 DType::U16 => format!("{:?}", self.as_slice::<u16>().unwrap()),
744 DType::U8 => format!("{:?}", self.as_slice::<u8>().unwrap()),
745 DType::Bool(BoolStore::Native) => format!("{:?}", self.as_slice::<bool>().unwrap()),
746 DType::Bool(BoolStore::U8) => format!("{:?}", self.as_slice::<u8>().unwrap()),
747 DType::Bool(BoolStore::U32) => format!("{:?}", self.as_slice::<u32>().unwrap()),
748 DType::QFloat(scheme) => match scheme {
749 QuantScheme {
750 mode: QuantMode::Symmetric,
751 value:
752 QuantValue::Q8F
753 | QuantValue::Q8S
754 | QuantValue::Q4F
756 | QuantValue::Q4S
757 | QuantValue::Q2F
758 | QuantValue::Q2S,
759 ..
760 } => {
761 format!("{:?} {scheme:?}", self.iter::<i8>().collect::<Vec<_>>())
762 },
763 QuantScheme {
764 mode: QuantMode::Symmetric,
765 value:
766 QuantValue::E4M3 | QuantValue::E5M2 | QuantValue::E2M1,
767 ..
768 } => {
769 format!("<float-quantized> {scheme:?}")
770 }
771 QuantScheme {
772 mode: QuantMode::Lookup,
773 ..
774 } => {
775 format!("<lookup-quantized> {scheme:?}")
776 }
777 },
778 };
779 f.write_str(fmt.as_str())
780 }
781}
782
783#[cfg(test)]
784mod tests {
785 use super::*;
786 use crate::*;
787 use ::rand::{
788 SeedableRng,
789 rngs::{StdRng, SysRng},
790 };
791 use alloc::string::ToString;
792 use alloc::vec;
793 use core::mem::{MaybeUninit, align_of, size_of};
794
795 #[test]
796 #[should_panic(expected = "Cannot create full tensor data with quantized dtype")]
797 fn full_dtype_rejects_quantized() {
798 TensorData::full_dtype([2, 3], 0, DType::QFloat(Default::default()));
799 }
800
801 #[test]
802 #[should_panic(expected = "Cannot create random tensor data with quantized dtype")]
803 fn random_dtype_rejects_quantized() {
804 TensorData::random_dtype(
805 [2, 3],
806 Distribution::Default,
807 &mut StdRng::seed_from_u64(42),
808 DType::QFloat(Default::default()),
809 );
810 }
811
812 #[test]
813 fn should_have_rank() {
814 let shape = [3, 5, 6];
815 let data = TensorData::random::<f32, _, _>(
816 shape,
817 Distribution::Default,
818 &mut StdRng::try_from_rng(&mut SysRng).unwrap(),
819 );
820
821 assert_eq!(data.rank(), 3);
822 }
823
824 #[test]
825 fn into_vec_should_yield_same_value_as_iter() {
826 let shape = [3, 5, 6];
827 let data = TensorData::random::<f32, _, _>(
828 shape,
829 Distribution::Default,
830 &mut StdRng::try_from_rng(&mut SysRng).unwrap(),
831 );
832
833 let expected = data.iter::<f32>().collect::<Vec<f32>>();
834 let actual = data.try_into_vec::<f32>().unwrap();
835
836 assert_eq!(expected, actual);
837 }
838
839 #[test]
840 #[should_panic]
841 fn into_vec_should_assert_wrong_dtype() {
842 let shape = [3, 5, 6];
843 let data = TensorData::random::<f32, _, _>(
844 shape,
845 Distribution::Default,
846 &mut StdRng::try_from_rng(&mut SysRng).unwrap(),
847 );
848
849 data.try_into_vec::<i32>().unwrap();
850 }
851
852 #[test]
853 fn should_have_right_num_elements() {
854 let shape = [3, 5, 6];
855 let num_elements: usize = shape.iter().product();
856 let data = TensorData::random::<f32, _, _>(
857 shape,
858 Distribution::Default,
859 &mut StdRng::try_from_rng(&mut SysRng).unwrap(),
860 );
861
862 assert_eq!(num_elements, data.bytes.len() / 4); assert_eq!(num_elements, data.as_slice::<f32>().unwrap().len());
864 }
865
866 #[test]
867 fn should_have_right_shape() {
868 let data = TensorData::from([[3.0, 5.0, 6.0]]);
869 assert_eq!(data.shape, shape![1, 3]);
870
871 let data = TensorData::from([[4.0, 5.0, 8.0], [3.0, 5.0, 6.0]]);
872 assert_eq!(data.shape, shape![2, 3]);
873
874 let data = TensorData::from([3.0, 5.0, 6.0]);
875 assert_eq!(data.shape, shape![3]);
876 }
877
878 #[test]
879 fn should_convert_bytes_correctly() {
880 let mut vector: Vec<f32> = Vec::with_capacity(5);
881 vector.push(2.0);
882 vector.push(3.0);
883 let data1 = TensorData::new(vector, vec![2]);
884
885 let factor = size_of::<f32>() / size_of::<u8>();
886 assert_eq!(data1.bytes.len(), 2 * factor);
887 assert_eq!(data1.bytes.capacity(), 5 * factor);
888 }
889
890 #[test]
891 fn should_convert_bytes_correctly_inplace() {
892 fn test_precision<E: Element>() {
893 let data = TensorData::new((0..32).collect(), [32]);
894 let self1 = data.clone().convert::<E>();
895 for (i, val) in self1.try_into_vec::<E>().unwrap().into_iter().enumerate() {
896 assert_eq!(i as u32, val.elem::<u32>())
897 }
898 }
899 test_precision::<f32>();
900 test_precision::<f16>();
901 test_precision::<i64>();
902 test_precision::<i32>();
903 }
904
905 #[test]
906 fn should_preserve_flex32_dtype_when_casting_from_f32() {
907 let data = TensorData::from([-1.5f32, 0.0, 2.25]);
908 let expected = TensorData::from([-1.5, 0.0, 2.25].map(flex32::from_f32));
909
910 let actual = data.clone().try_cast(DType::Flex32).unwrap();
911 assert_eq!(actual, expected);
912 assert_eq!(data.try_cast_as::<flex32>().unwrap(), expected);
913 assert_eq!(
914 actual.try_cast(DType::F32).unwrap(),
915 TensorData::from([-1.5f32, 0.0, 2.25])
916 );
917 }
918
919 #[test]
920 fn should_preserve_flex32_dtype_when_casting_from_f64() {
921 let data = TensorData::from([-1.5f64, 0.0, 2.25]);
922 let expected = TensorData::from([-1.5, 0.0, 2.25].map(flex32::from_f32));
923
924 let actual = data.clone().try_cast(DType::Flex32).unwrap();
925 assert_eq!(actual, expected);
926 assert_eq!(data.try_cast_as::<flex32>().unwrap(), expected);
927 assert_eq!(
928 actual.try_cast(DType::F32).unwrap(),
929 TensorData::from([-1.5f32, 0.0, 2.25])
930 );
931 }
932
933 #[test]
934 fn should_preserve_flex32_dtype_when_constructing_full_data() {
935 let actual = TensorData::full_dtype([2, 2], 1.5f32, DType::Flex32);
936 let expected = TensorData::full::<flex32, _>([2, 2], 1.5f32.elem());
937
938 assert_eq!(actual, expected);
939 assert_eq!(actual.dtype(), DType::Flex32);
940 }
941
942 #[test]
943 fn should_convert_negative_values_to_bool_store() {
944 for store in [BoolStore::U8, BoolStore::U32, BoolStore::Native] {
945 let data = TensorData::from([-1i32, 0, 1, -12]).convert_dtype(DType::Bool(store));
946 assert_eq!(data.dtype, DType::Bool(store));
947 assert_eq!(
948 data.iter::<bool>().collect::<Vec<_>>(),
949 [true, false, true, true]
950 );
951
952 let data = TensorData::from([-1.5f32, 0.0, 0.5]).convert_dtype(DType::Bool(store));
953 assert_eq!(data.iter::<bool>().collect::<Vec<_>>(), [true, false, true]);
954 }
955 }
956
957 fn check_dtype_constructors<E: Element + PartialEq, S: Element>(dtype: DType) {
958 let distribution = Distribution::Uniform(0.0, 8.0);
959 let random =
960 TensorData::random_dtype([2, 3], distribution, &mut StdRng::seed_from_u64(42), dtype);
961 let expected =
962 TensorData::random::<S, _, _>([2, 3], distribution, &mut StdRng::seed_from_u64(42));
963 for (data, values) in [
964 (
965 TensorData::zeros_dtype([2, 3], dtype),
966 vec![0.elem::<E>(); 6],
967 ),
968 (
969 TensorData::ones_dtype([2, 3], dtype),
970 vec![1.elem::<E>(); 6],
971 ),
972 (random, expected.iter::<E>().collect()),
973 ] {
974 assert_eq!(data.dtype(), dtype);
975 assert_eq!(data.shape(), &Shape::new([2, 3]));
976 assert_eq!(data.try_into_vec::<E>().unwrap(), values);
977 }
978 }
979
980 macro_rules! test_dtypes {
981 ($test_name:ident, $($dtype:ty),*) => {
982 $(
983 paste::paste! {
984 #[test]
985 fn [<$test_name _ $dtype:snake>]() {
986 check_dtype_constructors::<$dtype, $dtype>(<$dtype>::dtype());
987 let full_dtype = TensorData::full_dtype([2, 16], 4, <$dtype>::dtype());
988 let full = TensorData::full::<$dtype, _>([2, 16], 4.elem());
989 assert_eq!(full_dtype, full);
990 }
991 }
992 )*
993 };
994}
995
996 test_dtypes!(
997 should_create_with_dtype,
998 bool,
999 i8,
1000 i16,
1001 i32,
1002 i64,
1003 u8,
1004 u16,
1005 u32,
1006 u64,
1007 f16,
1008 bf16,
1009 f32,
1010 f64,
1011 flex32
1012 );
1013
1014 #[test]
1015 fn should_create_with_dtype_bool_u8() {
1016 check_dtype_constructors::<u8, bool>(DType::Bool(BoolStore::U8));
1017 }
1018
1019 #[test]
1020 fn should_create_with_dtype_bool_u32() {
1021 check_dtype_constructors::<u32, bool>(DType::Bool(BoolStore::U32));
1022 }
1023
1024 #[test]
1025 fn should_serialize_deserialize_tensor_data() {
1026 let data = TensorData::new(vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0], [2, 3]);
1027 assert_eq!(
1028 data.as_bytes(),
1029 [
1030 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 128, 64, 0, 0, 160, 64, 0, 0, 192,
1031 64
1032 ]
1033 );
1034 let serialized = serde_json::to_string(&data).unwrap();
1035 let deserialized: TensorData = serde_json::from_str(&serialized).unwrap();
1036 assert_eq!(data, deserialized);
1037 }
1038
1039 #[test]
1040 fn should_deserialize_tensor_data_with_shape_inner() {
1041 let serialized = r#"{
1043 "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],
1044 "shape": [2, 3],
1045 "dtype": "F32"
1046 }"#;
1047
1048 let data: TensorData = serde_json::from_str(serialized).unwrap();
1049 assert_eq!(data.shape, shape![2, 3]);
1050 assert_eq!(
1051 data.as_slice::<f32>().unwrap(),
1052 &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
1053 );
1054 }
1055
1056 #[test]
1057 fn should_not_deserialize_tensor_data_with_shape_larger_than_bytes() {
1058 let serialized = r#"{"bytes": [0, 0, 128, 63], "shape": [1000], "dtype": "F32"}"#;
1061
1062 let err = serde_json::from_str::<TensorData>(serialized).unwrap_err();
1063 assert!(
1064 err.to_string().contains("is invalid for input of size"),
1065 "unexpected error: {err}"
1066 );
1067 }
1068
1069 #[test]
1070 fn should_not_deserialize_tensor_data_with_overflowing_shape() {
1071 let serialized = r#"{"bytes": [0, 0, 128, 63, 0, 0, 0, 64], "shape": [9223372036854775809, 2], "dtype": "F32"}"#;
1074
1075 let err = serde_json::from_str::<TensorData>(serialized).unwrap_err();
1076 assert!(
1077 err.to_string().contains("is invalid for input of size"),
1078 "unexpected error: {err}"
1079 );
1080 }
1081
1082 #[test]
1083 fn should_serialize_shape_as_flat_array() {
1084 let data = TensorData::new(vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0], [2, 3]);
1087 let serialized = serde_json::to_string(&data).unwrap();
1088 let json: serde_json::Value = serde_json::from_str(&serialized).unwrap();
1089 assert_eq!(json["shape"], serde_json::json!([2, 3]));
1090 }
1091
1092 #[test]
1093 fn test_tensor_data_try_view_dtype_mismatch() {
1094 let data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
1095 let dtype = data.dtype;
1096
1097 assert_eq!(
1098 data.try_view::<i32>().unwrap_err(),
1099 DataError::DTypeMismatch {
1100 expected: <i32 as Element>::dtype(),
1101 actual: dtype,
1102 }
1103 );
1104 }
1105
1106 #[test]
1107 #[should_panic(expected = "Expected data type")]
1108 fn test_tensor_data_expect_view_dtype_mismatch() {
1109 let data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
1110 let _view = data.view::<i32>();
1111 }
1112
1113 #[test]
1114 fn test_tensor_data_try_mut_view_dtype_mismatch() {
1115 let mut data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
1116
1117 let result = data.try_mut_view::<i32>();
1118 assert_eq!(
1119 result.unwrap_err(),
1120 DataError::DTypeMismatch {
1121 actual: data.dtype,
1122 expected: <i32 as Element>::dtype(),
1123 }
1124 );
1125 }
1126
1127 #[test]
1128 fn try_view_validates_storage() {
1129 let invalid_representation =
1130 TensorData::from_bytes_unchecked(Bytes::from_bytes_vec(vec![0; 3]), [1], DType::F32);
1131 assert!(matches!(
1132 invalid_representation.try_view::<f32>(),
1133 Err(DataError::InvalidRepresentation(_))
1134 ));
1135
1136 let invalid_count =
1137 TensorData::from_bytes_unchecked(Bytes::from_bytes_vec(vec![0; 8]), [1], DType::F32);
1138 assert!(matches!(
1139 invalid_count.try_view::<f32>(),
1140 Err(DataError::ElementCountMismatch {
1141 expected: 1,
1142 actual: 2
1143 })
1144 ));
1145
1146 let invalid_bool = TensorData::from_bytes_vec(vec![2], [1], DType::Bool(BoolStore::Native));
1147 assert!(matches!(
1148 invalid_bool.try_view::<bool>(),
1149 Err(DataError::InvalidRepresentation(_))
1150 ));
1151 }
1152
1153 #[test]
1154 fn try_from_bytes_rejects_invalid_length() {
1155 let err = TensorData::try_from_bytes_vec(vec![0; 3], [1], DType::F32).unwrap_err();
1156 assert_eq!(
1157 err,
1158 DataError::InvalidByteLength {
1159 shape: Shape::from([1]),
1160 dtype: DType::F32,
1161 len: 3,
1162 }
1163 );
1164
1165 assert!(TensorData::try_from_bytes_vec(vec![0; 8], [1], DType::F32).is_err());
1166 assert!(TensorData::try_from_bytes_vec(vec![], [1], DType::F32).is_err());
1167 assert!(TensorData::try_from_bytes_vec(vec![], [0usize; 0], DType::F32).is_err());
1168 assert!(
1170 TensorData::try_from_bytes_vec(vec![0; 8], [usize::MAX / 2 + 2, 2], DType::F32)
1171 .is_err()
1172 );
1173 }
1174
1175 #[test]
1176 #[should_panic(expected = "more elements than fit in usize")]
1177 fn new_rejects_overflowing_shape() {
1178 let _ = TensorData::new(vec![0.0f32; 2], [usize::MAX / 2 + 2, 2]);
1180 }
1181
1182 #[test]
1183 #[should_panic(expected = "more elements than fit in usize")]
1184 fn zeros_rejects_overflowing_shape() {
1185 let _ = TensorData::zeros::<f32, _>([usize::MAX / 2 + 2, 2]);
1186 }
1187
1188 #[test]
1189 fn try_from_bytes_accepts_valid_length() {
1190 let data = TensorData::try_from_bytes_vec(vec![0; 8], [2], DType::F32).unwrap();
1191 assert_eq!(data.shape(), &Shape::from([2]));
1192 assert_eq!(data.dtype(), DType::F32);
1193 assert_eq!(data.bytes().len(), 8);
1194
1195 let empty = TensorData::try_from_bytes_vec(vec![], [0, 3], DType::F32).unwrap();
1196 assert_eq!(empty.num_elements(), 0);
1197
1198 let scalar = TensorData::try_from_bytes_vec(vec![0; 4], [0usize; 0], DType::F32).unwrap();
1199 assert_eq!(scalar.rank(), 0);
1200 }
1201
1202 #[test]
1203 #[should_panic(expected = "is invalid for input of size 3 bytes")]
1204 fn from_bytes_panics_on_invalid_length() {
1205 let _ = TensorData::from_bytes_vec(vec![0; 3], [1], DType::F32);
1206 }
1207
1208 #[test]
1209 fn try_from_bytes_accepts_quantized_layout() {
1210 let data = TensorData::quantized(vec![0i8; 4], [4], QuantScheme::default(), &[1.0], None);
1213 let (bytes, shape, dtype) = data.clone().into_parts();
1214 assert_eq!(
1215 TensorData::try_from_bytes(bytes, shape, dtype).unwrap(),
1216 data
1217 );
1218
1219 let serialized = serde_json::to_string(&data).unwrap();
1220 let deserialized: TensorData = serde_json::from_str(&serialized).unwrap();
1221 assert_eq!(deserialized, data);
1222 }
1223
1224 #[test]
1225 fn packed_quantized_scalar_roundtrips() {
1226 for store in [QuantStore::PackedU32(0), QuantStore::PackedNative(0)] {
1227 let scheme = QuantScheme::default()
1228 .with_store(store)
1229 .with_value(QuantValue::E2M1);
1230 let data = TensorData::quantized(vec![1i8], [0usize; 0], scheme, &[0.5], None);
1231
1232 let serialized = serde_json::to_string(&data).unwrap();
1233 let deserialized: TensorData = serde_json::from_str(&serialized).unwrap();
1234 assert_eq!(deserialized, data);
1235 }
1236 }
1237
1238 #[test]
1239 fn try_from_bytes_rejects_invalid_quantized_lengths_and_schemes() {
1240 let scheme = QuantScheme::default();
1241 let valid = TensorData::quantized(vec![0i8; 3], [3], scheme, &[1.0], None);
1242 let (bytes, shape, dtype) = valid.into_parts();
1243 assert!(TensorData::try_from_bytes(bytes.clone(), shape.clone(), dtype).is_ok());
1244
1245 for len in [bytes.len() - 1, bytes.len() + 1] {
1246 assert!(matches!(
1247 TensorData::try_from_bytes_vec(vec![0; len], shape.clone(), dtype),
1248 Err(DataError::InvalidByteLength { .. })
1249 ));
1250 }
1251
1252 let invalid_packed_dim = scheme.with_store(QuantStore::PackedU32(1));
1253 for shape in [Shape::new([1]), Shape::new([0usize; 0])] {
1254 assert!(matches!(
1255 TensorData::try_from_bytes_vec(
1256 vec![0; 4],
1257 shape,
1258 DType::QFloat(invalid_packed_dim)
1259 ),
1260 Err(DataError::InvalidQuantizedLayout { .. })
1261 ));
1262 }
1263
1264 let zero_block = scheme.per_block([0], crate::ScaleDtype::F32);
1265 assert!(matches!(
1266 TensorData::try_from_bytes_vec(vec![0; 4], [1], DType::QFloat(zero_block)),
1267 Err(DataError::InvalidQuantizedLayout { .. })
1268 ));
1269
1270 assert!(matches!(
1271 TensorData::try_from_bytes_vec(vec![], [usize::MAX, 2], DType::QFloat(scheme)),
1272 Err(DataError::InvalidQuantizedLayout { .. })
1273 ));
1274 }
1275
1276 #[test]
1277 fn deserialization_rejects_invalid_quantized_length() {
1278 let invalid = TensorData::from_bytes_unchecked(
1279 Bytes::from_bytes_vec(vec![0; 3]),
1280 [4],
1281 DType::QFloat(QuantScheme::default().with_store(QuantStore::Native)),
1282 );
1283 let serialized = serde_json::to_string(&invalid).unwrap();
1284
1285 assert!(serde_json::from_str::<TensorData>(&serialized).is_err());
1286 }
1287
1288 #[test]
1289 fn try_from_bytes_accepts_packed_quantized_layout_per_row() {
1290 let scheme = QuantScheme::default()
1291 .with_value(QuantValue::Q4S)
1292 .with_store(QuantStore::PackedU32(0));
1293 let data = TensorData::quantized(vec![0i8; 9], [3, 3], scheme, &[1.0], None);
1294 let (bytes, shape, dtype) = data.into_parts();
1295
1296 assert_eq!(bytes.len(), 3 * core::mem::size_of::<u32>() + 4);
1298 assert!(TensorData::try_from_bytes(bytes.clone(), shape.clone(), dtype).is_ok());
1299 for len in [bytes.len() - 1, bytes.len() + 1] {
1300 assert!(matches!(
1301 TensorData::try_from_bytes_vec(vec![0; len], shape.clone(), dtype),
1302 Err(DataError::InvalidByteLength { .. })
1303 ));
1304 }
1305 }
1306
1307 #[test]
1308 fn try_from_bytes_accepts_zero_sized_quantized_tensors() {
1309 let per_tensor =
1310 TensorData::quantized(Vec::<i8>::new(), [0], QuantScheme::default(), &[1.0], None);
1311 let (bytes, shape, dtype) = per_tensor.into_parts();
1312 assert_eq!(bytes.len(), 4);
1313 assert!(TensorData::try_from_bytes(bytes, shape, dtype).is_ok());
1314
1315 let per_block = QuantScheme::default()
1316 .with_store(QuantStore::Native)
1317 .per_block([2], crate::ScaleDtype::F32);
1318 let empty = TensorData::quantized(Vec::<i8>::new(), [0], per_block, &[], None);
1319 let (bytes, shape, dtype) = empty.into_parts();
1320 assert!(bytes.is_empty());
1321 assert!(TensorData::try_from_bytes(bytes, shape, dtype).is_ok());
1322 }
1323
1324 #[test]
1325 fn with_bytes_mut_allows_length_preserving_writes() {
1326 let mut a = TensorData::from([1.0f32, 2.0]);
1327 let mut b = TensorData::from([3i32]);
1328
1329 TensorData::with_bytes_mut([&mut a, &mut b], |bytes| {
1330 assert_eq!(bytes.len(), 2);
1331 for bytes in bytes {
1332 bytes.fill(0);
1333 }
1334 });
1335
1336 assert_eq!(a, TensorData::from([0.0f32, 0.0]));
1337 assert_eq!(b, TensorData::from([0i32]));
1338 }
1339
1340 #[test]
1341 #[should_panic(expected = "length must not change")]
1342 fn with_bytes_mut_rejects_length_change() {
1343 let mut data = TensorData::from([1.0f32]);
1344 TensorData::with_bytes_mut([&mut data], |mut bytes| {
1345 bytes[0].extend_from_byte_slice(&[0; 4]);
1346 });
1347 }
1348
1349 #[cfg(feature = "std")]
1350 #[test]
1351 fn with_bytes_mut_leaves_no_invalid_data_after_unwind() {
1352 use std::panic::{AssertUnwindSafe, catch_unwind};
1353
1354 let empty = TensorData::new(Vec::<u8>::new(), [0]);
1355
1356 let mut changed = TensorData::from([1.0f32]);
1358 let mut unchanged = TensorData::from([2.0f32]);
1359 let result = catch_unwind(AssertUnwindSafe(|| {
1360 TensorData::with_bytes_mut([&mut changed, &mut unchanged], |mut bytes| {
1361 bytes[0].extend_from_byte_slice(&[0; 4]);
1362 })
1363 }));
1364 assert!(result.is_err());
1365 assert_eq!(changed, empty);
1366 assert_eq!(unchanged, TensorData::from([2.0f32]));
1367
1368 let mut data = TensorData::from([1.0f32]);
1370 let result = catch_unwind(AssertUnwindSafe(|| {
1371 TensorData::with_bytes_mut([&mut data], |mut bytes| {
1372 bytes[0].extend_from_byte_slice(&[0; 4]);
1373 panic!("callback failed");
1374 })
1375 }));
1376 assert!(result.is_err());
1377 assert_eq!(data, empty);
1378 }
1379
1380 #[test]
1381 fn try_view_propagates_storage_access_failure() {
1382 use alloc::boxed::Box;
1383
1384 #[derive(Debug)]
1385 struct FailingController;
1386
1387 impl AllocationController for FailingController {
1388 fn alloc_align(&self) -> usize {
1389 align_of::<f32>()
1390 }
1391
1392 fn property(&self) -> AllocationProperty {
1393 AllocationProperty::Other
1394 }
1395
1396 fn capacity(&self) -> usize {
1397 size_of::<f32>()
1398 }
1399
1400 fn memory(&self, _policy: AccessPolicy) -> Result<&[MaybeUninit<u8>], AccessError> {
1401 Err(AccessError::Read("test read failure".into()))
1402 }
1403
1404 unsafe fn memory_mut(
1405 &mut self,
1406 _policy: AccessPolicy,
1407 ) -> Result<&mut [MaybeUninit<u8>], AccessError> {
1408 Err(AccessError::Read("test write failure".into()))
1409 }
1410 }
1411
1412 let bytes =
1414 unsafe { Bytes::from_controller(Box::new(FailingController), size_of::<f32>()) };
1415 let data = TensorData::from_bytes(bytes, [1], DType::F32);
1416
1417 assert!(matches!(
1418 data.try_view::<f32>(),
1419 Err(DataError::StorageAccess(AccessError::Read(reason))) if reason == "test read failure"
1420 ));
1421 }
1422
1423 #[test]
1424 fn try_mut_view_validates_storage() {
1425 let mut invalid_representation =
1426 TensorData::from_bytes_unchecked(Bytes::from_bytes_vec(vec![0; 3]), [1], DType::F32);
1427 assert!(matches!(
1428 invalid_representation.try_mut_view::<f32>(),
1429 Err(DataError::InvalidRepresentation(_))
1430 ));
1431 }
1432
1433 #[test]
1434 fn try_cast_propagates_invalid_storage() {
1435 let invalid_inplace =
1436 TensorData::from_bytes_unchecked(Bytes::from_bytes_vec(vec![0; 3]), [1], DType::F32);
1437 assert!(matches!(
1438 invalid_inplace.try_cast(DType::I32),
1439 Err(DataError::InvalidRepresentation(_))
1440 ));
1441
1442 let invalid_clone =
1443 TensorData::from_bytes_unchecked(Bytes::from_bytes_vec(vec![0; 3]), [1], DType::F32);
1444 assert!(matches!(
1445 invalid_clone.try_cast(DType::F64),
1446 Err(DataError::InvalidRepresentation(_))
1447 ));
1448
1449 let invalid_count =
1450 TensorData::from_bytes_unchecked(Bytes::from_bytes_vec(vec![0; 8]), [1], DType::F32);
1451 assert!(matches!(
1452 invalid_count.try_cast(DType::F64),
1453 Err(DataError::ElementCountMismatch {
1454 expected: 1,
1455 actual: 2
1456 })
1457 ));
1458 }
1459
1460 #[test]
1461 fn try_cast_reports_unsupported_quantized_conversion() {
1462 let scheme = QuantScheme::default();
1463 let target = DType::QFloat(scheme);
1464
1465 assert_eq!(
1466 TensorData::from([1.0f32]).try_cast(target),
1467 Err(DataError::UnsupportedConversion {
1468 from: DType::F32,
1469 to: target,
1470 })
1471 );
1472
1473 let quantized = TensorData::quantized(vec![0i8], [1], scheme, &[1.0], None);
1474 assert_eq!(
1475 quantized.try_cast(DType::F32),
1476 Err(DataError::UnsupportedConversion {
1477 from: target,
1478 to: DType::F32,
1479 })
1480 );
1481 }
1482
1483 #[test]
1484 #[should_panic(expected = "Expected data type")]
1485 fn test_tensor_data_expect_mut_view_dtype_mismatch() {
1486 let mut data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
1487 let _view = data.mut_view::<i32>();
1488 }
1489
1490 #[test]
1491 fn test_tensor_data_index_view() {
1492 let data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
1493 let view = data.view::<f64>();
1494
1495 assert_eq!(view.shape(), &data.shape);
1496
1497 assert_eq!(view[&[0, 0]], 1.0);
1498 assert_eq!(view[&[0, 1]], 2.0);
1499 assert_eq!(view[&[1, 0]], 3.0);
1500 assert_eq!(view[&[1, 1]], 4.0);
1501 }
1502
1503 #[test]
1504 fn test_tensor_data_index_mut_view() {
1505 let mut data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
1506 let shape = data.shape.clone();
1507
1508 let mut view = data.mut_view::<f64>();
1509
1510 assert_eq!(view.shape(), &shape);
1511
1512 assert_eq!(view[&[0, 0]], 1.0);
1513 assert_eq!(view[&[0, 1]], 2.0);
1514 assert_eq!(view[&[1, 0]], 3.0);
1515 assert_eq!(view[&[1, 1]], 4.0);
1516
1517 view[&[0, 0]] = 10.0;
1518 assert_eq!(view[&[0, 0]], 10.0);
1519 }
1520
1521 #[test]
1522 fn test_to_vec_as() {
1523 let data = TensorData::from([0.0f32, 1.0, 2.5]);
1524
1525 assert_eq!(data.try_to_vec_as::<f32>().unwrap(), vec![0.0f32, 1.0, 2.5]);
1527
1528 assert_eq!(data.try_to_vec_as::<f64>().unwrap(), vec![0.0f64, 1.0, 2.5]);
1530
1531 assert_eq!(data.try_to_vec_as::<i32>().unwrap(), vec![0i32, 1, 2]);
1533
1534 data.assert_eq(&TensorData::from([0.0f32, 1.0, 2.5]), true);
1536 }
1537
1538 #[test]
1539 fn test_into_vec_as() {
1540 let data = TensorData::from([0i32, 1, 2, 3]);
1541
1542 assert_eq!(
1544 data.clone().try_into_vec_as::<i32>().unwrap(),
1545 vec![0i32, 1, 2, 3]
1546 );
1547
1548 assert_eq!(
1550 data.clone().try_into_vec_as::<f32>().unwrap(),
1551 vec![0.0f32, 1.0, 2.0, 3.0]
1552 );
1553
1554 assert_eq!(data.try_into_vec_as::<u8>().unwrap(), vec![0u8, 1, 2, 3]);
1556 }
1557}