use edgefirst_tensor::{
Colorimetry, CpuAccess, Error, PixelFormat, Tensor, TensorDyn, TensorMapTrait, TensorMemory,
TensorTrait,
};
#[cfg(target_os = "linux")]
fn platform_resource_absent(err: &Error) -> bool {
match err {
Error::IoError(e) => {
matches!(
e.kind(),
std::io::ErrorKind::NotFound | std::io::ErrorKind::PermissionDenied
) || e.to_string().contains("Permission denied")
|| e.to_string().contains("No such file or directory")
}
Error::NotImplemented(msg) => {
msg.contains("Permission denied") || msg.contains("errno 13") || msg.contains("errno 2")
}
_ => false,
}
}
#[test]
fn host_roundtrip_sees_the_same_bytes() {
let t = Tensor::<u8>::image(
64,
32,
PixelFormat::Rgb,
Some(TensorMemory::Mem),
CpuAccess::ReadWrite,
)
.unwrap();
{
let mut m = t.map_write().unwrap();
m.as_mut_slice()[0] = 0xAB;
}
let pin = t.pin_host(CpuAccess::ReadWrite).unwrap();
let dyn_t = TensorDyn::from(t);
let desc = dyn_t.descriptor_pinned(Some(&pin));
let imported = TensorDyn::import_descriptor(&desc).unwrap();
assert_eq!(imported.shape(), dyn_t.shape());
assert_eq!(imported.dtype(), dyn_t.dtype());
assert_eq!(imported.format(), dyn_t.format());
let m = imported.as_u8().unwrap().map_read().unwrap();
assert_eq!(m.as_slice()[0], 0xAB, "import must alias, not copy");
}
#[test]
fn planar_format_round_trips_through_import() {
let t = Tensor::<u8>::image(
640,
480,
PixelFormat::PlanarRgb,
Some(TensorMemory::Mem),
CpuAccess::ReadWrite,
)
.unwrap();
let pin = t.pin_host(CpuAccess::ReadWrite).unwrap();
let dyn_t = TensorDyn::from(t);
let desc = dyn_t.descriptor_pinned(Some(&pin));
assert_eq!(
desc.fourcc, 0,
"precondition: fourcc cannot express PlanarRgb"
);
assert_ne!(
desc.format, 0,
"precondition: format carries the real format"
);
let imported = TensorDyn::import_descriptor(&desc).unwrap();
assert_eq!(
imported.format(),
Some(PixelFormat::PlanarRgb),
"must round-trip via format, not the fourcc==0 sentinel"
);
assert_eq!(imported.shape(), dyn_t.shape());
}
#[test]
fn rejects_unknown_version() {
let t = Tensor::<u8>::new(&[4], None, None).unwrap();
let mut desc = TensorDyn::from(t).descriptor();
desc.version = 9999;
let err = TensorDyn::import_descriptor(&desc).unwrap_err();
assert!(
matches!(err, Error::NotImplemented(_)),
"expected NotImplemented, got {err:?}"
);
}
#[test]
fn rejects_unknown_dtype_code() {
let t = Tensor::<u8>::new(&[4], None, None).unwrap();
let mut desc = TensorDyn::from(t).descriptor();
desc.dtype = 9999;
let err = TensorDyn::import_descriptor(&desc).unwrap_err();
assert!(
matches!(err, Error::NotImplemented(_)),
"expected NotImplemented, got {err:?}"
);
}
#[test]
fn colorimetry_round_trips_through_import() {
let t = Tensor::<u8>::image(
16,
16,
PixelFormat::Rgb,
Some(TensorMemory::Mem),
CpuAccess::ReadWrite,
)
.unwrap();
let pin = t.pin_host(CpuAccess::ReadWrite).unwrap();
let dyn_t = TensorDyn::from(t).with_colorimetry(Colorimetry::jfif());
let desc = dyn_t.descriptor_pinned(Some(&pin));
assert_ne!(desc.colorimetry, 0, "precondition: producer tagged jfif");
let imported = TensorDyn::import_descriptor(&desc).unwrap();
assert_eq!(
imported.colorimetry(),
Some(Colorimetry::jfif()),
"import must unpack desc.colorimetry onto the reconstructed tensor"
);
}
#[test]
fn undefined_colorimetry_imports_as_none() {
let t = Tensor::<u8>::image(
16,
16,
PixelFormat::Rgb,
Some(TensorMemory::Mem),
CpuAccess::ReadWrite,
)
.unwrap();
let pin = t.pin_host(CpuAccess::ReadWrite).unwrap();
let desc = TensorDyn::from(t).descriptor_pinned(Some(&pin));
assert_eq!(desc.colorimetry, 0);
let imported = TensorDyn::import_descriptor(&desc).unwrap();
assert_eq!(imported.colorimetry(), None);
}
#[test]
fn host_import_inherits_the_producers_capacity_headroom() {
let t = Tensor::<u8>::image(
295,
175,
PixelFormat::Nv12,
Some(TensorMemory::Mem),
CpuAccess::ReadWrite,
)
.unwrap();
let producer_capacity = t.capacity_bytes();
let producer_shape_bytes = t.size();
assert!(
producer_capacity > producer_shape_bytes,
"precondition: NV12 at an odd width must pad the allocation beyond \
the logical shape (capacity={producer_capacity}, shape_bytes={producer_shape_bytes})"
);
let pin = t.pin_host(CpuAccess::ReadWrite).unwrap();
let dyn_t = TensorDyn::from(t);
let desc = dyn_t.descriptor_pinned(Some(&pin));
assert_eq!(desc.capacity, producer_capacity as u64);
let imported = TensorDyn::import_descriptor(&desc).unwrap();
assert_eq!(
imported.capacity_bytes(),
producer_capacity,
"the imported alias must inherit the producer's real headroom, not \
just the declared shape's byte size"
);
let mut imported = imported;
imported
.configure_image(295, 175, PixelFormat::Nv12)
.expect("configure_image must fit within the producer's real capacity");
}
#[test]
fn host_import_preserves_the_producers_row_stride_for_pool_reuse() {
let t = Tensor::<u8>::image(
1920,
1080,
PixelFormat::Nv12,
Some(TensorMemory::Mem),
CpuAccess::ReadWrite,
)
.unwrap();
assert_eq!(
t.row_stride(),
Some(1920),
"precondition: semi-planar always records it"
);
let pin = t.pin_host(CpuAccess::ReadWrite).unwrap();
let dyn_t = TensorDyn::from(t);
let desc = dyn_t.descriptor_pinned(Some(&pin));
let mut imported = TensorDyn::import_descriptor(&desc).unwrap();
imported
.configure_image(1280, 720, PixelFormat::Nv12)
.expect("fits within capacity");
assert_eq!(
imported.effective_row_stride(),
Some(1920),
"must preserve the producer's pool-sized pitch, not recompute a \
tighter one that only fits the smaller image"
);
}
#[test]
fn host_import_rejects_a_row_stride_that_would_overflow_capacity() {
let t = Tensor::<u8>::image(
16,
16,
PixelFormat::Rgb,
Some(TensorMemory::Mem),
CpuAccess::ReadWrite,
)
.unwrap();
let pin = t.pin_host(CpuAccess::ReadWrite).unwrap();
let dyn_t = TensorDyn::from(t);
let mut desc = dyn_t.descriptor_pinned(Some(&pin));
let malicious_stride = 1_000_000i64;
desc.strides[0] = malicious_stride;
let imported = TensorDyn::import_descriptor(&desc).unwrap();
assert_ne!(
imported.row_stride(),
Some(malicious_stride as usize),
"an oversized stride must not be trusted just because set_row_stride's \
own validation is a minimum-only check"
);
}
#[test]
fn host_import_without_pin_fails() {
let t = Tensor::<u8>::new(&[4], Some(TensorMemory::Mem), None).unwrap();
let desc = TensorDyn::from(t).descriptor();
let err = TensorDyn::import_descriptor(&desc).unwrap_err();
assert!(
matches!(err, Error::InvalidArgument(_)),
"expected InvalidArgument, got {err:?}"
);
}
#[cfg(not(target_os = "linux"))]
#[test]
fn dmabuf_import_has_no_coverage_off_linux() {
use std::io::Write;
let _ = writeln!(
std::io::stderr(),
"SKIP: TensorDyn::import_descriptor's kind::DMABUF arm is untested on \
this platform (dma-buf is Linux-only). No aliasing coverage for the \
dma-buf import path outside a Linux run."
);
}
#[cfg(target_os = "linux")]
#[test]
fn dmabuf_roundtrip_sees_the_same_bytes() {
let t = match Tensor::<u8>::image(
64,
32,
PixelFormat::Rgb,
Some(TensorMemory::DmaBuf),
CpuAccess::ReadWrite,
) {
Ok(t) => t,
Err(e) if platform_resource_absent(&e) => {
use std::io::Write;
let _ = writeln!(
std::io::stderr(),
"SKIP: dmabuf_roundtrip_sees_the_same_bytes -- this platform has no \
DMA-BUF heap (Tensor::image(.., TensorMemory::DmaBuf, ..) returned \
NotFound); dma-buf allocation is unavailable here, not broken."
);
return;
}
Err(e) => panic!("alloc dma: {e:?}"),
};
{
let mut m = t.map_write().unwrap();
m.as_mut_slice()[0] = 0xEF;
}
let dyn_t = TensorDyn::from(t);
let desc = dyn_t.descriptor(); assert_eq!(desc.kind, edgefirst_tensor::tensor_kind::DMABUF);
let imported = TensorDyn::import_descriptor(&desc).unwrap();
assert_eq!(imported.shape(), dyn_t.shape());
let m = imported.as_u8().unwrap().map_read().unwrap();
assert_eq!(m.as_slice()[0], 0xEF, "dma-buf import must alias, not copy");
}
#[cfg(target_os = "linux")]
#[test]
fn imported_dmabuf_with_a_recorded_stride_is_still_cpu_mappable() {
let owner = match Tensor::<u8>::image(
64,
32,
PixelFormat::Rgb,
Some(TensorMemory::DmaBuf),
CpuAccess::ReadWrite,
) {
Ok(t) => t,
Err(e) if platform_resource_absent(&e) => {
use std::io::Write;
let _ = writeln!(
std::io::stderr(),
"SKIP: imported_dmabuf_with_a_recorded_stride_is_still_cpu_mappable -- \
this platform has no DMA-BUF heap; dma-buf allocation is unavailable \
here, not broken."
);
return;
}
Err(e) => panic!("alloc dma: {e:?}"),
};
let fd = TensorTrait::clone_fd(&owner).expect("clone dma-buf fd");
let mut imported = Tensor::<u8>::from_fd(fd, &[32, 64, 3], None).expect("import via from_fd");
imported.set_format(PixelFormat::Rgb).expect("set_format");
imported
.set_row_stride(64 * 3)
.expect("set_row_stride: a HAL-computed pitch for the import's own format/width");
{
let mut m = imported.map_write().expect(
"a HAL-computed, capacity-bounded stride must not be rejected on an imported \
DMA-BUF -- that is exactly the write path a cross-package decode takes",
);
m.as_mut_slice()[0] = 0xAB;
}
let m = owner
.map_read()
.expect("read back through the owning tensor");
assert_eq!(
m.as_slice()[0],
0xAB,
"write through the imported, now-strided alias must be visible to the owner"
);
}
#[cfg(target_os = "linux")]
#[test]
fn dmabuf_import_preserves_the_producers_row_stride_for_pool_reuse() {
let t = match Tensor::<u8>::image(
1920,
1080,
PixelFormat::Nv12,
Some(TensorMemory::DmaBuf),
CpuAccess::ReadWrite,
) {
Ok(t) => t,
Err(e) if platform_resource_absent(&e) => {
use std::io::Write;
let _ = writeln!(
std::io::stderr(),
"SKIP: dmabuf_import_preserves_the_producers_row_stride_for_pool_reuse -- \
this platform has no DMA-BUF heap; dma-buf allocation is unavailable \
here, not broken."
);
return;
}
Err(e) => panic!("alloc dma: {e:?}"),
};
assert_eq!(
t.row_stride(),
Some(1920),
"precondition: semi-planar always records it"
);
let dyn_t = TensorDyn::from(t);
let desc = dyn_t.descriptor();
let mut imported = TensorDyn::import_descriptor(&desc).unwrap();
imported
.configure_image(1280, 720, PixelFormat::Nv12)
.expect("fits within capacity");
assert_eq!(
imported.effective_row_stride(),
Some(1920),
"must preserve the producer's pool-sized pitch, not recompute a tighter one \
that only fits the smaller image"
);
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[test]
fn iosurface_roundtrip_sees_the_same_bytes() {
let t = Tensor::<u8>::image(
64,
32,
PixelFormat::Rgb,
Some(TensorMemory::DmaBuf),
CpuAccess::ReadWrite,
)
.unwrap();
{
let mut m = t.map_write().unwrap();
m.as_mut_slice()[0] = 0xCD;
}
let dyn_t = TensorDyn::from(t);
let desc = dyn_t.descriptor(); assert_eq!(desc.kind, edgefirst_tensor::tensor_kind::IOSURFACE);
let imported = TensorDyn::import_descriptor(&desc).unwrap();
assert_eq!(imported.shape(), dyn_t.shape());
assert_eq!(
imported.row_stride(),
None,
"a non-HOST (Dma) import must not have row_stride set by the HOST-only \
restoration path"
);
let m = imported.as_u8().unwrap().map_read().unwrap();
assert_eq!(
m.as_slice()[0],
0xCD,
"IOSurface import must alias, not copy"
);
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[test]
fn iosurface_import_rejects_dead_id() {
let t = Tensor::<u8>::image(
16,
16,
PixelFormat::Grey,
Some(TensorMemory::DmaBuf),
CpuAccess::ReadWrite,
)
.unwrap();
let mut desc = TensorDyn::from(t).descriptor();
desc.handle = 0x7FFF_FFFF; let err = TensorDyn::import_descriptor(&desc).unwrap_err();
assert!(
matches!(err, Error::InvalidArgument(_)),
"expected InvalidArgument, got {err:?}"
);
}
#[test]
fn import_refuses_a_descriptor_advertising_an_unwaitable_fence() {
let t = Tensor::<u8>::image(
16,
8,
PixelFormat::Rgb,
Some(TensorMemory::Mem),
CpuAccess::ReadWrite,
)
.expect("alloc");
let pin = t.pin_host(CpuAccess::ReadWrite).unwrap();
let dyn_t = TensorDyn::from(t);
let mut desc = dyn_t.descriptor_pinned(Some(&pin));
TensorDyn::import_descriptor(&desc).expect("clean descriptor imports");
desc.flags |= edgefirst_tensor::protocol::flags::SYNC_PRESENT;
let err = TensorDyn::import_descriptor(&desc)
.expect_err("a descriptor advertising SYNC_PRESENT must be refused");
let msg = format!("{err}");
assert!(
msg.contains("SYNC_PRESENT"),
"the error must name what it refused, got: {msg}"
);
}