tenferro_tensor/default_scalars.rs
1//! The crate's default scalar set as a dtype-erased host value.
2//!
3//! [`DefaultScalars`] is tenferro's own [`ScalarSet`]: one value holding a
4//! host tensor of any preset dtype. Each member is the canonical
5//! `TypedTensor<T, DynRank, Host>` (views: `TypedTensorView<'a, T, DynRank,
6//! Host>`), so the set adds dtype erasure without a second owner or view
7//! family. `tenferro-tensor-core` keeps the scalar tags and promotion facts.
8
9use num_complex::{Complex32, Complex64};
10use tenferro_tensor_core::{promote_in_set, DType, DynRank};
11
12use crate::{Host, ScalarSet, StridedSliceSpec, TensorScalar, TypedTensor, TypedTensorView};
13
14fn dtype_mismatch(op: &'static str, expected: DType, actual: DType) -> crate::Error {
15 crate::Error::validation(
16 op,
17 tenferro_tensor_core::ValidationError::DTypeMismatch { expected, actual },
18 )
19}
20
21/// Dynamic host tensor over the crate's preset scalar set.
22///
23/// The payload is a private inline value: a host tensor is one move and a copy
24/// allocates nothing, and the preset variants are not part of the public
25/// surface. Construct through [`DefaultScalars::from_vec_col_major`] and read
26/// through [`DefaultScalars::as_slice`], [`DefaultScalars::as_mut_slice`], or
27/// [`DefaultScalars::into_vec_col_major`].
28///
29/// # Examples
30///
31/// ```rust
32/// use tenferro_tensor::{DefaultScalars, DType};
33/// use tenferro_tensor::ScalarSet;
34///
35/// let value = DefaultScalars::from_vec_col_major(vec![1], vec![7_i32])?;
36/// assert_eq!(value.tag(), DType::I32);
37/// assert_eq!(value.as_slice::<i32>()?, &[7]);
38/// # Ok::<(), tenferro_tensor::Error>(())
39/// ```
40#[derive(Clone, Debug)]
41pub struct DefaultScalars {
42 value: DefaultScalarsValue,
43}
44
45/// Private payload of [`DefaultScalars`].
46///
47/// The variants are not part of the public surface: construct through
48/// [`DefaultScalars::from_vec_col_major`] and read through
49/// [`DefaultScalars::as_slice`].
50#[derive(Clone, Debug)]
51pub(crate) enum DefaultScalarsValue {
52 F32(TypedTensor<f32, DynRank, Host>),
53 F64(TypedTensor<f64, DynRank, Host>),
54 I32(TypedTensor<i32, DynRank, Host>),
55 I64(TypedTensor<i64, DynRank, Host>),
56 Bool(TypedTensor<bool, DynRank, Host>),
57 C32(TypedTensor<Complex32, DynRank, Host>),
58 C64(TypedTensor<Complex64, DynRank, Host>),
59}
60
61impl ScalarSet for DefaultScalarsValue {
62 type Tag = DType;
63
64 const TAGS: &'static [Self::Tag] = DType::TAGS;
65
66 fn tag(&self) -> Self::Tag {
67 match self {
68 Self::F32(_) => DType::F32,
69 Self::F64(_) => DType::F64,
70 Self::I32(_) => DType::I32,
71 Self::I64(_) => DType::I64,
72 Self::Bool(_) => DType::Bool,
73 Self::C32(_) => DType::C32,
74 Self::C64(_) => DType::C64,
75 }
76 }
77
78 fn promote(lhs: Self::Tag, rhs: Self::Tag) -> Self::Tag {
79 // An externally defined member promotes to itself, because tenferro
80 // declares no facts that relate it to one of its own members.
81 if matches!(lhs, DType::External(_)) {
82 return lhs;
83 }
84 if matches!(rhs, DType::External(_)) {
85 return rhs;
86 }
87 promote_in_set(DType::TAGS, DType::SPECS, lhs, rhs)
88 }
89}
90
91impl DefaultScalarsValue {
92 /// Return the tensor dtype tag.
93 ///
94 /// # Examples
95 ///
96 /// ```rust
97 /// use tenferro_tensor::{DefaultScalars, DType};
98 ///
99 /// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![false])?;
100 /// assert_eq!(tensor.dtype(), DType::Bool);
101 /// # Ok::<(), tenferro_tensor::Error>(())
102 /// ```
103 pub fn dtype(&self) -> DType {
104 match self {
105 Self::F32(_) => DType::F32,
106 Self::F64(_) => DType::F64,
107 Self::I32(_) => DType::I32,
108 Self::I64(_) => DType::I64,
109 Self::Bool(_) => DType::Bool,
110 Self::C32(_) => DType::C32,
111 Self::C64(_) => DType::C64,
112 }
113 }
114
115 /// Borrow the tensor shape.
116 ///
117 /// # Examples
118 ///
119 /// ```rust
120 /// use tenferro_tensor::DefaultScalars;
121 ///
122 /// let tensor = DefaultScalars::from_vec_col_major(vec![2], vec![1_i32, 2])?;
123 /// assert_eq!(tensor.shape(), &[2]);
124 /// # Ok::<(), tenferro_tensor::Error>(())
125 /// ```
126 pub fn shape(&self) -> &[usize] {
127 match self {
128 Self::F32(t) => t.shape(),
129 Self::F64(t) => t.shape(),
130 Self::I32(t) => t.shape(),
131 Self::I64(t) => t.shape(),
132 Self::Bool(t) => t.shape(),
133 Self::C32(t) => t.shape(),
134 Self::C64(t) => t.shape(),
135 }
136 }
137
138 /// Return the tensor rank.
139 ///
140 /// # Examples
141 ///
142 /// ```rust
143 /// use tenferro_tensor::DefaultScalars;
144 ///
145 /// let tensor = DefaultScalars::from_vec_col_major(vec![1, 1], vec![1_i64])?;
146 /// assert_eq!(tensor.rank(), 2);
147 /// # Ok::<(), tenferro_tensor::Error>(())
148 /// ```
149 pub fn rank(&self) -> usize {
150 self.shape().len()
151 }
152
153 /// Return whether the tensor has zero elements.
154 ///
155 /// # Examples
156 ///
157 /// ```rust
158 /// use tenferro_tensor::DefaultScalars;
159 ///
160 /// let tensor = DefaultScalars::from_vec_col_major(vec![0], Vec::<f64>::new())?;
161 /// assert!(tensor.is_empty());
162 /// # Ok::<(), tenferro_tensor::Error>(())
163 /// ```
164 pub fn is_empty(&self) -> bool {
165 match self {
166 Self::F32(t) => t.shape().contains(&0),
167 Self::F64(t) => t.shape().contains(&0),
168 Self::I32(t) => t.shape().contains(&0),
169 Self::I64(t) => t.shape().contains(&0),
170 Self::Bool(t) => t.shape().contains(&0),
171 Self::C32(t) => t.shape().contains(&0),
172 Self::C64(t) => t.shape().contains(&0),
173 }
174 }
175
176 /// Borrow this tensor as a dynamic zero-offset view.
177 ///
178 /// # Examples
179 ///
180 /// ```rust
181 /// use tenferro_tensor::{DefaultScalars, DType};
182 ///
183 /// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![1_i64])?;
184 /// assert_eq!(tensor.as_view().dtype(), DType::I64);
185 /// # Ok::<(), tenferro_tensor::Error>(())
186 /// ```
187 pub fn as_view(&self) -> DefaultScalarsView<'_> {
188 match self {
189 Self::F32(t) => DefaultScalarsView::F32(t.as_view()),
190 Self::F64(t) => DefaultScalarsView::F64(t.as_view()),
191 Self::I32(t) => DefaultScalarsView::I32(t.as_view()),
192 Self::I64(t) => DefaultScalarsView::I64(t.as_view()),
193 Self::Bool(t) => DefaultScalarsView::Bool(t.as_view()),
194 Self::C32(t) => DefaultScalarsView::C32(t.as_view()),
195 Self::C64(t) => DefaultScalarsView::C64(t.as_view()),
196 }
197 }
198}
199
200impl DefaultScalars {
201 /// Create a dynamic tensor from a column-major host buffer.
202 ///
203 /// # Examples
204 ///
205 /// ```rust
206 /// use tenferro_tensor::{DefaultScalars, DType};
207 ///
208 /// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![2.0_f32])?;
209 /// assert_eq!(tensor.dtype(), DType::F32);
210 /// # Ok::<(), tenferro_tensor::Error>(())
211 /// ```
212 ///
213 /// # Errors
214 ///
215 /// Returns a validation error carrying
216 /// [`tenferro_tensor_core::ValidationError::ShapeDataLengthMismatch`] when the shape product
217 /// differs from `data.len()`, or [`tenferro_tensor_core::ValidationError::IntegerOverflow`]
218 /// when validating the shape overflows.
219 pub fn from_vec_col_major<T: TensorScalar>(
220 shape: impl Into<Vec<usize>>,
221 data: Vec<T>,
222 ) -> crate::Result<Self> {
223 T::into_default_scalars(shape.into(), data)
224 }
225
226 /// Return the tensor dtype tag.
227 ///
228 /// # Examples
229 ///
230 /// ```rust
231 /// use tenferro_tensor::{DefaultScalars, DType};
232 ///
233 /// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![false])?;
234 /// assert_eq!(tensor.dtype(), DType::Bool);
235 /// # Ok::<(), tenferro_tensor::Error>(())
236 /// ```
237 pub fn dtype(&self) -> DType {
238 self.value.dtype()
239 }
240
241 /// Borrow the tensor shape.
242 ///
243 /// # Examples
244 ///
245 /// ```rust
246 /// use tenferro_tensor::DefaultScalars;
247 ///
248 /// let tensor = DefaultScalars::from_vec_col_major(vec![2], vec![1_i32, 2])?;
249 /// assert_eq!(tensor.shape(), &[2]);
250 /// # Ok::<(), tenferro_tensor::Error>(())
251 /// ```
252 pub fn shape(&self) -> &[usize] {
253 self.value.shape()
254 }
255
256 /// Return the tensor rank.
257 ///
258 /// # Examples
259 ///
260 /// ```rust
261 /// use tenferro_tensor::DefaultScalars;
262 ///
263 /// let tensor = DefaultScalars::from_vec_col_major(vec![1, 1], vec![1_i64])?;
264 /// assert_eq!(tensor.rank(), 2);
265 /// # Ok::<(), tenferro_tensor::Error>(())
266 /// ```
267 pub fn rank(&self) -> usize {
268 self.value.rank()
269 }
270
271 /// Return whether the tensor has zero elements.
272 ///
273 /// # Examples
274 ///
275 /// ```rust
276 /// use tenferro_tensor::DefaultScalars;
277 ///
278 /// let tensor = DefaultScalars::from_vec_col_major(vec![0], Vec::<f64>::new())?;
279 /// assert!(tensor.is_empty());
280 /// # Ok::<(), tenferro_tensor::Error>(())
281 /// ```
282 pub fn is_empty(&self) -> bool {
283 self.value.is_empty()
284 }
285
286 /// Borrow the typed host slice when the dtype matches.
287 ///
288 /// # Examples
289 ///
290 /// ```rust
291 /// use tenferro_tensor::DefaultScalars;
292 ///
293 /// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![3.0_f64])?;
294 /// assert_eq!(tensor.as_slice::<f64>()?, &[3.0]);
295 /// assert!(tensor.as_slice::<f32>().is_err());
296 /// # Ok::<(), tenferro_tensor::Error>(())
297 /// ```
298 ///
299 /// # Errors
300 ///
301 /// Returns [`crate::Error::Validation`] with a dtype mismatch when `T`
302 /// does not match the tensor's runtime dtype.
303 pub fn as_slice<T: TensorScalar>(&self) -> crate::Result<&[T]> {
304 let actual = self.dtype();
305 T::default_scalars_slice(self)
306 .ok_or_else(|| dtype_mismatch("DefaultScalars::as_slice", T::dtype(), actual))
307 }
308
309 /// Mutably borrow the typed host slice when the dtype matches.
310 ///
311 /// # Examples
312 ///
313 /// ```rust
314 /// use tenferro_tensor::DefaultScalars;
315 ///
316 /// let mut tensor = DefaultScalars::from_vec_col_major(vec![1], vec![3.0_f64])?;
317 /// tensor.as_mut_slice::<f64>()?[0] = 4.0;
318 /// assert_eq!(tensor.as_slice::<f64>()?, &[4.0]);
319 /// # Ok::<(), tenferro_tensor::Error>(())
320 /// ```
321 ///
322 /// # Errors
323 ///
324 /// Returns [`crate::Error::Validation`] with a dtype mismatch when `T`
325 /// does not match the tensor's runtime dtype.
326 pub fn as_mut_slice<T: TensorScalar>(&mut self) -> crate::Result<&mut [T]> {
327 let actual = self.dtype();
328 T::default_scalars_slice_mut(self)
329 .ok_or_else(|| dtype_mismatch("DefaultScalars::as_mut_slice", T::dtype(), actual))
330 }
331
332 /// Borrow this tensor as a dynamic zero-offset view.
333 ///
334 /// # Examples
335 ///
336 /// ```rust
337 /// use tenferro_tensor::{DefaultScalars, DType};
338 ///
339 /// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![1.0_f32])?;
340 /// assert_eq!(tensor.as_view().dtype(), DType::F32);
341 /// # Ok::<(), tenferro_tensor::Error>(())
342 /// ```
343 pub fn as_view(&self) -> DefaultScalarsView<'_> {
344 self.value.as_view()
345 }
346
347 /// Consume this tensor and return typed column-major data when the dtype matches.
348 ///
349 /// # Examples
350 ///
351 /// ```rust
352 /// use tenferro_tensor::DefaultScalars;
353 ///
354 /// let tensor = DefaultScalars::from_vec_col_major(vec![2], vec![1.0_f64, 2.0])?;
355 /// let (shape, data) = tensor.into_vec_col_major::<f64>()?;
356 /// assert_eq!(shape, vec![2]);
357 /// assert_eq!(data, vec![1.0, 2.0]);
358 /// # Ok::<(), tenferro_tensor::Error>(())
359 /// ```
360 ///
361 /// # Errors
362 ///
363 /// Returns [`crate::Error::Validation`] with a dtype mismatch when `T`
364 /// does not match the tensor's runtime dtype.
365 pub fn into_vec_col_major<T: TensorScalar>(self) -> crate::Result<(Vec<usize>, Vec<T>)> {
366 let actual = self.dtype();
367 T::from_default_scalars(self)
368 .map(TypedTensor::<T, DynRank, Host>::into_vec_col_major)
369 .ok_or_else(|| dtype_mismatch("DefaultScalars::into_vec_col_major", T::dtype(), actual))
370 }
371
372 pub(crate) fn from_payload(value: DefaultScalarsValue) -> Self {
373 Self { value }
374 }
375
376 pub(crate) fn payload(&self) -> &DefaultScalarsValue {
377 &self.value
378 }
379
380 pub(crate) fn payload_mut(&mut self) -> &mut DefaultScalarsValue {
381 &mut self.value
382 }
383
384 pub(crate) fn into_payload(self) -> DefaultScalarsValue {
385 self.value
386 }
387}
388
389impl ScalarSet for DefaultScalars {
390 type Tag = DType;
391
392 const TAGS: &'static [Self::Tag] = <DefaultScalarsValue as ScalarSet>::TAGS;
393
394 fn tag(&self) -> Self::Tag {
395 self.value.tag()
396 }
397
398 fn promote(lhs: Self::Tag, rhs: Self::Tag) -> Self::Tag {
399 <DefaultScalarsValue as ScalarSet>::promote(lhs, rhs)
400 }
401}
402
403/// Dynamic borrowed host tensor view.
404///
405/// # Examples
406///
407/// ```rust
408/// use tenferro_tensor::{DefaultScalars, DType};
409///
410/// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![true])?;
411/// let view = tensor.as_view();
412/// assert_eq!(view.dtype(), DType::Bool);
413/// # Ok::<(), tenferro_tensor::Error>(())
414/// ```
415///
416/// ```compile_fail
417/// # use tenferro_tensor::DefaultScalars;
418/// # let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![1.0_f64]).unwrap();
419/// let a = tensor.as_view();
420/// let b = tensor.as_view();
421/// let _ = a == b;
422/// ```
423#[derive(Clone, Debug)]
424pub enum DefaultScalarsView<'a> {
425 F32(TypedTensorView<'a, f32, DynRank, Host>),
426 F64(TypedTensorView<'a, f64, DynRank, Host>),
427 I32(TypedTensorView<'a, i32, DynRank, Host>),
428 I64(TypedTensorView<'a, i64, DynRank, Host>),
429 Bool(TypedTensorView<'a, bool, DynRank, Host>),
430 C32(TypedTensorView<'a, Complex32, DynRank, Host>),
431 C64(TypedTensorView<'a, Complex64, DynRank, Host>),
432}
433
434macro_rules! impl_dynamic_view {
435 ($self:ident, $method:ident($($arg:ident),*) => $inner:ident) => {
436 match $self {
437 DefaultScalarsView::F32(view) => DefaultScalarsView::F32(view.$method($($arg),*)?),
438 DefaultScalarsView::F64(view) => DefaultScalarsView::F64(view.$method($($arg),*)?),
439 DefaultScalarsView::I32(view) => DefaultScalarsView::I32(view.$method($($arg),*)?),
440 DefaultScalarsView::I64(view) => DefaultScalarsView::I64(view.$method($($arg),*)?),
441 DefaultScalarsView::Bool(view) => DefaultScalarsView::Bool(view.$method($($arg),*)?),
442 DefaultScalarsView::C32(view) => DefaultScalarsView::C32(view.$method($($arg),*)?),
443 DefaultScalarsView::C64(view) => DefaultScalarsView::C64(view.$method($($arg),*)?),
444 }
445 };
446}
447
448impl<'a> DefaultScalarsView<'a> {
449 /// Return this view's dtype.
450 ///
451 /// # Examples
452 ///
453 /// ```rust
454 /// use tenferro_tensor::{DefaultScalars, DType};
455 ///
456 /// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![1.0_f32])?;
457 /// assert_eq!(tensor.as_view().dtype(), DType::F32);
458 /// # Ok::<(), tenferro_tensor::Error>(())
459 /// ```
460 pub fn dtype(&self) -> DType {
461 match self {
462 Self::F32(_) => DType::F32,
463 Self::F64(_) => DType::F64,
464 Self::I32(_) => DType::I32,
465 Self::I64(_) => DType::I64,
466 Self::Bool(_) => DType::Bool,
467 Self::C32(_) => DType::C32,
468 Self::C64(_) => DType::C64,
469 }
470 }
471
472 /// Borrow this view's shape.
473 ///
474 /// # Examples
475 ///
476 /// ```rust
477 /// use tenferro_tensor::DefaultScalars;
478 ///
479 /// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![1.0_f64])?;
480 /// assert_eq!(tensor.as_view().shape(), &[1]);
481 /// # Ok::<(), tenferro_tensor::Error>(())
482 /// ```
483 pub fn shape(&self) -> &[usize] {
484 match self {
485 Self::F32(view) => view.shape(),
486 Self::F64(view) => view.shape(),
487 Self::I32(view) => view.shape(),
488 Self::I64(view) => view.shape(),
489 Self::Bool(view) => view.shape(),
490 Self::C32(view) => view.shape(),
491 Self::C64(view) => view.shape(),
492 }
493 }
494
495 /// Return the view rank.
496 ///
497 /// # Examples
498 ///
499 /// ```rust
500 /// use tenferro_tensor::DefaultScalars;
501 ///
502 /// let tensor = DefaultScalars::from_vec_col_major(vec![1, 1], vec![1_i64])?;
503 /// assert_eq!(tensor.as_view().rank(), 2);
504 /// # Ok::<(), tenferro_tensor::Error>(())
505 /// ```
506 pub fn rank(&self) -> usize {
507 self.shape().len()
508 }
509
510 /// Return whether this view has zero logical elements.
511 ///
512 /// # Examples
513 ///
514 /// ```rust
515 /// use tenferro_tensor::DefaultScalars;
516 ///
517 /// let tensor = DefaultScalars::from_vec_col_major(vec![0], Vec::<f64>::new())?;
518 /// assert!(tensor.as_view().is_empty());
519 /// # Ok::<(), tenferro_tensor::Error>(())
520 /// ```
521 pub fn is_empty(&self) -> bool {
522 match self {
523 Self::F32(view) => view.shape().contains(&0),
524 Self::F64(view) => view.shape().contains(&0),
525 Self::I32(view) => view.shape().contains(&0),
526 Self::I64(view) => view.shape().contains(&0),
527 Self::Bool(view) => view.shape().contains(&0),
528 Self::C32(view) => view.shape().contains(&0),
529 Self::C64(view) => view.shape().contains(&0),
530 }
531 }
532
533 /// Return a metadata-only reshape of this dynamic view.
534 ///
535 /// # Examples
536 ///
537 /// ```rust
538 /// use tenferro_tensor::DefaultScalars;
539 ///
540 /// let tensor = DefaultScalars::from_vec_col_major(vec![4], vec![1_i32, 2, 3, 4])?;
541 /// assert_eq!(tensor.as_view().reshape_view(vec![2, 2])?.shape(), &[2, 2]);
542 /// # Ok::<(), tenferro_tensor::Error>(())
543 /// ```
544 ///
545 /// # Errors
546 ///
547 /// Returns a validation error carrying [`tenferro_tensor_core::ValidationError::ShapeMismatch`]
548 /// when the element counts differ,
549 /// [`tenferro_tensor_core::ValidationError::NonContiguousViewAsSlice`] when the view's strides
550 /// cannot express the new shape, or [`tenferro_tensor_core::ValidationError::IntegerOverflow`]
551 /// when shape arithmetic overflows.
552 pub fn reshape_view(&self, shape: impl AsRef<[usize]>) -> crate::Result<Self> {
553 let shape = shape.as_ref();
554 Ok(impl_dynamic_view!(self, reshape_view(shape) => view))
555 }
556
557 /// Return a metadata-only transposed dynamic view with axes in the requested order.
558 ///
559 /// # Examples
560 ///
561 /// ```rust
562 /// use tenferro_tensor::DefaultScalars;
563 ///
564 /// let tensor = DefaultScalars::from_vec_col_major(vec![1, 2], vec![1_i64, 2])?;
565 /// assert_eq!(tensor.as_view().transpose_view(&[1, 0])?.shape(), &[2, 1]);
566 /// # Ok::<(), tenferro_tensor::Error>(())
567 /// ```
568 ///
569 /// # Errors
570 ///
571 /// Returns a validation error carrying
572 /// [`tenferro_tensor_core::ValidationError::InvalidPermutationLength`],
573 /// [`tenferro_tensor_core::ValidationError::AxisOutOfBounds`] or
574 /// [`tenferro_tensor_core::ValidationError::DuplicateAxis`] when `axes` is not a permutation of
575 /// the view rank.
576 pub fn transpose_view(&self, axes: &[usize]) -> crate::Result<Self> {
577 Ok(impl_dynamic_view!(self, transpose_view(axes) => view))
578 }
579
580 /// Return a metadata-only positive-step slice of this dynamic view.
581 ///
582 /// # Examples
583 ///
584 /// ```rust
585 /// use tenferro_tensor::{DefaultScalars, StridedSliceSpec};
586 ///
587 /// let tensor = DefaultScalars::from_vec_col_major(vec![3], vec![1_i64, 2, 3])?;
588 /// assert_eq!(
589 /// tensor.as_view().slice_view(&[StridedSliceSpec::new(1, Some(3), 1)])?.shape(),
590 /// &[2],
591 /// );
592 /// # Ok::<(), tenferro_tensor::Error>(())
593 /// ```
594 ///
595 /// # Errors
596 ///
597 /// Returns [`crate::Error::Validation`] for a rank mismatch or invalid
598 /// slice bounds or step.
599 pub fn slice_view(&self, spec: &[StridedSliceSpec]) -> crate::Result<Self> {
600 Ok(impl_dynamic_view!(self, slice_view(spec) => view))
601 }
602}
603
604/// Core-neutral tensor input reference.
605///
606/// # Examples
607///
608/// ```rust
609/// use tenferro_tensor::{DefaultScalars, DefaultScalarsRef};
610///
611/// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![1.0_f32])?;
612/// let reference = DefaultScalarsRef::Tensor(&tensor);
613/// assert_eq!(reference.shape(), &[1]);
614/// # Ok::<(), tenferro_tensor::Error>(())
615/// ```
616// The view variant holds a canonical `TypedTensorView` inline so a borrowed
617// input costs no allocation; boxing it would allocate on every reference.
618#[allow(clippy::large_enum_variant)]
619#[derive(Clone, Debug)]
620pub enum DefaultScalarsRef<'a> {
621 Tensor(&'a DefaultScalars),
622 View(DefaultScalarsView<'a>),
623}
624
625impl<'a> DefaultScalarsRef<'a> {
626 /// Return the referenced dtype.
627 ///
628 /// # Examples
629 ///
630 /// ```rust
631 /// use tenferro_tensor::{DefaultScalars, DefaultScalarsRef, DType};
632 ///
633 /// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![1_i64])?;
634 /// assert_eq!(DefaultScalarsRef::Tensor(&tensor).dtype(), DType::I64);
635 /// # Ok::<(), tenferro_tensor::Error>(())
636 /// ```
637 pub fn dtype(&self) -> DType {
638 match self {
639 Self::Tensor(tensor) => tensor.dtype(),
640 Self::View(view) => view.dtype(),
641 }
642 }
643
644 /// Borrow the referenced shape.
645 ///
646 /// # Examples
647 ///
648 /// ```rust
649 /// use tenferro_tensor::{DefaultScalars, DefaultScalarsRef};
650 ///
651 /// let tensor = DefaultScalars::from_vec_col_major(vec![1], vec![1_i64])?;
652 /// assert_eq!(DefaultScalarsRef::Tensor(&tensor).shape(), &[1]);
653 /// # Ok::<(), tenferro_tensor::Error>(())
654 /// ```
655 pub fn shape(&self) -> &[usize] {
656 match self {
657 Self::Tensor(tensor) => tensor.shape(),
658 Self::View(view) => view.shape(),
659 }
660 }
661
662 /// Return the referenced rank.
663 ///
664 /// # Examples
665 ///
666 /// ```rust
667 /// use tenferro_tensor::{DefaultScalars, DefaultScalarsRef};
668 ///
669 /// let tensor = DefaultScalars::from_vec_col_major(vec![1, 1], vec![1_i64])?;
670 /// assert_eq!(DefaultScalarsRef::Tensor(&tensor).rank(), 2);
671 /// # Ok::<(), tenferro_tensor::Error>(())
672 /// ```
673 pub fn rank(&self) -> usize {
674 self.shape().len()
675 }
676
677 /// Return whether the referenced tensor/view is empty.
678 ///
679 /// # Examples
680 ///
681 /// ```rust
682 /// use tenferro_tensor::{DefaultScalars, DefaultScalarsRef};
683 ///
684 /// let tensor = DefaultScalars::from_vec_col_major(vec![0], Vec::<f64>::new())?;
685 /// assert!(DefaultScalarsRef::Tensor(&tensor).is_empty());
686 /// # Ok::<(), tenferro_tensor::Error>(())
687 /// ```
688 pub fn is_empty(&self) -> bool {
689 match self {
690 Self::Tensor(tensor) => tensor.is_empty(),
691 Self::View(view) => view.shape().contains(&0),
692 }
693 }
694}