use std::panic::Location;
use crate::axes::{self, IntoShape};
use crate::buffer::Buffer;
use crate::shape;
use crate::{Array, Complex64, DType, Element, Error, Result, bf16, f16};
pub(crate) fn from_data<T: Element>(data: &[T], shape: &[usize]) -> Result<Array> {
let expected = shape::checked_size(shape)?;
if data.len() != expected {
return Err(Error::size_mismatch("from_slice", expected, data.len()));
}
let mut buffer = Buffer::try_alloc(shape::checked_nbytes(shape, T::DTYPE.size())?)?;
T::write_bytes(data, buffer.bytes_mut());
Array::from_buffer(buffer, T::DTYPE, shape)
}
impl Array {
pub(crate) fn constructor(
op: &'static str,
at: &'static Location<'static>,
dtype: DType,
spec: &[i64],
f: impl FnOnce(&[usize]) -> Result<Array>,
) -> Array {
match axes::dims(spec) {
Ok(shape) => {
f(&shape).unwrap_or_else(|e| Array::failed(e.locate(op, at), dtype, &shape))
}
Err(e) => Array::failed(e.locate(op, at), dtype, &[]),
}
}
#[track_caller]
pub fn from_slice<T: Element>(data: &[T], shape: impl IntoShape) -> Array {
let spec = shape.shape_spec();
Self::constructor("from_slice", Location::caller(), T::DTYPE, &spec, |shape| {
from_data(data, shape)
})
}
}
impl<T: Element> From<T> for Array {
#[track_caller]
fn from(value: T) -> Self {
Array::from_slice(&[value], ())
}
}
impl<T: Element, const N: usize> From<[T; N]> for Array {
#[track_caller]
fn from(values: [T; N]) -> Self {
Array::from_slice(&values, [N])
}
}
impl<T: Element> From<Vec<T>> for Array {
#[track_caller]
fn from(values: Vec<T>) -> Self {
Array::from_slice(&values, [values.len()])
}
}
impl<T: Element> From<&[T]> for Array {
#[track_caller]
fn from(values: &[T]) -> Self {
Array::from_slice(values, [values.len()])
}
}
impl<T: Element> FromIterator<T> for Array {
#[track_caller]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let values: Vec<T> = iter.into_iter().collect();
Array::from_slice(&values, [values.len()])
}
}
#[doc(hidden)]
pub trait Literal: Copy {
fn into_array(data: &[Self], shape: &[usize], at: &'static Location<'static>) -> Array;
}
macro_rules! literal {
($($t:ty),*) => {$(
impl Literal for $t {
fn into_array(data: &[Self], shape: &[usize], at: &'static Location<'static>) -> Array {
from_data(data, shape).unwrap_or_else(|e| {
Array::failed(e.locate("array", at), <$t as Element>::DTYPE, shape)
})
}
}
)*};
}
literal!(
bool, u8, u16, u32, u64, i8, i16, i32, i64, f16, bf16, f32, Complex64
);
impl Literal for f64 {
fn into_array(data: &[Self], shape: &[usize], at: &'static Location<'static>) -> Array {
let data: Vec<f32> = data.iter().map(|&x| x as f32).collect();
f32::into_array(&data, shape, at)
}
}
#[doc(hidden)]
pub mod __private {
use std::panic::Location;
use super::Literal;
use crate::Array;
#[track_caller]
pub fn from_nested1<T: Literal, const A: usize>(x: [T; A]) -> Array {
T::into_array(&x, &[A], Location::caller())
}
#[track_caller]
pub fn from_nested2<T: Literal, const A: usize, const B: usize>(x: [[T; B]; A]) -> Array {
let flat: Vec<T> = x.iter().flatten().copied().collect();
T::into_array(&flat, &[A, B], Location::caller())
}
#[track_caller]
pub fn from_nested3<T: Literal, const A: usize, const B: usize, const C: usize>(
x: [[[T; C]; B]; A],
) -> Array {
let flat: Vec<T> = x.iter().flatten().flatten().copied().collect();
T::into_array(&flat, &[A, B, C], Location::caller())
}
#[track_caller]
pub fn from_nested4<
T: Literal,
const A: usize,
const B: usize,
const C: usize,
const D: usize,
>(
x: [[[[T; D]; C]; B]; A],
) -> Array {
let flat: Vec<T> = x.iter().flatten().flatten().flatten().copied().collect();
T::into_array(&flat, &[A, B, C, D], Location::caller())
}
}
#[macro_export]
macro_rules! array {
($([$([$([$($x:expr),* $(,)?]),* $(,)?]),* $(,)?]),+ $(,)?) => {
$crate::__private::from_nested4([$([$([$([$($x),*]),*]),*]),+])
};
($([$([$($x:expr),* $(,)?]),* $(,)?]),+ $(,)?) => {
$crate::__private::from_nested3([$([$([$($x),*]),*]),+])
};
($([$($x:expr),* $(,)?]),+ $(,)?) => {
$crate::__private::from_nested2([$([$($x),*]),+])
};
($($x:expr),+ $(,)?) => {
$crate::__private::from_nested1([$($x),+])
};
}
#[cfg(test)]
mod tests {
use crate::{Array, DType};
#[test]
fn literals() {
let a = crate::array![[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
assert_eq!((a.shape(), a.dtype()), (&[2, 2, 2][..], DType::I32));
let b = crate::array![[[[1.5f64]]]];
assert_eq!((b.shape(), b.dtype()), (&[1, 1, 1, 1][..], DType::F32));
assert_eq!(crate::array![true, false].dtype(), DType::Bool);
assert_eq!(Array::from(vec![1i64; 6]).shape(), [6]);
assert_eq!(Array::from(3.0f64).dtype(), DType::F64);
}
}