use super::Array;
use crate::{BaseItem, Shape, c32, c64};
pub struct ScalarArrayImpl<Item: Copy + Default> {
scalar: Item,
}
pub type ZeroDimArray<Item> = Array<ScalarArrayImpl<Item>, 0>;
impl<Item: Copy + Default> BaseItem for ScalarArrayImpl<Item> {
type Item = Item;
}
impl<Item: Copy + Default> Shape<0> for ScalarArrayImpl<Item> {
fn shape(&self) -> [usize; 0] {
[]
}
}
impl<Item: Copy + Default> ZeroDimArray<Item> {
pub fn from_scalar(value: Item) -> Self {
Array::new(ScalarArrayImpl { scalar: value })
}
pub fn into_scalar(self) -> Item {
self.into_imp().scalar
}
pub fn scalar(&self) -> &Item {
&self.imp().scalar
}
pub fn scalar_mut(&mut self) -> &mut Item {
&mut self.imp_mut().scalar
}
}
macro_rules! impl_zero_dim_scalar_conversions {
($($item:ty),+ $(,)?) => {
$(
impl From<$item> for ZeroDimArray<$item> {
fn from(value: $item) -> Self {
Self::from_scalar(value)
}
}
impl From<ZeroDimArray<$item>> for $item {
fn from(value: ZeroDimArray<$item>) -> Self {
value.into_scalar()
}
}
)+
};
}
impl_zero_dim_scalar_conversions!(
f32, f64, c32, c64, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize,
);
#[cfg(test)]
mod tests {
use super::ZeroDimArray;
use crate::{Shape, c32, c64};
#[test]
fn scalar_shape_and_borrows() {
let mut array = ZeroDimArray::from_scalar(7_i32);
assert_eq!(array.shape(), [0usize; 0]);
assert_eq!(array.imp().shape(), [0usize; 0]);
assert_eq!(array.len(), 1);
assert_eq!(array.number_of_elements(), 1);
assert!(!array.is_empty());
let scalar: &i32 = array.scalar();
assert_eq!(*scalar, 7);
let scalar: &mut i32 = array.scalar_mut();
*scalar = -11;
assert_eq!(*array.scalar(), -11);
assert_eq!(array.into_scalar(), -11);
}
#[test]
fn concrete_conversion_roundtrips() {
fn roundtrip<Item>(value: Item)
where
Item: Copy + Default + PartialEq + std::fmt::Debug + From<ZeroDimArray<Item>>,
ZeroDimArray<Item>: From<Item>,
{
let array: ZeroDimArray<Item> = value.into();
assert_eq!(*array.scalar(), value);
let recovered: Item = array.into();
assert_eq!(recovered, value);
}
roundtrip(1.25_f32);
roundtrip(-2.5_f64);
roundtrip(c32::new(1.25, -3.5));
roundtrip(c64::new(-2.5, 7.25));
roundtrip(i8::MIN);
roundtrip(i16::MIN);
roundtrip(i32::MIN);
roundtrip(i64::MIN);
roundtrip(i128::MIN);
roundtrip(isize::MIN);
roundtrip(u8::MAX);
roundtrip(u16::MAX);
roundtrip(u32::MAX);
roundtrip(u64::MAX);
roundtrip(u128::MAX);
roundtrip(usize::MAX);
}
#[test]
fn custom_copy_default_item() {
#[derive(Clone, Copy, Default)]
struct CustomItem {
value: u32,
}
fn wrap<Item: Copy + Default>(value: Item) -> ZeroDimArray<Item> {
ZeroDimArray::from_scalar(value)
}
let mut array = wrap(CustomItem { value: 42 });
assert_eq!(array.scalar().value, 42);
array.scalar_mut().value = 73;
assert_eq!(array.into_scalar().value, 73);
assert_eq!(wrap(CustomItem::default()).into_scalar().value, 0);
}
}