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}