Skip to main content

cjc_runtime/
buffer.rs

1use std::cell::{Ref, RefCell};
2use std::rc::Rc;
3
4use crate::error::RuntimeError;
5
6// ---------------------------------------------------------------------------
7// 1. Buffer<T> — Deterministic memory allocation with COW semantics
8// ---------------------------------------------------------------------------
9
10/// A reference-counted buffer with copy-on-write semantics.
11///
12/// Internally backed by `Rc<RefCell<Vec<T>>>`. When multiple `Buffer`s share
13/// the same underlying storage, a mutation via [`Buffer::set`] or
14/// [`Buffer::make_unique`] triggers a deep copy so that other holders are
15/// unaffected.
16#[derive(Debug)]
17pub struct Buffer<T: Clone> {
18    inner: Rc<RefCell<Vec<T>>>,
19}
20
21impl<T: Clone> Buffer<T> {
22    /// Allocate a buffer of `len` elements, each initialized to `default`.
23    pub fn alloc(len: usize, default: T) -> Self {
24        Buffer {
25            inner: Rc::new(RefCell::new(vec![default; len])),
26        }
27    }
28
29    /// Create a buffer from an existing `Vec<T>`.
30    pub fn from_vec(data: Vec<T>) -> Self {
31        Buffer {
32            inner: Rc::new(RefCell::new(data)),
33        }
34    }
35
36    /// Number of elements in the buffer.
37    pub fn len(&self) -> usize {
38        self.inner.borrow().len()
39    }
40
41    /// Whether the buffer is empty.
42    pub fn is_empty(&self) -> bool {
43        self.inner.borrow().is_empty()
44    }
45
46    /// Read the value at `idx`. Returns `None` if out of bounds.
47    pub fn get(&self, idx: usize) -> Option<T> {
48        self.inner.borrow().get(idx).cloned()
49    }
50
51    /// Write `val` at `idx`. If the buffer is shared (refcount > 1), a deep
52    /// copy is performed first (COW). Returns `Err` if `idx` is out of bounds.
53    pub fn set(&mut self, idx: usize, val: T) -> Result<(), RuntimeError> {
54        self.make_unique();
55        let mut vec = self.inner.borrow_mut();
56        if idx >= vec.len() {
57            return Err(RuntimeError::IndexOutOfBounds {
58                index: idx,
59                length: vec.len(),
60            });
61        }
62        vec[idx] = val;
63        Ok(())
64    }
65
66    /// Return a snapshot of the data as a `Vec<T>`.
67    pub fn as_slice(&self) -> Vec<T> {
68        self.inner.borrow().clone()
69    }
70
71    /// Borrow the underlying Vec without cloning.
72    /// The returned `Ref` guard keeps the borrow alive.
73    pub fn borrow_data(&self) -> Ref<Vec<T>> {
74        self.inner.borrow()
75    }
76
77    /// Force a deep copy, returning a new `Buffer` that does not share
78    /// storage with `self`.
79    pub fn clone_buffer(&self) -> Buffer<T> {
80        Buffer {
81            inner: Rc::new(RefCell::new(self.inner.borrow().clone())),
82        }
83    }
84
85    /// Ensure this `Buffer` has exclusive ownership of the underlying data.
86    /// If the refcount is > 1, the data is deep-copied and this `Buffer` is
87    /// re-pointed to the fresh copy.
88    pub fn make_unique(&mut self) {
89        if Rc::strong_count(&self.inner) > 1 {
90            let data = self.inner.borrow().clone();
91            self.inner = Rc::new(RefCell::new(data));
92        }
93    }
94
95    /// Number of live references to the underlying storage.
96    pub fn refcount(&self) -> usize {
97        Rc::strong_count(&self.inner)
98    }
99}
100
101impl<T: Clone> Clone for Buffer<T> {
102    /// Cloning a `Buffer` increments the refcount — it does NOT copy data.
103    fn clone(&self) -> Self {
104        Buffer {
105            inner: Rc::clone(&self.inner),
106        }
107    }
108}
109