1use alloc::{string::ToString, sync::Arc, vec, vec::Vec};
4use core::{fmt, marker::PhantomData};
5use serde::{
6 Deserialize, Deserializer, Serialize, Serializer,
7 de::{Error as _, SeqAccess, Visitor},
8 ser::{SerializeSeq, SerializeStruct},
9};
10
11use super::{BinaryOp, DType, DataError, Scalar};
12
13pub const MAX_ELEMENTS: usize = 16 * 1024 * 1024;
15pub const MAX_RANK: usize = 32;
17
18#[derive(Clone, Debug, PartialEq, Eq)]
20pub enum AxisIndex {
21 Index(isize),
23 Slice {
25 start: Option<isize>,
27 stop: Option<isize>,
29 step: isize,
31 },
32 NewAxis,
34 Ellipsis,
36}
37
38#[derive(Clone, Debug)]
46pub struct Tensor {
47 dtype: DType,
48 shape: Arc<[usize]>,
49 strides: Arc<[isize]>,
50 offset: usize,
51 data: Arc<[u8]>,
52}
53
54impl PartialEq for Tensor {
55 fn eq(&self, other: &Self) -> bool {
56 self.dtype == other.dtype
57 && self.shape == other.shape
58 && self.len() == other.len()
59 && (0..self.len())
60 .all(|index| self.scalar_at_linear(index) == other.scalar_at_linear(index))
61 }
62}
63
64impl Eq for Tensor {}
65
66impl Tensor {
67 pub fn from_scalars(
69 dtype: DType,
70 shape: Vec<usize>,
71 values: Vec<Scalar>,
72 ) -> Result<Self, DataError> {
73 let count = checked_count(&shape)?;
74 if count != values.len() {
75 return Err(DataError::ShapeMismatch);
76 }
77 if values.iter().any(|value| value.dtype() != dtype) {
78 return Err(DataError::TypeMismatch);
79 }
80 let bytes = values_to_bytes(dtype, &values)?;
81 Self::from_le_bytes(dtype, shape, bytes)
82 }
83
84 pub fn from_le_bytes(
86 dtype: DType,
87 shape: Vec<usize>,
88 bytes: Vec<u8>,
89 ) -> Result<Self, DataError> {
90 let count = checked_count(&shape)?;
91 let width = dtype.bytes();
92 if width == 0
93 || width > 16
94 || count.checked_mul(width).ok_or(DataError::AllocationLimit)? != bytes.len()
95 {
96 return Err(DataError::InvalidMetadata);
97 }
98 for index in 0..count {
100 let _ = scalar_at_bytes(dtype, &bytes, index)?;
101 }
102 let strides = contiguous_strides(&shape)?;
103 Ok(Self {
104 dtype,
105 shape: Arc::from(shape),
106 strides: Arc::from(strides),
107 offset: 0,
108 data: Arc::from(bytes),
109 })
110 }
111
112 pub fn zeros(dtype: DType, shape: Vec<usize>) -> Result<Self, DataError> {
114 let count = checked_count(&shape)?;
115 let bytes = count
116 .checked_mul(dtype.bytes())
117 .ok_or(DataError::AllocationLimit)?;
118 Self::from_le_bytes(dtype, shape, vec![0; bytes])
119 }
120
121 pub fn dtype(&self) -> DType {
123 self.dtype
124 }
125 pub fn shape(&self) -> &[usize] {
127 &self.shape
128 }
129 pub fn strides(&self) -> &[isize] {
131 &self.strides
132 }
133 pub fn len(&self) -> usize {
135 self.shape.iter().copied().product()
136 }
137 pub fn is_empty(&self) -> bool {
139 self.len() == 0
140 }
141 pub fn byte_len(&self) -> usize {
143 self.len().saturating_mul(self.dtype.bytes())
144 }
145 pub fn storage_byte_len(&self) -> usize {
147 self.data.len()
148 }
149
150 pub fn get(&self, indices: &[isize]) -> Result<Scalar, DataError> {
152 if indices.len() != self.shape.len() {
153 return Err(DataError::Bounds);
154 }
155 let mut position = self.offset as isize;
156 for ((&index, &dimension), &stride) in indices
157 .iter()
158 .zip(self.shape.iter())
159 .zip(self.strides.iter())
160 {
161 let index = normalize_index(index, dimension)?;
162 position = position
163 .checked_add(index.checked_mul(stride).ok_or(DataError::Bounds)?)
164 .ok_or(DataError::Bounds)?;
165 }
166 scalar_at_bytes(
167 self.dtype,
168 &self.data,
169 usize::try_from(position).map_err(|_| DataError::Bounds)?,
170 )
171 }
172
173 pub fn slice(&self, indices: &[AxisIndex]) -> Result<Self, DataError> {
175 let layout = slice_layout(&self.shape, &self.strides, self.offset, indices)?;
176 Ok(Self {
177 dtype: self.dtype,
178 shape: Arc::from(layout.shape),
179 strides: Arc::from(layout.strides),
180 offset: layout.offset,
181 data: self.data.clone(),
182 })
183 }
184
185 pub fn with_slice(&self, indices: &[AxisIndex], replacement: &Self) -> Result<Self, DataError> {
210 self.replace_selection(core::iter::once(indices), replacement)
211 }
212
213 pub fn with_index_path(
224 &self,
225 path: &[Vec<AxisIndex>],
226 replacement: &Self,
227 ) -> Result<Self, DataError> {
228 self.replace_selection(path.iter().map(Vec::as_slice), replacement)
229 }
230
231 fn replace_selection<'a>(
232 &self,
233 path: impl IntoIterator<Item = &'a [AxisIndex]>,
234 replacement: &Self,
235 ) -> Result<Self, DataError> {
236 if self.dtype != replacement.dtype {
237 return Err(DataError::TypeMismatch);
238 }
239 let output_strides = contiguous_strides(&self.shape)?;
240 let mut selection = SliceLayout {
241 shape: self.shape.to_vec(),
242 strides: output_strides.clone(),
243 offset: 0,
244 };
245 for (depth, indices) in path.into_iter().enumerate() {
246 if depth == MAX_RANK {
247 return Err(DataError::InvalidSlice);
248 }
249 selection = slice_layout(
250 &selection.shape,
251 &selection.strides,
252 selection.offset,
253 indices,
254 )?;
255 }
256 if broadcast_shape(&selection.shape, &replacement.shape)? != selection.shape {
257 return Err(DataError::ShapeMismatch);
258 }
259 let prefix = selection.shape.len() - replacement.shape.len();
260 let selected_count = checked_count(&selection.shape)?;
261 let width = self.dtype.bytes();
262 let mut bytes = self.to_le_bytes();
263 for mut flat in 0..selected_count {
264 let mut destination =
265 isize::try_from(selection.offset).map_err(|_| DataError::Bounds)?;
266 let mut source = isize::try_from(replacement.offset).map_err(|_| DataError::Bounds)?;
267 for axis in (0..selection.shape.len()).rev() {
268 let coordinate = flat % selection.shape[axis];
269 flat /= selection.shape[axis];
270 let coordinate = isize::try_from(coordinate).map_err(|_| DataError::Bounds)?;
271 destination = destination
272 .checked_add(
273 coordinate
274 .checked_mul(selection.strides[axis])
275 .ok_or(DataError::Bounds)?,
276 )
277 .ok_or(DataError::Bounds)?;
278 if axis >= prefix && replacement.shape[axis - prefix] != 1 {
279 source = source
280 .checked_add(
281 coordinate
282 .checked_mul(replacement.strides[axis - prefix])
283 .ok_or(DataError::Bounds)?,
284 )
285 .ok_or(DataError::Bounds)?;
286 }
287 }
288 let value = scalar_at_bytes(
289 self.dtype,
290 &replacement.data,
291 usize::try_from(source).map_err(|_| DataError::Bounds)?,
292 )?;
293 let start = usize::try_from(destination)
294 .map_err(|_| DataError::Bounds)?
295 .checked_mul(width)
296 .ok_or(DataError::Bounds)?;
297 let end = start.checked_add(width).ok_or(DataError::Bounds)?;
298 bytes
299 .get_mut(start..end)
300 .ok_or(DataError::Bounds)?
301 .copy_from_slice(&value.bits().to_le_bytes()[..width]);
302 }
303 Ok(Self {
306 dtype: self.dtype,
307 shape: self.shape.clone(),
308 strides: Arc::from(output_strides),
309 offset: 0,
310 data: Arc::from(bytes),
311 })
312 }
313
314 pub fn reshape(&self, shape: Vec<usize>) -> Result<Self, DataError> {
316 if checked_count(&shape)? != self.len() {
317 return Err(DataError::ShapeMismatch);
318 }
319 let data = if self.is_contiguous() {
320 self.data.clone()
321 } else {
322 Arc::from(self.to_le_bytes())
323 };
324 let offset = if self.is_contiguous() { self.offset } else { 0 };
325 let strides = contiguous_strides(&shape)?;
326 Ok(Self {
327 dtype: self.dtype,
328 shape: Arc::from(shape),
329 strides: Arc::from(strides),
330 offset,
331 data,
332 })
333 }
334
335 pub fn transpose(&self, axes: &[usize]) -> Result<Self, DataError> {
337 if axes.len() != self.shape.len() {
338 return Err(DataError::InvalidShape);
339 }
340 let mut seen = vec![false; axes.len()];
341 let mut shape = Vec::with_capacity(axes.len());
342 let mut strides = Vec::with_capacity(axes.len());
343 for &axis in axes {
344 if axis >= axes.len() || seen[axis] {
345 return Err(DataError::InvalidShape);
346 }
347 seen[axis] = true;
348 shape.push(self.shape[axis]);
349 strides.push(self.strides[axis]);
350 }
351 Ok(Self {
352 dtype: self.dtype,
353 shape: Arc::from(shape),
354 strides: Arc::from(strides),
355 offset: self.offset,
356 data: self.data.clone(),
357 })
358 }
359
360 pub fn binary(&self, operation: BinaryOp, rhs: &Self) -> Result<Self, DataError> {
362 if self.dtype != rhs.dtype {
363 return Err(DataError::TypeMismatch);
364 }
365 let shape = broadcast_shape(&self.shape, &rhs.shape)?;
366 let count = checked_count(&shape)?;
367 let mut bytes = Vec::with_capacity(count * self.dtype.bytes());
368 for mut flat in 0..count {
369 let mut indices = vec![0isize; shape.len()];
370 for axis in (0..shape.len()).rev() {
371 indices[axis] = (flat % shape[axis]) as isize;
372 flat /= shape[axis];
373 }
374 let value = self
375 .value_broadcast(&indices, &shape)?
376 .binary(operation, self_or_rhs(rhs, &indices, &shape)?)?;
377 bytes.extend_from_slice(&value.bits().to_le_bytes()[..self.dtype.bytes()]);
378 }
379 Self::from_le_bytes(self.dtype, shape, bytes)
380 }
381
382 pub fn scalar_binary(&self, operation: BinaryOp, rhs: Scalar) -> Result<Self, DataError> {
384 if rhs.dtype() != self.dtype {
385 return Err(DataError::TypeMismatch);
386 }
387 let mut bytes = Vec::with_capacity(self.byte_len());
388 for index in 0..self.len() {
389 let value = self.scalar_at_linear(index).binary(operation, rhs)?;
390 bytes.extend_from_slice(&value.bits().to_le_bytes()[..self.dtype.bytes()]);
391 }
392 Self::from_le_bytes(self.dtype, self.shape.to_vec(), bytes)
393 }
394
395 pub fn convert(&self, dtype: DType) -> Result<Self, DataError> {
397 let mut bytes = Vec::with_capacity(
398 self.len()
399 .checked_mul(dtype.bytes())
400 .ok_or(DataError::AllocationLimit)?,
401 );
402 for index in 0..self.len() {
403 let value = self.scalar_at_linear(index).convert(dtype)?;
404 bytes.extend_from_slice(&value.bits().to_le_bytes()[..dtype.bytes()]);
405 }
406 Self::from_le_bytes(dtype, self.shape.to_vec(), bytes)
407 }
408
409 pub fn sum(&self) -> Result<Scalar, DataError> {
411 let mut total = Scalar::zero(self.dtype);
412 for index in 0..self.len() {
413 total = total.binary(BinaryOp::Add, self.scalar_at_linear(index))?;
414 }
415 Ok(total)
416 }
417
418 pub fn neg(&self) -> Result<Self, DataError> {
420 let mut bytes = Vec::with_capacity(self.byte_len());
421 for index in 0..self.len() {
422 let value = self.scalar_at_linear(index).neg()?;
423 bytes.extend_from_slice(&value.bits().to_le_bytes()[..self.dtype.bytes()]);
424 }
425 Self::from_le_bytes(self.dtype, self.shape.to_vec(), bytes)
426 }
427
428 pub fn matmul(&self, rhs: &Self) -> Result<Self, DataError> {
430 if self.dtype != rhs.dtype {
431 return Err(DataError::TypeMismatch);
432 }
433 if self.shape.len() < 2 || rhs.shape.len() < 2 {
434 return Err(DataError::InvalidShape);
435 }
436 let (m, k) = (
437 self.shape[self.shape.len() - 2],
438 self.shape[self.shape.len() - 1],
439 );
440 if k != rhs.shape[rhs.shape.len() - 2] {
441 return Err(DataError::ShapeMismatch);
442 }
443 let n = rhs.shape[rhs.shape.len() - 1];
444 let batch = broadcast_shape(
445 &self.shape[..self.shape.len() - 2],
446 &rhs.shape[..rhs.shape.len() - 2],
447 )?;
448 let mut shape = batch.clone();
449 shape.push(m);
450 shape.push(n);
451 let count = checked_count(&shape)?;
452 let mut bytes = Vec::with_capacity(count * self.dtype.bytes());
453 for flat in 0..count {
454 let mut out = linear_indices(flat, &shape);
455 let column = out.pop().unwrap_or(0);
456 let row = out.pop().unwrap_or(0);
457 let mut total = Scalar::zero(self.dtype);
458 for inner in 0..k {
459 let left = self.matmul_value(&out, row, inner)?;
460 let right = rhs.matmul_value(&out, inner, column)?;
461 total = total.binary(BinaryOp::Add, left.binary(BinaryOp::Mul, right)?)?;
462 }
463 bytes.extend_from_slice(&total.bits().to_le_bytes()[..self.dtype.bytes()]);
464 }
465 Self::from_le_bytes(self.dtype, shape, bytes)
466 }
467
468 pub fn to_scalars(&self) -> Vec<Scalar> {
470 let mut values = Vec::with_capacity(self.len());
471 for flat in 0..self.len() {
472 values.push(self.scalar_at_linear(flat));
473 }
474 values
475 }
476
477 pub fn to_le_bytes(&self) -> Vec<u8> {
479 let width = self.dtype.bytes();
480 let mut bytes = Vec::with_capacity(self.byte_len());
481 for index in 0..self.len() {
482 bytes.extend_from_slice(&self.scalar_at_linear(index).bits().to_le_bytes()[..width]);
483 }
484 bytes
485 }
486
487 fn is_contiguous(&self) -> bool {
488 contiguous_strides(&self.shape).is_ok_and(|strides| strides == self.strides.as_ref())
489 }
490 fn value_broadcast(
491 &self,
492 output: &[isize],
493 output_shape: &[usize],
494 ) -> Result<Scalar, DataError> {
495 let prefix = output_shape
496 .len()
497 .checked_sub(self.shape.len())
498 .ok_or(DataError::ShapeMismatch)?;
499 let mut indices = Vec::with_capacity(self.shape.len());
500 for (axis, &dimension) in self.shape.iter().enumerate() {
501 indices.push(if dimension == 1 {
502 0
503 } else {
504 output[prefix + axis]
505 });
506 }
507 self.get(&indices)
508 }
509 fn matmul_value(
510 &self,
511 output_batch: &[usize],
512 row: usize,
513 column: usize,
514 ) -> Result<Scalar, DataError> {
515 let batch_rank = self.shape.len() - 2;
516 let output_prefix = output_batch
517 .len()
518 .checked_sub(batch_rank)
519 .ok_or(DataError::ShapeMismatch)?;
520 let mut indices = Vec::with_capacity(self.shape.len());
521 for axis in 0..batch_rank {
522 indices.push(if self.shape[axis] == 1 {
523 0
524 } else {
525 output_batch[output_prefix + axis] as isize
526 });
527 }
528 indices.push(row as isize);
529 indices.push(column as isize);
530 self.get(&indices)
531 }
532 fn scalar_at_linear(&self, mut flat: usize) -> Scalar {
533 let mut position = self.offset as isize;
534 for axis in (0..self.shape.len()).rev() {
535 let dimension = self.shape[axis];
536 let index = flat % dimension;
537 flat /= dimension;
538 position += (index as isize) * self.strides[axis];
539 }
540 scalar_at_bytes(self.dtype, &self.data, position as usize)
541 .expect("Tensor constructors and view operations preserve packed-data bounds")
542 }
543}
544
545struct SliceLayout {
546 shape: Vec<usize>,
547 strides: Vec<isize>,
548 offset: usize,
549}
550
551fn slice_layout(
552 input_shape: &[usize],
553 input_strides: &[isize],
554 initial_offset: usize,
555 indices: &[AxisIndex],
556) -> Result<SliceLayout, DataError> {
557 if indices.len() > 2 * MAX_RANK + 1 {
558 return Err(DataError::InvalidSlice);
559 }
560 let ellipses = indices
561 .iter()
562 .filter(|item| matches!(item, AxisIndex::Ellipsis))
563 .count();
564 if ellipses > 1 {
565 return Err(DataError::InvalidSlice);
566 }
567 let consumed = indices
568 .iter()
569 .filter(|item| !matches!(item, AxisIndex::NewAxis | AxisIndex::Ellipsis))
570 .count();
571 if consumed > input_shape.len() {
572 return Err(DataError::InvalidSlice);
573 }
574 let fill = input_shape.len() - consumed;
575 let mut expanded = Vec::new();
576 for item in indices {
577 if matches!(item, AxisIndex::Ellipsis) {
578 expanded.extend((0..fill).map(|_| AxisIndex::Slice {
579 start: None,
580 stop: None,
581 step: 1,
582 }));
583 } else {
584 expanded.push(item.clone());
585 }
586 }
587 if ellipses == 0 {
588 expanded.extend((0..fill).map(|_| AxisIndex::Slice {
589 start: None,
590 stop: None,
591 step: 1,
592 }));
593 }
594 let mut source_axis = 0usize;
595 let mut offset = initial_offset as isize;
596 let mut shape = Vec::new();
597 let mut strides = Vec::new();
598 for item in expanded {
599 match item {
600 AxisIndex::NewAxis => {
601 shape.push(1);
602 strides.push(0);
603 }
604 AxisIndex::Index(index) => {
605 let index = normalize_index(index, input_shape[source_axis])?;
606 offset = offset
607 .checked_add(
608 index
609 .checked_mul(input_strides[source_axis])
610 .ok_or(DataError::Bounds)?,
611 )
612 .ok_or(DataError::Bounds)?;
613 source_axis += 1;
614 }
615 AxisIndex::Slice { start, stop, step } => {
616 let (start, length) = normalize_slice(start, stop, step, input_shape[source_axis])?;
617 offset = offset
618 .checked_add(
619 start
620 .checked_mul(input_strides[source_axis])
621 .ok_or(DataError::Bounds)?,
622 )
623 .ok_or(DataError::Bounds)?;
624 shape.push(length);
625 strides.push(
626 input_strides[source_axis]
627 .checked_mul(step)
628 .ok_or(DataError::Bounds)?,
629 );
630 source_axis += 1;
631 }
632 AxisIndex::Ellipsis => return Err(DataError::InvalidSlice),
633 }
634 }
635 let count = checked_count(&shape)?;
636 Ok(SliceLayout {
637 shape,
638 strides,
639 offset: if count == 0 {
640 0
641 } else {
642 usize::try_from(offset).map_err(|_| DataError::Bounds)?
643 },
644 })
645}
646
647fn self_or_rhs(tensor: &Tensor, indices: &[isize], shape: &[usize]) -> Result<Scalar, DataError> {
648 tensor.value_broadcast(indices, shape)
649}
650fn checked_count(shape: &[usize]) -> Result<usize, DataError> {
651 if shape.len() > MAX_RANK {
652 return Err(DataError::InvalidShape);
653 }
654 let count = shape.iter().try_fold(1usize, |a, &d| {
655 if d > isize::MAX as usize {
656 return Err(DataError::InvalidShape);
657 }
658 a.checked_mul(d).ok_or(DataError::AllocationLimit)
659 })?;
660 if count > MAX_ELEMENTS {
661 Err(DataError::AllocationLimit)
662 } else {
663 Ok(count)
664 }
665}
666fn contiguous_strides(shape: &[usize]) -> Result<Vec<isize>, DataError> {
667 checked_count(shape)?;
668 let mut result = vec![0; shape.len()];
669 let mut stride = 1usize;
670 for axis in (0..shape.len()).rev() {
671 result[axis] = isize::try_from(stride).map_err(|_| DataError::AllocationLimit)?;
672 stride = stride
673 .checked_mul(shape[axis])
674 .ok_or(DataError::AllocationLimit)?;
675 }
676 Ok(result)
677}
678fn normalize_index(index: isize, len: usize) -> Result<isize, DataError> {
679 let len = isize::try_from(len).map_err(|_| DataError::Bounds)?;
680 let index = if index < 0 {
681 index.checked_add(len).ok_or(DataError::Bounds)?
682 } else {
683 index
684 };
685 if index < 0 || index >= len {
686 Err(DataError::Bounds)
687 } else {
688 Ok(index)
689 }
690}
691fn normalize_slice(
692 start: Option<isize>,
693 stop: Option<isize>,
694 step: isize,
695 len: usize,
696) -> Result<(isize, usize), DataError> {
697 if step == 0 {
698 return Err(DataError::InvalidSlice);
699 }
700 let len = isize::try_from(len).map_err(|_| DataError::InvalidSlice)?;
701 if len == 0 {
702 return Ok((0, 0));
703 }
704 if step > 0 {
705 let mut a = start.unwrap_or(0);
706 let mut b = stop.unwrap_or(len);
707 if a < 0 {
708 a += len;
709 }
710 if b < 0 {
711 b += len;
712 }
713 a = a.clamp(0, len);
714 b = b.clamp(0, len);
715 let n = if b <= a { 0 } else { (b - a - 1) / step + 1 };
716 Ok((a, n as usize))
717 } else {
718 let mut a = start.unwrap_or(len - 1);
719 let mut b = stop.unwrap_or(-1);
720 if start.is_some() && a < 0 {
721 a += len;
722 }
723 if stop.is_some() && b < 0 {
724 b += len;
725 }
726 a = a.clamp(-1, len - 1);
727 b = b.clamp(-1, len - 1);
728 let n = if a <= b {
729 0
730 } else {
731 usize::try_from(a - b - 1).map_err(|_| DataError::InvalidSlice)? / step.unsigned_abs()
732 + 1
733 };
734 Ok((a, n))
735 }
736}
737fn broadcast_shape(left: &[usize], right: &[usize]) -> Result<Vec<usize>, DataError> {
738 let rank = left.len().max(right.len());
739 if rank > MAX_RANK {
740 return Err(DataError::InvalidShape);
741 }
742 let mut shape = vec![1; rank];
743 for out in 0..rank {
744 let a = if out < rank - left.len() {
745 1
746 } else {
747 left[out - (rank - left.len())]
748 };
749 let b = if out < rank - right.len() {
750 1
751 } else {
752 right[out - (rank - right.len())]
753 };
754 shape[out] = if a == b {
755 a
756 } else if a == 1 {
757 b
758 } else if b == 1 {
759 a
760 } else {
761 return Err(DataError::ShapeMismatch);
762 };
763 }
764 checked_count(&shape)?;
765 Ok(shape)
766}
767fn linear_indices(mut flat: usize, shape: &[usize]) -> Vec<usize> {
768 let mut indices = vec![0; shape.len()];
769 for axis in (0..shape.len()).rev() {
770 if shape[axis] != 0 {
771 indices[axis] = flat % shape[axis];
772 flat /= shape[axis];
773 }
774 }
775 indices
776}
777fn scalar_at_bytes(dtype: DType, bytes: &[u8], index: usize) -> Result<Scalar, DataError> {
778 let width = dtype.bytes();
779 let start = index.checked_mul(width).ok_or(DataError::Bounds)?;
780 let slice = bytes
781 .get(start..start.checked_add(width).ok_or(DataError::Bounds)?)
782 .ok_or(DataError::Bounds)?;
783 let mut raw = [0u8; 16];
784 raw[..width].copy_from_slice(slice);
785 Scalar::from_bits(dtype, u128::from_le_bytes(raw))
786}
787fn values_to_bytes(dtype: DType, values: &[Scalar]) -> Result<Vec<u8>, DataError> {
788 let width = dtype.bytes();
789 let mut bytes = Vec::with_capacity(
790 values
791 .len()
792 .checked_mul(width)
793 .ok_or(DataError::AllocationLimit)?,
794 );
795 for value in values {
796 if value.dtype() != dtype {
797 return Err(DataError::TypeMismatch);
798 }
799 bytes.extend_from_slice(&value.bits().to_le_bytes()[..width]);
800 }
801 Ok(bytes)
802}
803
804impl Serialize for Tensor {
805 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
806 let mut state = serializer.serialize_struct("Tensor", 3)?;
809 state.serialize_field("dtype", &self.dtype)?;
810 state.serialize_field("shape", &self.shape.as_ref())?;
811 state.serialize_field("data", &DecimalValues(self))?;
812 state.end()
813 }
814}
815
816struct DecimalValues<'a>(&'a Tensor);
817
818impl Serialize for DecimalValues<'_> {
819 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
820 let mut sequence = serializer.serialize_seq(Some(self.0.len()))?;
821 for index in 0..self.0.len() {
822 sequence.serialize_element(&self.0.scalar_at_linear(index).to_string())?;
823 }
824 sequence.end()
825 }
826}
827
828impl<'de> Deserialize<'de> for Tensor {
829 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
830 #[derive(Deserialize)]
831 #[serde(deny_unknown_fields)]
832 struct Wire {
833 dtype: DType,
834 #[serde(deserialize_with = "deserialize_shape")]
835 shape: Vec<usize>,
836 #[serde(deserialize_with = "deserialize_decimal_data")]
837 data: Vec<alloc::string::String>,
838 }
839 let wire = Wire::deserialize(deserializer)?;
840 let count = checked_count(&wire.shape).map_err(D::Error::custom)?;
841 if wire.data.len() != count {
842 return Err(D::Error::custom(DataError::ShapeMismatch));
843 }
844 let mut values = Vec::with_capacity(count);
845 for text in wire.data {
846 values.push(Scalar::parse(wire.dtype, &text).map_err(D::Error::custom)?);
847 }
848 Tensor::from_scalars(wire.dtype, wire.shape, values).map_err(D::Error::custom)
849 }
850}
851
852fn deserialize_shape<'de, D>(deserializer: D) -> Result<Vec<usize>, D::Error>
853where
854 D: Deserializer<'de>,
855{
856 deserialize_limited_sequence(deserializer, MAX_RANK, PhantomData)
857}
858
859fn deserialize_decimal_data<'de, D>(deserializer: D) -> Result<Vec<alloc::string::String>, D::Error>
860where
861 D: Deserializer<'de>,
862{
863 deserialize_limited_sequence(deserializer, MAX_ELEMENTS, PhantomData)
864}
865
866fn deserialize_limited_sequence<'de, D, T>(
867 deserializer: D,
868 limit: usize,
869 marker: PhantomData<T>,
870) -> Result<Vec<T>, D::Error>
871where
872 D: Deserializer<'de>,
873 T: Deserialize<'de>,
874{
875 struct Limited<T> {
876 limit: usize,
877 marker: PhantomData<T>,
878 }
879 impl<'de, T> Visitor<'de> for Limited<T>
880 where
881 T: Deserialize<'de>,
882 {
883 type Value = Vec<T>;
884
885 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
886 write!(formatter, "an array with at most {} values", self.limit)
887 }
888
889 fn visit_seq<A>(self, mut sequence: A) -> Result<Self::Value, A::Error>
890 where
891 A: SeqAccess<'de>,
892 {
893 let mut values = Vec::new();
894 while let Some(value) = sequence.next_element()? {
895 if values.len() == self.limit {
896 return Err(A::Error::custom(DataError::AllocationLimit));
897 }
898 values.push(value);
899 }
900 Ok(values)
901 }
902 }
903 deserializer.deserialize_seq(Limited { limit, marker })
904}
905
906impl fmt::Display for Tensor {
907 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
908 write!(formatter, "Tensor<{:?}, {:?}>", self.dtype, self.shape)
909 }
910}
911
912#[cfg(test)]
913mod tests {
914 use super::*;
915 #[test]
916 fn negative_slice_reverses() {
917 let t = Tensor::from_scalars(
918 DType::I32,
919 vec![4],
920 vec![
921 Scalar::parse(DType::I32, "1").unwrap(),
922 Scalar::parse(DType::I32, "2").unwrap(),
923 Scalar::parse(DType::I32, "3").unwrap(),
924 Scalar::parse(DType::I32, "4").unwrap(),
925 ],
926 )
927 .unwrap();
928 let r = t
929 .slice(&[AxisIndex::Slice {
930 start: None,
931 stop: None,
932 step: -1,
933 }])
934 .unwrap();
935 assert_eq!(r.get(&[0]).unwrap().to_string(), "4");
936 assert_eq!(r.get(&[3]).unwrap().to_string(), "1");
937 let minimum_step = t
938 .slice(&[AxisIndex::Slice {
939 start: None,
940 stop: None,
941 step: isize::MIN,
942 }])
943 .unwrap();
944 assert_eq!(strings(&minimum_step), ["4"]);
945 }
946 #[test]
947 fn broadcast_adds_trailing_axes() {
948 let a = Tensor::from_scalars(
949 DType::I32,
950 vec![2, 1],
951 vec![
952 Scalar::parse(DType::I32, "1").unwrap(),
953 Scalar::parse(DType::I32, "2").unwrap(),
954 ],
955 )
956 .unwrap();
957 let b = Tensor::from_scalars(
958 DType::I32,
959 vec![3],
960 (3..6)
961 .map(|n| Scalar::parse(DType::I32, &n.to_string()).unwrap())
962 .collect(),
963 )
964 .unwrap();
965 let r = a.binary(BinaryOp::Add, &b).unwrap();
966 assert_eq!(r.shape(), &[2, 3]);
967 assert_eq!(r.get(&[1, 2]).unwrap().to_string(), "7");
968 }
969
970 #[test]
971 fn zero_axis_broadcast_has_no_division_or_elements() {
972 let empty = Tensor::zeros(DType::I8, vec![0, 3]).unwrap();
973 let row = Tensor::zeros(DType::I8, vec![1, 3]).unwrap();
974 let result = empty.binary(BinaryOp::Add, &row).unwrap();
975 assert_eq!(result.shape(), &[0, 3]);
976 assert!(result.is_empty());
977 }
978
979 #[test]
980 fn noncontiguous_negative_slice_materializes_in_logical_order() {
981 let source = ints(DType::I16, &[2, 3], &[1, 2, 3, 4, 5, 6]);
982 let reverse_columns = source
983 .slice(&[
984 AxisIndex::Slice {
985 start: None,
986 stop: None,
987 step: 1,
988 },
989 AxisIndex::Slice {
990 start: None,
991 stop: None,
992 step: -1,
993 },
994 ])
995 .unwrap();
996 let reshaped = reverse_columns.reshape(vec![3, 2]).unwrap();
997 assert_eq!(strings(&reshaped), ["3", "2", "1", "6", "5", "4"]);
998 assert_eq!(
999 reverse_columns,
1000 ints(DType::I16, &[2, 3], &[3, 2, 1, 6, 5, 4])
1001 );
1002 let empty = Tensor::zeros(DType::I16, vec![0]).unwrap();
1003 assert!(
1004 empty
1005 .slice(&[AxisIndex::Slice {
1006 start: None,
1007 stop: None,
1008 step: -1,
1009 }])
1010 .unwrap()
1011 .is_empty()
1012 );
1013 }
1014
1015 #[test]
1016 fn failed_i8_arithmetic_does_not_mutate_shared_view() {
1017 let source = ints(DType::I8, &[2], &[126, 127]);
1018 let view = source
1019 .slice(&[AxisIndex::Slice {
1020 start: Some(1),
1021 stop: None,
1022 step: 1,
1023 }])
1024 .unwrap();
1025 let one = Scalar::parse(DType::I8, "1").unwrap();
1026 assert_eq!(
1027 view.scalar_binary(BinaryOp::Add, one),
1028 Err(DataError::Overflow)
1029 );
1030 assert_eq!(view.get(&[0]).unwrap().to_string(), "127");
1031 assert_eq!(source.get(&[1]).unwrap().to_string(), "127");
1032 }
1033
1034 #[test]
1035 fn reductions_and_matmul_report_checked_overflow() {
1036 let values = ints(DType::I16, &[3], &[1, 2, 3]);
1037 assert_eq!(values.sum().unwrap().to_string(), "6");
1038 let left = ints(DType::I8, &[1, 1], &[127]);
1039 let right = ints(DType::I8, &[1, 1], &[2]);
1040 assert_eq!(left.matmul(&right), Err(DataError::Overflow));
1041 }
1042
1043 #[test]
1044 fn matmul_handles_values_batches_and_empty_inner_axes() {
1045 let left = ints(DType::I16, &[2, 3], &[1, 2, 3, 4, 5, 6]);
1046 let right = ints(DType::I16, &[3, 2], &[7, 8, 9, 10, 11, 12]);
1047 assert_eq!(
1048 strings(&left.matmul(&right).unwrap()),
1049 ["58", "64", "139", "154"]
1050 );
1051
1052 let batched = ints(
1053 DType::I16,
1054 &[2, 2, 3],
1055 &[1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6],
1056 );
1057 let result = batched.matmul(&right).unwrap();
1058 assert_eq!(result.shape(), &[2, 2, 2]);
1059 assert_eq!(
1060 strings(&result),
1061 ["58", "64", "139", "154", "58", "64", "139", "154"]
1062 );
1063
1064 let empty_left = Tensor::zeros(DType::I16, vec![2, 0]).unwrap();
1065 let empty_right = Tensor::zeros(DType::I16, vec![0, 3]).unwrap();
1066 assert_eq!(
1067 strings(&empty_left.matmul(&empty_right).unwrap()),
1068 ["0", "0", "0", "0", "0", "0"]
1069 );
1070 }
1071
1072 #[test]
1073 fn views_retain_storage_and_support_extended_indexing() {
1074 let source = ints(DType::I16, &[2, 3], &[1, 2, 3, 4, 5, 6]);
1075 let transposed = source.transpose(&[1, 0]).unwrap();
1076 let view = transposed
1077 .slice(&[
1078 AxisIndex::NewAxis,
1079 AxisIndex::Ellipsis,
1080 AxisIndex::Index(-1),
1081 ])
1082 .unwrap();
1083 assert_eq!(view.shape(), &[1, 3]);
1084 assert_eq!(view.get(&[-1, -1]).unwrap().to_string(), "6");
1085 assert_eq!(view.storage_byte_len(), source.storage_byte_len());
1086 assert!(view.byte_len() < view.storage_byte_len());
1087 assert_eq!(source.transpose(&[0, 0]), Err(DataError::InvalidShape));
1088 assert_eq!(source.transpose(&[0]), Err(DataError::InvalidShape));
1089 }
1090
1091 #[test]
1092 fn slice_replacement_broadcasts_into_reversed_columns_without_mutation() {
1093 let original = ints(DType::I16, &[2, 3], &[1, 2, 3, 4, 5, 6]);
1094 let alias = original.clone();
1095 let row = ints(DType::I16, &[3], &[10, 20, 30]);
1096 let updated = original
1097 .with_slice(&[AxisIndex::Ellipsis, reverse()], &row)
1098 .unwrap();
1099 assert_eq!(strings(&updated), ["30", "20", "10", "30", "20", "10"]);
1100 assert_eq!(updated.shape(), original.shape());
1101 assert_eq!(original, alias);
1102 assert_eq!(strings(&original), ["1", "2", "3", "4", "5", "6"]);
1103 assert!(!Arc::ptr_eq(&updated.data, &original.data));
1104
1105 let scalar = ints(DType::I16, &[], &[99]);
1106 let indexed = original
1107 .with_slice(&[AxisIndex::Index(-1), AxisIndex::Index(-1)], &scalar)
1108 .unwrap();
1109 assert_eq!(strings(&indexed), ["1", "2", "3", "4", "5", "99"]);
1110 let expanded = original
1111 .with_slice(&[AxisIndex::NewAxis, AxisIndex::Ellipsis], &row)
1112 .unwrap();
1113 assert_eq!(strings(&expanded), ["10", "20", "30", "10", "20", "30"]);
1114 }
1115
1116 #[test]
1117 fn overlapping_and_noncontiguous_replacements_read_original_storage() {
1118 let original = ints(DType::I16, &[5], &[1, 2, 3, 4, 5]);
1119 let replacement = original
1120 .slice(&[AxisIndex::Slice {
1121 start: None,
1122 stop: Some(4),
1123 step: 1,
1124 }])
1125 .unwrap();
1126 let updated = original
1127 .with_slice(
1128 &[AxisIndex::Slice {
1129 start: Some(1),
1130 stop: None,
1131 step: 1,
1132 }],
1133 &replacement,
1134 )
1135 .unwrap();
1136 assert_eq!(strings(&updated), ["1", "1", "2", "3", "4"]);
1137 assert_eq!(strings(&original), ["1", "2", "3", "4", "5"]);
1138 assert_eq!(strings(&replacement), ["1", "2", "3", "4"]);
1139 let reversed = original.slice(&[reverse()]).unwrap();
1140 assert_eq!(
1141 strings(&original.with_slice(&[], &reversed).unwrap()),
1142 ["5", "4", "3", "2", "1"]
1143 );
1144
1145 let matrix = ints(DType::I16, &[2, 3], &[1, 2, 3, 4, 5, 6]);
1146 let transposed = matrix.transpose(&[1, 0]).unwrap();
1147 let row = ints(DType::I16, &[2], &[8, 9]);
1148 let changed = transposed.with_slice(&[AxisIndex::Index(1)], &row).unwrap();
1149 assert_eq!(changed.shape(), &[3, 2]);
1150 assert_eq!(strings(&changed), ["1", "4", "8", "9", "3", "6"]);
1151 assert_eq!(strings(&transposed), ["1", "4", "2", "5", "3", "6"]);
1152 assert_eq!(strings(&matrix), ["1", "2", "3", "4", "5", "6"]);
1153 }
1154
1155 #[test]
1156 fn replacing_a_subview_materializes_only_its_logical_tensor() {
1157 let original = ints(DType::I16, &[2, 4], &[1, 2, 3, 4, 5, 6, 7, 8]);
1158 let view = original
1159 .slice(&[
1160 AxisIndex::Index(1),
1161 AxisIndex::Slice {
1162 start: None,
1163 stop: None,
1164 step: 2,
1165 },
1166 ])
1167 .unwrap();
1168 let updated = view
1169 .with_slice(&[AxisIndex::Index(0)], &ints(DType::I16, &[], &[99]))
1170 .unwrap();
1171 assert_eq!(strings(&updated), ["99", "7"]);
1172 assert_eq!(updated.shape(), &[2]);
1173 assert_eq!(updated.storage_byte_len(), 4);
1174 assert_eq!(view.storage_byte_len(), 16);
1175 assert_eq!(strings(&view), ["5", "7"]);
1176 assert_eq!(original.get(&[1, 0]).unwrap().to_string(), "5");
1177 }
1178
1179 #[test]
1180 fn nested_index_paths_compose_before_replacement() {
1181 let original = ints(DType::I16, &[2, 3], &[1, 2, 3, 4, 5, 6]);
1182 let path = vec![
1183 vec![AxisIndex::Ellipsis, reverse()],
1184 vec![AxisIndex::Index(1)],
1185 vec![AxisIndex::Slice {
1186 start: None,
1187 stop: Some(2),
1188 step: 1,
1189 }],
1190 ];
1191 let replacement = ints(DType::I16, &[2], &[8, 9]);
1192 let updated = original.with_index_path(&path, &replacement).unwrap();
1193 assert_eq!(strings(&updated), ["1", "2", "3", "4", "9", "8"]);
1194 assert_eq!(strings(&original), ["1", "2", "3", "4", "5", "6"]);
1195 let transposed = original.transpose(&[1, 0]).unwrap();
1196 let updated = transposed
1197 .with_index_path(&[vec![reverse()], vec![AxisIndex::Index(0)]], &replacement)
1198 .unwrap();
1199 assert_eq!(strings(&updated), ["1", "4", "2", "5", "8", "9"]);
1200 assert_eq!(
1201 original.with_index_path(&vec![vec![]; MAX_RANK + 1], &replacement),
1202 Err(DataError::InvalidSlice)
1203 );
1204 let scalar = ints(DType::I16, &[], &[7]);
1205 assert_eq!(
1206 strings(&original.with_index_path(&[], &scalar).unwrap()),
1207 ["7", "7", "7", "7", "7", "7"]
1208 );
1209 }
1210
1211 #[test]
1212 fn slice_replacement_checks_empty_shapes_scalars_types_and_bounds() {
1213 let empty = Tensor::zeros(DType::I16, vec![0, 3]).unwrap();
1214 let row = ints(DType::I16, &[3], &[1, 2, 3]);
1215 assert!(empty.with_slice(&[], &row).unwrap().is_empty());
1216 assert!(
1217 empty
1218 .with_slice(&[reverse()], &ints(DType::I16, &[], &[1]))
1219 .unwrap()
1220 .is_empty()
1221 );
1222 assert_eq!(
1223 empty.with_slice(&[], &ints(DType::I16, &[2], &[1, 2])),
1224 Err(DataError::ShapeMismatch)
1225 );
1226 assert_eq!(
1227 empty.with_slice(&[], &ints(DType::I32, &[3], &[1, 2, 3])),
1228 Err(DataError::TypeMismatch)
1229 );
1230 assert_eq!(
1231 empty.with_slice(&[AxisIndex::Index(0)], &row),
1232 Err(DataError::Bounds)
1233 );
1234
1235 let scalar = ints(DType::I16, &[], &[7]);
1236 assert_eq!(
1237 strings(
1238 &scalar
1239 .with_slice(&[], &ints(DType::I16, &[], &[9]))
1240 .unwrap()
1241 ),
1242 ["9"]
1243 );
1244 assert_eq!(
1245 scalar.with_slice(&[], &ints(DType::I16, &[1], &[9])),
1246 Err(DataError::ShapeMismatch)
1247 );
1248 let original = ints(DType::I16, &[3], &[1, 2, 3]);
1249 assert_eq!(
1250 original.with_slice(&[AxisIndex::Ellipsis, AxisIndex::Ellipsis], &scalar),
1251 Err(DataError::InvalidSlice)
1252 );
1253 assert_eq!(
1254 original.with_slice(
1255 &[AxisIndex::Slice {
1256 start: None,
1257 stop: None,
1258 step: 0
1259 }],
1260 &scalar
1261 ),
1262 Err(DataError::InvalidSlice)
1263 );
1264 assert_eq!(
1265 original.with_slice(&[], &ints(DType::I16, &[1, 3], &[1, 2, 3])),
1266 Err(DataError::ShapeMismatch)
1267 );
1268 let minimum_step = original
1269 .with_slice(
1270 &[AxisIndex::Slice {
1271 start: None,
1272 stop: None,
1273 step: isize::MIN,
1274 }],
1275 &scalar,
1276 )
1277 .unwrap();
1278 assert_eq!(strings(&minimum_step), ["1", "2", "7"]);
1279 assert_eq!(strings(&original), ["1", "2", "3"]);
1280 }
1281
1282 fn reverse() -> AxisIndex {
1283 AxisIndex::Slice {
1284 start: None,
1285 stop: None,
1286 step: -1,
1287 }
1288 }
1289
1290 #[test]
1291 fn serde_rejects_malformed_counts_nonfinite_values_and_large_shapes() {
1292 let count = serde_json::from_str::<Tensor>(r#"{"dtype":"i8","shape":[2],"data":["1"]}"#);
1293 assert!(count.is_err());
1294 let nonfinite =
1295 serde_json::from_str::<Tensor>(r#"{"dtype":"f32","shape":[1],"data":["NaN"]}"#);
1296 assert!(nonfinite.is_err());
1297 let large =
1298 serde_json::from_str::<Tensor>(r#"{"dtype":"u8","shape":[16777217],"data":[]}"#);
1299 assert!(large.is_err());
1300 }
1301
1302 #[test]
1303 fn streaming_serde_matches_generated_tensor_wire_shape() {
1304 let tensor = ints(DType::I128, &[2], &[1, i128::MAX]);
1305 let expected = serde_json::to_value(crate::data::wire::Tensor {
1306 dtype: tensor.dtype(),
1307 shape: tensor.shape().to_vec(),
1308 data: strings(&tensor),
1309 })
1310 .unwrap();
1311 assert_eq!(serde_json::to_value(&tensor).unwrap(), expected);
1312 }
1313
1314 fn ints(dtype: DType, shape: &[usize], values: &[i128]) -> Tensor {
1315 Tensor::from_scalars(
1316 dtype,
1317 shape.to_vec(),
1318 values
1319 .iter()
1320 .map(|value| Scalar::parse(dtype, &value.to_string()).unwrap())
1321 .collect(),
1322 )
1323 .unwrap()
1324 }
1325
1326 fn strings(tensor: &Tensor) -> Vec<alloc::string::String> {
1327 tensor
1328 .to_scalars()
1329 .iter()
1330 .map(ToString::to_string)
1331 .collect()
1332 }
1333}