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