Skip to main content

compressed_intvec/fixed/
proxy.rs

1//! # Mutable Access Proxy
2//!
3//! This module defines [`MutProxy`], a temporary proxy object that enables
4//! ergonomic, index-like mutable access to elements within a [`FixedVec`].
5//!
6//! Because [`FixedVec`] stores its elements in a compressed, bit-packed format,
7//! it is not possible to return a direct mutable reference (`&mut T`) to an
8//! element. Instead, methods like [`at_mut`](super::FixedVec::at_mut) return a
9//! [`MutProxy`]. This proxy holds a temporary, decoded copy of an element's value.
10//! When the proxy is dropped (goes out of scope), its [`Drop`] implementation
11//! automatically writes the (potentially modified) value back into the vector.
12//!
13//! # Examples
14//!
15//! ```
16//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
17//! use compressed_intvec::fixed::{FixedVec, UFixedVec, BitWidth};
18//!
19//! let data: &[u32] = &[10, 20, 30];
20//! let mut vec: UFixedVec<u32> = FixedVec::builder().bit_width(BitWidth::Explicit(7)).build(data)?;
21//!
22//! // Get a mutable proxy for the element at index 1.
23//! if let Some(mut proxy) = vec.at_mut(1) {
24//!     // DerefMut allows us to modify the value.
25//!     *proxy = 99;
26//! } // The proxy is dropped here, and the new value is written back.
27//!
28//! assert_eq!(vec.get(1), Some(99));
29//! # Ok(())
30//! # }
31//! ```
32
33use super::{
34    traits::{Storable, Word},
35    FixedVec,
36};
37use dsi_bitstream::prelude::Endianness;
38use std::{
39    fmt,
40    mem,
41    ops::{Deref, DerefMut},
42};
43
44/// A proxy object for mutable access to an element within a [`FixedVec`].
45///
46/// This struct is returned by [`FixedVec::at_mut`]. It holds a temporary copy
47/// of an element's value. When the proxy is dropped, its [`Drop`] implementation
48/// writes the (potentially modified) value back into the parent vector.
49/// This "copy-on-read, write-on-drop" mechanism allows for an API that feels
50/// like direct mutable access.
51pub struct MutProxy<'a, T, W, E, B>
52where
53    T: Storable<W>,
54    W: Word,
55    E: Endianness,
56    B: AsRef<[W]> + AsMut<[W]>,
57{
58    /// A mutable reference to the parent vector.
59    vec: &'a mut FixedVec<T, W, E, B>,
60    /// The index of the element being accessed.
61    index: usize,
62    /// A temporary, decoded copy of the element's value.
63    value: T,
64}
65
66impl<T, W, E, B> fmt::Debug for MutProxy<'_, T, W, E, B>
67where
68    T: Storable<W> + fmt::Debug,
69    W: Word,
70    E: Endianness,
71    B: AsRef<[W]> + AsMut<[W]>,
72{
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        f.debug_struct("MutProxy")
75            .field("index", &self.index)
76            .field("value", &self.value)
77            .finish()
78    }
79}
80
81impl<'a, T, W, E, B> MutProxy<'a, T, W, E, B>
82where
83    T: Storable<W>,
84    W: Word,
85    E: Endianness,
86    B: AsRef<[W]> + AsMut<[W]>,
87{
88    /// Creates a new [`MutProxy`].
89    ///
90    /// This is called by [`at_mut`](FixedVec::at_mut). It reads the initial value
91    /// from the vector and stores it in the `value` field.
92    pub(super) fn new(vec: &'a mut FixedVec<T, W, E, B>, index: usize) -> Self {
93        let value = vec
94            .get(index)
95            .expect("Index out of bounds in MutProxy creation");
96        Self { vec, index, value }
97    }
98
99    /// Consumes the proxy, returning the current value without writing it back.
100    ///
101    /// This can be used to avoid the overhead of a write operation if the value
102    /// was read but not modified.
103    pub fn into_inner(self) -> T {
104        // Take ownership of the value.
105        let value = self.value;
106        // Prevent the Drop implementation from running, thus skipping the write-back.
107        mem::forget(self);
108        value
109    }
110}
111
112impl<T, W, E, B> Deref for MutProxy<'_, T, W, E, B>
113where
114    T: Storable<W>,
115    W: Word,
116    E: Endianness,
117    B: AsRef<[W]> + AsMut<[W]>,
118{
119    type Target = T;
120
121    /// Returns a reference to the temporary value held by the proxy.
122    fn deref(&self) -> &Self::Target {
123        &self.value
124    }
125}
126
127impl<T, W, E, B> DerefMut for MutProxy<'_, T, W, E, B>
128where
129    T: Storable<W>,
130    W: Word,
131    E: Endianness,
132    B: AsRef<[W]> + AsMut<[W]>,
133{
134    /// Returns a mutable reference to the temporary value, allowing modification.
135    fn deref_mut(&mut self) -> &mut Self::Target {
136        &mut self.value
137    }
138}
139
140impl<T, W, E, B> Drop for MutProxy<'_, T, W, E, B>
141where
142    T: Storable<W>,
143    W: Word,
144    E: Endianness,
145    B: AsRef<[W]> + AsMut<[W]>,
146{
147    /// Writes the potentially modified value back to the [`FixedVec`] when the
148    /// proxy goes out of scope.
149    fn drop(&mut self) {
150        // The `value` field is copied here before being passed to `set`.
151        // `set` will handle re-encoding the value and writing it to the bit buffer.
152        self.vec.set(self.index, self.value);
153    }
154}