use std::collections::BTreeMap;
use std::fmt;
use thiserror::Error;
use super::{DType, IrError, TensorMap, TensorRef};
#[derive(Error, Debug)]
pub enum MaterializeError {
#[error("I/O error materialising tensor '{name}': {source}")]
Io {
name: String,
#[source]
source: std::io::Error,
},
#[error("Transform failed for tensor '{name}': {reason}")]
Transform { name: String, reason: String },
#[error(
"Tensor '{name}' materialised with {actual} bytes; declared metadata expects {expected} bytes"
)]
SizeMismatch {
name: String,
expected: usize,
actual: usize,
},
#[error("IR error materialising tensor '{name}': {source}")]
Ir {
name: String,
#[source]
source: IrError,
},
}
#[derive(Debug, Clone)]
pub struct LazyMeta {
pub name: String,
pub shape: Vec<usize>,
pub dtype: DType,
pub byte_len: usize,
}
impl LazyMeta {
pub fn new(name: String, shape: Vec<usize>, dtype: DType) -> Self {
let numel: usize = shape.iter().product();
let byte_len = numel * dtype.element_size();
Self {
name,
shape,
dtype,
byte_len,
}
}
}
enum LazyState {
Materialized(Vec<u8>),
MaterializedShared(std::sync::Arc<Vec<u8>>),
Pending(Box<dyn FnOnce() -> Result<Vec<u8>, MaterializeError> + Send + 'static>),
}
impl fmt::Debug for LazyState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LazyState::Materialized(bytes) => f
.debug_tuple("Materialized")
.field(&format_args!("<{} bytes>", bytes.len()))
.finish(),
LazyState::MaterializedShared(bytes) => f
.debug_tuple("MaterializedShared")
.field(&format_args!(
"<{} bytes, refcount {}>",
bytes.len(),
std::sync::Arc::strong_count(bytes)
))
.finish(),
LazyState::Pending(_) => f.debug_tuple("Pending").field(&"<closure>").finish(),
}
}
}
#[derive(Debug)]
pub struct LazyTensor {
meta: LazyMeta,
state: LazyState,
}
impl LazyTensor {
pub fn from_bytes(meta: LazyMeta, bytes: Vec<u8>) -> Self {
Self {
meta,
state: LazyState::Materialized(bytes),
}
}
pub fn from_arc_bytes(meta: LazyMeta, bytes: std::sync::Arc<Vec<u8>>) -> Self {
Self {
meta,
state: LazyState::MaterializedShared(bytes),
}
}
pub fn from_closure<F>(meta: LazyMeta, load: F) -> Self
where
F: FnOnce() -> Result<Vec<u8>, MaterializeError> + Send + 'static,
{
Self {
meta,
state: LazyState::Pending(Box::new(load)),
}
}
pub fn name(&self) -> &str {
&self.meta.name
}
pub fn shape(&self) -> &[usize] {
&self.meta.shape
}
pub fn dtype(&self) -> DType {
self.meta.dtype
}
pub fn byte_len(&self) -> usize {
self.meta.byte_len
}
pub fn meta(&self) -> &LazyMeta {
&self.meta
}
pub fn materialize(self) -> Result<TensorRef, MaterializeError> {
let LazyTensor { meta, state } = self;
let bytes = match state {
LazyState::Materialized(bytes) => bytes,
LazyState::MaterializedShared(arc) => {
std::sync::Arc::unwrap_or_clone(arc)
}
LazyState::Pending(load) => load()?,
};
if bytes.len() != meta.byte_len {
return Err(MaterializeError::SizeMismatch {
name: meta.name,
expected: meta.byte_len,
actual: bytes.len(),
});
}
Ok(TensorRef {
name: meta.name,
shape: meta.shape,
dtype: meta.dtype,
data: std::sync::Arc::new(bytes),
})
}
pub fn materialize_cloned(&self) -> Result<TensorRef, MaterializeError> {
let data: std::sync::Arc<Vec<u8>> = match &self.state {
LazyState::Materialized(bytes) => std::sync::Arc::new(bytes.clone()),
LazyState::MaterializedShared(arc) => std::sync::Arc::clone(arc),
LazyState::Pending(_) => {
return Err(MaterializeError::Transform {
name: self.meta.name.clone(),
reason:
"borrowed materialization is only available for already-resident tensors"
.to_string(),
});
}
};
if data.len() != self.meta.byte_len {
return Err(MaterializeError::SizeMismatch {
name: self.meta.name.clone(),
expected: self.meta.byte_len,
actual: data.len(),
});
}
Ok(TensorRef {
name: self.meta.name.clone(),
shape: self.meta.shape.clone(),
dtype: self.meta.dtype,
data,
})
}
pub fn map<F>(self, f: F) -> Self
where
F: FnOnce(TensorRef) -> Result<TensorRef, MaterializeError> + Send + 'static,
{
let new_meta = self.meta.clone();
let parent = self;
LazyTensor::from_closure(new_meta, move || {
let materialized = parent.materialize()?;
let transformed = f(materialized)?;
Ok(std::sync::Arc::unwrap_or_clone(transformed.data))
})
}
pub fn map_with_meta<F>(self, new_meta: LazyMeta, f: F) -> Self
where
F: FnOnce(TensorRef) -> Result<TensorRef, MaterializeError> + Send + 'static,
{
let parent = self;
LazyTensor::from_closure(new_meta, move || {
let materialized = parent.materialize()?;
let transformed = f(materialized)?;
Ok(std::sync::Arc::unwrap_or_clone(transformed.data))
})
}
}
#[derive(Debug, Default)]
pub struct LazyTensorMap {
inner: BTreeMap<String, LazyTensor>,
}
impl LazyTensorMap {
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, tensor: LazyTensor) {
let key = tensor.meta.name.clone();
self.inner.insert(key, tensor);
}
pub fn get(&self, name: &str) -> Option<&LazyTensor> {
self.inner.get(name)
}
pub fn remove(&mut self, name: &str) -> Option<LazyTensor> {
self.inner.remove(name)
}
pub fn contains_key(&self, name: &str) -> bool {
self.inner.contains_key(name)
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&String, &LazyTensor)> {
self.inner.iter()
}
pub fn convert_bf16_to_f16(&mut self) -> Result<usize, MaterializeError> {
let bf16_names: Vec<String> = self
.inner
.iter()
.filter(|(_, t)| t.meta().dtype == DType::BF16)
.map(|(name, _)| name.clone())
.collect();
let count = bf16_names.len();
for name in bf16_names {
if let Some(lazy) = self.inner.remove(&name) {
let meta = lazy.meta();
let new_meta = LazyMeta::new(meta.name.clone(), meta.shape.clone(), DType::F16);
let new_lazy = lazy.map_with_meta(new_meta, |tensor| {
tensor.to_f16().map_err(|e| MaterializeError::Transform {
name: tensor.name.clone(),
reason: format!("bf16→f16: {e}"),
})
});
self.inner.insert(name, new_lazy);
}
}
Ok(count)
}
pub fn total_size_bytes(&self) -> usize {
self.inner.values().map(|t| t.meta().byte_len).sum()
}
pub fn names(&self) -> impl Iterator<Item = &String> {
self.inner.keys()
}
pub fn into_iter(self) -> impl Iterator<Item = (String, LazyTensor)> {
self.inner.into_iter()
}
pub fn from_eager(tensor_map: TensorMap) -> Self {
let mut out = Self::new();
for (_, tref) in tensor_map.tensors.into_iter() {
let meta = LazyMeta::new(tref.name.clone(), tref.shape.clone(), tref.dtype);
out.insert(LazyTensor::from_arc_bytes(meta, tref.data));
}
out
}
pub fn from_eager_borrowed(tensor_map: &TensorMap) -> Self {
let mut out = Self::new();
for (_, tref) in tensor_map.tensors.iter() {
let meta = LazyMeta::new(tref.name.clone(), tref.shape.clone(), tref.dtype);
let name_for_err = tref.name.clone();
out.insert(LazyTensor::from_closure(meta, move || {
Err(MaterializeError::Transform {
name: name_for_err.clone(),
reason: "from_eager_borrowed view is metadata-only; \
source tensor_map owns the bytes (ADR-014 P2 iter-2 §S1)"
.to_string(),
})
}));
}
out
}
pub fn materialize_all(self) -> Result<TensorMap, MaterializeError> {
let mut out = TensorMap::new();
for (_, lazy) in self.inner.into_iter() {
let tref = lazy.materialize()?;
out.insert(tref);
}
Ok(out)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
fn meta(name: &str, shape: Vec<usize>, dtype: DType) -> LazyMeta {
LazyMeta::new(name.to_string(), shape, dtype)
}
fn f32_bytes(values: &[f32]) -> Vec<u8> {
values.iter().flat_map(|v| v.to_le_bytes()).collect()
}
#[test]
fn test_meta_byte_len_derives_from_shape_and_dtype() {
let m = meta("t", vec![2, 3], DType::F32);
assert_eq!(m.byte_len, 2 * 3 * 4);
}
#[test]
fn arc_clone_lazy_view_shares_bytes_with_source_no_byte_copy() {
let bytes = f32_bytes(&[1.0, 2.0, 3.0, 4.0]); let source_data_arc: Arc<Vec<u8>> = Arc::new(bytes);
let source_addr = Arc::as_ptr(&source_data_arc);
let tensor = TensorRef {
name: "shared".to_string(),
shape: vec![4],
dtype: DType::F32,
data: Arc::clone(&source_data_arc),
};
assert_eq!(
Arc::strong_count(&source_data_arc),
2,
"before LazyTensor share: source + tensor"
);
let lazy = LazyTensor::from_arc_bytes(
LazyMeta::new(tensor.name.clone(), tensor.shape.clone(), tensor.dtype),
Arc::clone(&tensor.data),
);
assert_eq!(
Arc::strong_count(&source_data_arc),
3,
"after LazyTensor::from_arc_bytes: source + tensor + lazy_view all share \
the SAME Arc — no byte copy. Pre-refactor this would have been a deep \
clone of the Vec<u8>."
);
let after_addr = Arc::as_ptr(&source_data_arc);
assert_eq!(
source_addr, after_addr,
"Vec<u8> allocation address must not change — Arc share is pointer-bump only"
);
drop(lazy);
assert_eq!(
Arc::strong_count(&source_data_arc),
2,
"after lazy_view drops: refcount returns to source + tensor"
);
}
#[test]
fn test_materialize_pending_runs_closure_once() {
let counter = Arc::new(AtomicUsize::new(0));
let counter_clone = counter.clone();
let m = meta("t", vec![3], DType::F32);
let lazy = LazyTensor::from_closure(m, move || {
counter_clone.fetch_add(1, Ordering::SeqCst);
Ok(f32_bytes(&[1.0, 2.0, 3.0]))
});
assert_eq!(counter.load(Ordering::SeqCst), 0);
assert_eq!(lazy.shape(), &[3]);
assert_eq!(lazy.dtype(), DType::F32);
assert_eq!(lazy.name(), "t");
assert_eq!(counter.load(Ordering::SeqCst), 0);
let tref = lazy.materialize().unwrap();
assert_eq!(counter.load(Ordering::SeqCst), 1);
assert_eq!(tref.shape, vec![3]);
assert_eq!(tref.dtype, DType::F32);
assert_eq!(*tref.data, f32_bytes(&[1.0, 2.0, 3.0]));
}
#[test]
fn test_materialize_once_fnonce_compile() {
let m = meta("t", vec![1], DType::F32);
let lazy = LazyTensor::from_closure(m, || Ok(f32_bytes(&[42.0])));
let _first = lazy.materialize().unwrap();
}
#[test]
fn test_shape_dtype_no_materialise() {
let counter = Arc::new(AtomicUsize::new(0));
let counter_clone = counter.clone();
let m = meta("guard", vec![4, 8], DType::BF16);
let lazy = LazyTensor::from_closure(m, move || {
counter_clone.fetch_add(1, Ordering::SeqCst);
Ok(vec![0u8; 4 * 8 * 2])
});
for _ in 0..100 {
let _ = lazy.shape();
let _ = lazy.dtype();
let _ = lazy.name();
let _ = lazy.byte_len();
let _ = lazy.meta();
}
assert_eq!(
counter.load(Ordering::SeqCst),
0,
"metadata access must never invoke the materialiser"
);
}
#[test]
fn test_map_compose_idempotent_three_chain() {
let input_eager: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0];
let eager: Vec<f32> = input_eager
.iter()
.map(|x| x * 2.0)
.map(|x| x + 1.0)
.map(|x| -x)
.collect();
let m = meta("chain", vec![4], DType::F32);
let lazy = LazyTensor::from_closure(m, move || Ok(f32_bytes(&input_eager)));
let lazy = lazy.map(|t| {
let mut data = std::sync::Arc::unwrap_or_clone(t.data);
for chunk in data.chunks_exact_mut(4) {
let v = f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]) * 2.0;
chunk.copy_from_slice(&v.to_le_bytes());
}
Ok(TensorRef {
data: std::sync::Arc::new(data),
..t
})
});
let lazy = lazy.map(|t| {
let mut data = std::sync::Arc::unwrap_or_clone(t.data);
for chunk in data.chunks_exact_mut(4) {
let v = f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]) + 1.0;
chunk.copy_from_slice(&v.to_le_bytes());
}
Ok(TensorRef {
data: std::sync::Arc::new(data),
..t
})
});
let lazy = lazy.map(|t| {
let mut data = std::sync::Arc::unwrap_or_clone(t.data);
for chunk in data.chunks_exact_mut(4) {
let v = -f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
chunk.copy_from_slice(&v.to_le_bytes());
}
Ok(TensorRef {
data: std::sync::Arc::new(data),
..t
})
});
let realised = lazy.materialize().unwrap();
let lazy_values: Vec<f32> = realised
.data
.chunks_exact(4)
.map(|c| f32::from_le_bytes([c[0], c[1], c[2], c[3]]))
.collect();
assert_eq!(lazy_values, eager);
}
#[test]
fn test_map_compose_runs_closure_chain_only_at_materialise() {
let parent_counter = Arc::new(AtomicUsize::new(0));
let map1_counter = Arc::new(AtomicUsize::new(0));
let map2_counter = Arc::new(AtomicUsize::new(0));
let parent_clone = parent_counter.clone();
let m = meta("watched", vec![1], DType::F32);
let lazy = LazyTensor::from_closure(m, move || {
parent_clone.fetch_add(1, Ordering::SeqCst);
Ok(f32_bytes(&[7.0]))
});
let map1_clone = map1_counter.clone();
let lazy = lazy.map(move |t| {
map1_clone.fetch_add(1, Ordering::SeqCst);
Ok(t)
});
let map2_clone = map2_counter.clone();
let lazy = lazy.map(move |t| {
map2_clone.fetch_add(1, Ordering::SeqCst);
Ok(t)
});
assert_eq!(parent_counter.load(Ordering::SeqCst), 0);
assert_eq!(map1_counter.load(Ordering::SeqCst), 0);
assert_eq!(map2_counter.load(Ordering::SeqCst), 0);
assert_eq!(lazy.shape(), &[1]);
assert_eq!(parent_counter.load(Ordering::SeqCst), 0);
let _ = lazy.materialize().unwrap();
assert_eq!(parent_counter.load(Ordering::SeqCst), 1);
assert_eq!(map1_counter.load(Ordering::SeqCst), 1);
assert_eq!(map2_counter.load(Ordering::SeqCst), 1);
}
#[test]
fn test_map_with_meta_changes_shape_and_dtype() {
let m_in = meta("dtype-cast", vec![3], DType::F32);
let lazy = LazyTensor::from_closure(m_in, || Ok(f32_bytes(&[1.0, 2.0, 3.0])));
let m_out = meta("dtype-cast", vec![6], DType::F16);
let lazy = lazy.map_with_meta(m_out, |t| {
let mut data = Vec::with_capacity(12);
for chunk in t.data.chunks_exact(4) {
let v = f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
let f16 = half::f16::from_f32(v);
data.extend_from_slice(&f16.to_le_bytes());
data.extend_from_slice(&f16.to_le_bytes());
}
Ok(TensorRef {
name: t.name,
shape: vec![6],
dtype: DType::F16,
data: std::sync::Arc::new(data),
})
});
assert_eq!(lazy.shape(), &[6]);
assert_eq!(lazy.dtype(), DType::F16);
let realised = lazy.materialize().unwrap();
assert_eq!(realised.dtype, DType::F16);
assert_eq!(realised.data.len(), 12);
}
#[test]
fn test_size_mismatch_is_typed_error() {
let m = meta("t", vec![4], DType::F32); let lazy = LazyTensor::from_closure(m, || Ok(vec![0u8; 8])); let err = lazy.materialize().unwrap_err();
match err {
MaterializeError::SizeMismatch {
expected, actual, ..
} => {
assert_eq!(expected, 16);
assert_eq!(actual, 8);
}
_ => panic!("expected SizeMismatch"),
}
}
#[test]
fn test_materialize_io_error_propagates() {
let m = meta("io", vec![1], DType::F32);
let lazy = LazyTensor::from_closure(m, || {
Err(MaterializeError::Io {
name: "io".to_string(),
source: std::io::Error::new(std::io::ErrorKind::NotFound, "synthetic"),
})
});
let err = lazy.materialize().unwrap_err();
match err {
MaterializeError::Io { name, .. } => assert_eq!(name, "io"),
_ => panic!("expected Io"),
}
}
#[test]
fn test_total_size_bytes_matches_post_materialize() {
let mut lazy_map = LazyTensorMap::new();
lazy_map.insert(LazyTensor::from_bytes(
meta("a", vec![2], DType::F32),
vec![0u8; 8],
));
lazy_map.insert(LazyTensor::from_bytes(
meta("b", vec![3, 2], DType::F16),
vec![0u8; 12],
));
lazy_map.insert(LazyTensor::from_bytes(
meta("c", vec![4], DType::BF16),
vec![0u8; 8],
));
lazy_map.insert(LazyTensor::from_bytes(
meta("d", vec![5], DType::U8),
vec![0u8; 5],
));
let lazy_total = lazy_map.total_size_bytes();
let expected = 8 + 12 + 8 + 5;
assert_eq!(
lazy_total, expected,
"lazy total_size_bytes computes byte_len from metadata"
);
let eager = lazy_map.materialize_all().expect("materialize");
assert_eq!(
eager.total_size_bytes(),
lazy_total,
"lazy total_size_bytes must match TensorMap::total_size_bytes \
post-materialize — iter-3 telemetry swap is byte-identical"
);
}
#[test]
fn test_convert_bf16_to_f16_matches_eager() {
fn bf16_bytes(values: &[f32]) -> Vec<u8> {
values
.iter()
.flat_map(|v| half::bf16::from_f32(*v).to_le_bytes())
.collect()
}
fn f16_bytes(values: &[f32]) -> Vec<u8> {
values
.iter()
.flat_map(|v| half::f16::from_f32(*v).to_le_bytes())
.collect()
}
let f32_a = [1.0_f32, 2.0, 3.0, 4.0];
let f32_b = [-1.5_f32, 0.5, 2.5];
let mut lazy = LazyTensorMap::new();
lazy.insert(LazyTensor::from_bytes(
meta("bf16_a", vec![4], DType::BF16),
bf16_bytes(&f32_a),
));
lazy.insert(LazyTensor::from_bytes(
meta("bf16_b", vec![3], DType::BF16),
bf16_bytes(&f32_b),
));
lazy.insert(LazyTensor::from_bytes(
meta("f16_c", vec![3], DType::F16),
f16_bytes(&f32_b),
));
let mut eager = TensorMap::new();
eager.insert(TensorRef {
name: "bf16_a".to_string(),
shape: vec![4],
dtype: DType::BF16,
data: bf16_bytes(&f32_a).into(),
});
eager.insert(TensorRef {
name: "bf16_b".to_string(),
shape: vec![3],
dtype: DType::BF16,
data: bf16_bytes(&f32_b).into(),
});
eager.insert(TensorRef {
name: "f16_c".to_string(),
shape: vec![3],
dtype: DType::F16,
data: f16_bytes(&f32_b).into(),
});
let lazy_count = lazy.convert_bf16_to_f16().expect("lazy convert");
let eager_count = eager.convert_bf16_to_f16().expect("eager convert");
assert_eq!(lazy_count, eager_count, "convert counts equal");
assert_eq!(lazy_count, 2, "exactly two BF16 tensors");
let materialized = lazy.materialize_all().expect("materialize");
for name in ["bf16_a", "bf16_b", "f16_c"] {
let m = materialized
.tensors
.get(name)
.unwrap_or_else(|| panic!("materialized missing {name}"));
let e = eager
.tensors
.get(name)
.unwrap_or_else(|| panic!("eager missing {name}"));
assert_eq!(
m.dtype, e.dtype,
"{name}: dtype must match (BF16 → F16 for converted; F16 unchanged)"
);
assert_eq!(
m.dtype,
DType::F16,
"{name}: post-conversion dtype must be F16"
);
assert_eq!(
m.data, e.data,
"{name}: bytes must equal eager-converted output"
);
}
}
#[test]
fn test_from_arc_bytes_materialize_byte_equal_to_from_bytes() {
use std::sync::Arc;
let m_arc = meta("arc-tensor", vec![3], DType::F32);
let m_vec = meta("arc-tensor", vec![3], DType::F32);
let payload = f32_bytes(&[1.0, 2.0, 3.0]);
let lazy_arc = LazyTensor::from_arc_bytes(m_arc, Arc::new(payload.clone()));
let lazy_vec = LazyTensor::from_bytes(m_vec, payload.clone());
let t_arc = lazy_arc.materialize().expect("arc materialize");
let t_vec = lazy_vec.materialize().expect("vec materialize");
assert_eq!(*t_arc.data, *t_vec.data, "Arc-path bytes equal Vec-path");
assert_eq!(t_arc.shape, t_vec.shape);
assert_eq!(t_arc.dtype, t_vec.dtype);
}
#[test]
fn test_from_arc_bytes_shared_refcount_clones_inner() {
use std::sync::Arc;
let payload = f32_bytes(&[7.0, 8.0]);
let shared: Arc<Vec<u8>> = Arc::new(payload.clone());
let _keepalive = Arc::clone(&shared);
let lazy = LazyTensor::from_arc_bytes(meta("shared", vec![2], DType::F32), shared);
let t = lazy.materialize().expect("shared materialize");
assert_eq!(*t.data, payload, "shared-refcount path returns equal bytes");
}
#[test]
fn materialize_cloned_shares_arc_no_byte_copy() {
use std::sync::Arc;
let payload = f32_bytes(&[1.0, 2.0, 3.0, 4.0]);
let arc: Arc<Vec<u8>> = Arc::new(payload.clone());
let pre_count = Arc::strong_count(&arc);
assert_eq!(pre_count, 1, "test setup: only the test holds the Arc");
let lazy =
LazyTensor::from_arc_bytes(meta("share-test", vec![4], DType::F32), Arc::clone(&arc));
assert_eq!(Arc::strong_count(&arc), 2);
let t = lazy
.materialize_cloned()
.expect("borrowed materialize on shared variant");
assert!(
Arc::ptr_eq(&arc, &t.data),
"materialize_cloned must share the Arc, not deep-clone the Vec"
);
assert!(
Arc::strong_count(&arc) >= 3,
"Arc::strong_count must be >= 3 (caller + lazy + t); got {}",
Arc::strong_count(&arc)
);
assert_eq!(**t.data, *payload);
drop(t);
assert_eq!(Arc::strong_count(&arc), 2);
drop(lazy);
assert_eq!(
Arc::strong_count(&arc),
pre_count,
"post-drop refcount restored — materialize_cloned doesn't leak"
);
}
#[test]
fn materialize_cloned_owned_vec_path_byte_equal() {
use std::sync::Arc;
let payload = f32_bytes(&[5.0, 6.0]);
let lazy = LazyTensor::from_bytes(meta("owned", vec![2], DType::F32), payload.clone());
let t = lazy
.materialize_cloned()
.expect("borrowed materialize on owned variant");
assert_eq!(**t.data, *payload);
assert_eq!(
Arc::strong_count(&t.data),
1,
"owned-Vec variant: returned Arc is fresh (no upstream to share)"
);
}
#[test]
fn test_lazy_tensor_map_btreemap_ordering() {
let mut map = LazyTensorMap::new();
for name in ["zebra", "alpha", "mango", "beta"] {
let m = meta(name, vec![1], DType::F32);
map.insert(LazyTensor::from_closure(m, || Ok(f32_bytes(&[0.0]))));
}
let names: Vec<&String> = map.names().collect();
assert_eq!(names, vec!["alpha", "beta", "mango", "zebra"]);
}
#[test]
fn test_lazy_tensor_map_materialize_all_round_trip() {
let mut map = LazyTensorMap::new();
let m_a = meta("a", vec![2], DType::F32);
map.insert(LazyTensor::from_bytes(m_a, f32_bytes(&[1.0, 2.0])));
let m_b = meta("b", vec![1], DType::F32);
map.insert(LazyTensor::from_bytes(m_b, f32_bytes(&[42.0])));
let eager = map.materialize_all().unwrap();
assert_eq!(eager.len(), 2);
let a = eager.get("a").unwrap();
assert_eq!(a.shape, vec![2]);
assert_eq!(*a.data, f32_bytes(&[1.0, 2.0]));
let b = eager.get("b").unwrap();
assert_eq!(*b.data, f32_bytes(&[42.0]));
}
#[test]
fn test_send_bound() {
fn assert_send<T: Send>() {}
assert_send::<LazyTensor>();
assert_send::<LazyTensorMap>();
assert_send::<LazyMeta>();
assert_send::<MaterializeError>();
}
#[test]
fn test_remove_returns_ownership() {
let mut map = LazyTensorMap::new();
let m = meta("k", vec![1], DType::F32);
map.insert(LazyTensor::from_bytes(m, f32_bytes(&[3.14])));
let owned = map.remove("k").unwrap();
assert_eq!(owned.name(), "k");
assert!(map.get("k").is_none());
let realised = owned.materialize().unwrap();
assert_eq!(*realised.data, f32_bytes(&[3.14]));
}
}