use crate::array::Array;
use crate::error::{NumRs2Error, Result};
pub fn fromfunction<T, F>(function: F, shape: &[usize]) -> Result<Array<T>>
where
T: Clone + num_traits::Zero,
F: Fn(&[usize]) -> T,
{
if shape.is_empty() {
return Ok(Array::from_vec(vec![]));
}
let total_elements: usize = shape.iter().product();
let mut result_data = Vec::with_capacity(total_elements);
let mut indices = vec![0; shape.len()];
for _ in 0..total_elements {
let value = function(&indices);
result_data.push(value);
let mut carry = true;
for dim in (0..shape.len()).rev() {
if carry {
indices[dim] += 1;
carry = indices[dim] >= shape[dim];
if carry {
indices[dim] = 0;
}
}
}
}
Ok(Array::from_vec(result_data).reshape(shape))
}
pub fn frombuffer<T: Clone + Default>(
buffer: &[u8],
dtype_size: usize,
count: isize,
offset: usize,
) -> Result<Array<T>> {
if dtype_size == 0 {
return Err(NumRs2Error::InvalidOperation(
"Data type size cannot be zero".to_string(),
));
}
if offset >= buffer.len() {
return Err(NumRs2Error::IndexOutOfBounds(format!(
"Offset {} is beyond buffer size {}",
offset,
buffer.len()
)));
}
if dtype_size != std::mem::size_of::<T>() {
return Err(NumRs2Error::InvalidOperation(format!(
"Data type size mismatch: expected {}, got {}",
std::mem::size_of::<T>(),
dtype_size
)));
}
let available_bytes = buffer.len() - offset;
let max_elements = available_bytes / dtype_size;
let num_elements = if count < 0 {
max_elements
} else {
let requested = count as usize;
if requested > max_elements {
return Err(NumRs2Error::InvalidOperation(format!(
"Requested {} elements but only {} available in buffer",
requested, max_elements
)));
}
requested
};
if num_elements == 0 {
return Ok(Array::from_vec(vec![]));
}
let mut result = Vec::with_capacity(num_elements);
for i in 0..num_elements {
let byte_offset = offset + i * dtype_size;
let element_bytes = &buffer[byte_offset..byte_offset + dtype_size];
let element = unsafe { std::ptr::read(element_bytes.as_ptr() as *const T) };
result.push(element);
}
Ok(Array::from_vec(result))
}
pub fn fromiter<T: Clone, I: Iterator<Item = T>>(
iter: I,
shape: Option<&[usize]>,
) -> Result<Array<T>> {
let data: Vec<T> = iter.collect();
match shape {
Some(s) => {
let expected_size: usize = s.iter().product();
if data.len() != expected_size {
return Err(NumRs2Error::ShapeMismatch {
expected: vec![expected_size],
actual: vec![data.len()],
});
}
Ok(Array::from_vec(data).reshape(s))
}
None => Ok(Array::from_vec(data)),
}
}