#![allow(dead_code)]
use std::sync::Arc;
use crate::types::{PixelFormat, Timestamp};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FrameMetadata {
pub width: u32,
pub height: u32,
pub format: PixelFormat,
pub timestamp: Timestamp,
}
#[derive(Debug, Clone)]
pub struct SharedFrameBuffer {
inner: Arc<[u8]>,
}
impl SharedFrameBuffer {
#[must_use]
pub fn from_slice(data: &[u8]) -> Self {
Self {
inner: Arc::from(data),
}
}
#[must_use]
pub fn from_vec(data: Vec<u8>) -> Self {
Self {
inner: Arc::from(data.into_boxed_slice()),
}
}
#[must_use]
pub fn data(&self) -> &[u8] {
&self.inner
}
#[must_use]
pub fn len(&self) -> usize {
self.inner.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[must_use]
pub fn ref_count(&self) -> usize {
Arc::strong_count(&self.inner)
}
#[must_use]
pub fn slice(&self, start: usize, end: usize) -> SharedFrameSlice {
assert!(start <= end, "slice start must be <= end");
assert!(end <= self.len(), "slice end out of bounds");
SharedFrameSlice {
buffer: self.clone(),
start,
end,
}
}
}
#[derive(Debug, Clone)]
pub struct SharedFrameSlice {
buffer: SharedFrameBuffer,
start: usize,
end: usize,
}
impl SharedFrameSlice {
#[must_use]
pub fn data(&self) -> &[u8] {
&self.buffer.data()[self.start..self.end]
}
#[must_use]
pub fn len(&self) -> usize {
self.end - self.start
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.start == self.end
}
#[must_use]
pub fn offset(&self) -> usize {
self.start
}
#[must_use]
pub fn ref_count(&self) -> usize {
self.buffer.ref_count()
}
}
#[derive(Debug)]
pub struct MutableFrameBuffer {
data: Vec<u8>,
}
impl MutableFrameBuffer {
#[must_use]
pub fn new(size: usize) -> Self {
Self {
data: vec![0u8; size],
}
}
#[must_use]
pub fn from_vec(data: Vec<u8>) -> Self {
Self { data }
}
#[must_use]
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn data_mut(&mut self) -> &mut [u8] {
&mut self.data
}
#[must_use]
pub fn len(&self) -> usize {
self.data.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[must_use]
pub fn freeze(self) -> SharedFrameBuffer {
SharedFrameBuffer::from_vec(self.data)
}
}
#[derive(Debug, Clone)]
pub struct SharedFrame {
buffer: SharedFrameBuffer,
pub meta: FrameMetadata,
}
impl SharedFrame {
#[must_use]
pub fn new(buffer: SharedFrameBuffer, meta: FrameMetadata) -> Self {
Self { buffer, meta }
}
#[must_use]
pub fn data(&self) -> &[u8] {
self.buffer.data()
}
#[must_use]
pub fn len(&self) -> usize {
self.buffer.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
#[must_use]
pub fn ref_count(&self) -> usize {
self.buffer.ref_count()
}
#[must_use]
pub fn buffer(&self) -> &SharedFrameBuffer {
&self.buffer
}
#[must_use]
pub fn slice(&self, start: usize, end: usize) -> SharedFrameSlice {
self.buffer.slice(start, end)
}
pub fn try_into_mutable(self) -> Result<MutableFrameBuffer, Self> {
if Arc::strong_count(&self.buffer.inner) == 1 {
let data = self.buffer.inner.to_vec();
Ok(MutableFrameBuffer::from_vec(data))
} else {
Err(self)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{PixelFormat, Rational, Timestamp};
fn make_meta() -> FrameMetadata {
FrameMetadata {
width: 4,
height: 4,
format: PixelFormat::Rgb24,
timestamp: Timestamp::new(0, Rational::new(1, 30)),
}
}
#[test]
fn test_shared_buffer_from_slice() {
let buf = SharedFrameBuffer::from_slice(&[1, 2, 3, 4]);
assert_eq!(buf.len(), 4);
assert_eq!(buf.data(), &[1, 2, 3, 4]);
}
#[test]
fn test_shared_buffer_from_vec() {
let v = vec![10u8, 20, 30];
let buf = SharedFrameBuffer::from_vec(v);
assert_eq!(buf.len(), 3);
assert_eq!(buf.data()[1], 20);
}
#[test]
fn test_shared_buffer_ref_count() {
let buf = SharedFrameBuffer::from_slice(&[0u8; 16]);
assert_eq!(buf.ref_count(), 1);
let clone = buf.clone();
assert_eq!(buf.ref_count(), 2);
assert_eq!(clone.ref_count(), 2);
drop(clone);
assert_eq!(buf.ref_count(), 1);
}
#[test]
fn test_shared_buffer_slice() {
let buf = SharedFrameBuffer::from_slice(&[0, 1, 2, 3, 4, 5]);
let slice = buf.slice(2, 5);
assert_eq!(slice.data(), &[2, 3, 4]);
assert_eq!(slice.len(), 3);
assert_eq!(slice.offset(), 2);
}
#[test]
fn test_slice_shares_ref_count() {
let buf = SharedFrameBuffer::from_slice(&[0u8; 8]);
let slice = buf.slice(0, 4);
assert_eq!(buf.ref_count(), 2);
drop(slice);
assert_eq!(buf.ref_count(), 1);
}
#[test]
fn test_empty_slice() {
let buf = SharedFrameBuffer::from_slice(&[1, 2, 3]);
let slice = buf.slice(1, 1);
assert!(slice.is_empty());
assert_eq!(slice.len(), 0);
}
#[test]
fn test_mutable_buffer_new_zeroed() {
let mbuf = MutableFrameBuffer::new(8);
assert_eq!(mbuf.len(), 8);
assert!(mbuf.data().iter().all(|&b| b == 0));
}
#[test]
fn test_mutable_buffer_freeze() {
let mut mbuf = MutableFrameBuffer::new(4);
mbuf.data_mut().copy_from_slice(&[10, 20, 30, 40]);
let shared = mbuf.freeze();
assert_eq!(shared.data(), &[10, 20, 30, 40]);
assert_eq!(shared.ref_count(), 1);
}
#[test]
fn test_shared_frame_new() {
let buf = SharedFrameBuffer::from_slice(&[1u8; 48]); let frame = SharedFrame::new(buf, make_meta());
assert_eq!(frame.len(), 48);
assert_eq!(frame.meta.width, 4);
}
#[test]
fn test_shared_frame_clone_no_copy() {
let mut mbuf = MutableFrameBuffer::new(12);
mbuf.data_mut().fill(0xAB);
let shared_buf = mbuf.freeze();
let frame = SharedFrame::new(shared_buf, make_meta());
assert_eq!(frame.ref_count(), 1);
let clone = frame.clone();
assert_eq!(frame.ref_count(), 2);
assert_eq!(clone.ref_count(), 2);
assert_eq!(clone.data()[0], 0xAB);
}
#[test]
fn test_shared_frame_slice() {
let data: Vec<u8> = (0..12).collect();
let buf = SharedFrameBuffer::from_vec(data);
let frame = SharedFrame::new(buf, make_meta());
let slice = frame.slice(4, 8);
assert_eq!(slice.data(), &[4, 5, 6, 7]);
}
#[test]
fn test_try_into_mutable_success() {
let buf = SharedFrameBuffer::from_slice(&[1, 2, 3]);
let frame = SharedFrame::new(buf, make_meta());
let mutable = frame.try_into_mutable().expect("should succeed");
assert_eq!(mutable.data(), &[1, 2, 3]);
}
#[test]
fn test_try_into_mutable_fails_with_clone() {
let buf = SharedFrameBuffer::from_slice(&[7, 8, 9]);
let frame = SharedFrame::new(buf, make_meta());
let _clone = frame.clone();
let result = frame.try_into_mutable();
assert!(result.is_err());
}
#[test]
fn test_shared_buffer_is_empty() {
let empty = SharedFrameBuffer::from_slice(&[]);
assert!(empty.is_empty());
let nonempty = SharedFrameBuffer::from_slice(&[1]);
assert!(!nonempty.is_empty());
}
#[test]
fn test_mutable_buffer_from_vec() {
let mbuf = MutableFrameBuffer::from_vec(vec![5, 10, 15]);
assert_eq!(mbuf.len(), 3);
assert_eq!(mbuf.data()[2], 15);
}
}