jam_std_common/util/
immutable.rs1use crate::{BytesCursor, RecordedInput, hash_raw};
2use bytes::Bytes;
3use castaway::cast;
4use codec::{Decode, Encode, Input, MaxEncodedLen};
5use jam_types::{Hash, Wrap};
6use std::{borrow::Borrow, ops::Deref};
7
8pub trait HashOrNoHash {
12 fn hash(data: &[u8]) -> Self;
14}
15
16#[derive(Clone, Copy, Debug)]
17pub struct NoHash;
18
19impl HashOrNoHash for NoHash {
20 fn hash(_data: &[u8]) -> Self {
21 Self
22 }
23}
24
25impl<T: From<Hash>> HashOrNoHash for T {
26 fn hash(data: &[u8]) -> Self {
27 hash_raw(data).into()
28 }
29}
30
31#[derive(Clone, Debug)]
36pub struct Immutable<T, H = NoHash> {
37 value: T,
38 encoded: Bytes,
40 hash: H,
42}
43
44impl<T, H: HashOrNoHash> Immutable<T, H> {
45 pub fn from_parts(value: T, hash: H, encoded: Bytes) -> Self {
47 Self { value, encoded, hash }
48 }
49
50 pub fn from_value_and_encoded(value: T, encoded: Bytes) -> Self {
52 let hash = H::hash(&encoded);
53 Self { value, encoded, hash }
54 }
55
56 pub fn encoded(&self) -> &Bytes {
58 &self.encoded
59 }
60
61 pub fn encoded_len(&self) -> usize {
63 self.encoded.len()
64 }
65
66 pub fn into_value(self) -> T {
68 self.value
69 }
70
71 #[allow(dead_code)]
73 pub fn into_encoded(self) -> Bytes {
74 self.encoded
75 }
76
77 pub fn into_value_and_encoded(self) -> (T, Bytes) {
79 (self.value, self.encoded)
80 }
81
82 pub fn into_parts(self) -> (T, Bytes, H) {
84 (self.value, self.encoded, self.hash)
85 }
86}
87
88impl<T, H: Into<Hash> + Copy> Immutable<T, H> {
90 pub fn hash(&self) -> H {
92 self.hash
93 }
94}
95
96impl<T: Encode, H: HashOrNoHash> From<T> for Immutable<T, H> {
98 fn from(value: T) -> Self {
99 let encoded = value.encode().into();
100 Self::from_value_and_encoded(value, encoded)
101 }
102}
103
104impl<T: Encode, H: HashOrNoHash> Immutable<T, H> {
105 pub fn modify_and_encode(&mut self, f: impl FnOnce(&mut T)) {
106 f(&mut self.value);
107 self.encoded = self.value.encode().into();
108 self.hash = H::hash(&self.encoded);
109 }
110}
111
112impl<T, H> Deref for Immutable<T, H> {
113 type Target = T;
114
115 fn deref(&self) -> &T {
116 &self.value
117 }
118}
119
120impl<T, H> Borrow<T> for Immutable<T, H> {
121 fn borrow(&self) -> &T {
122 &self.value
123 }
124}
125
126impl<T: Decode, H: HashOrNoHash> Decode for Immutable<T, H> {
127 fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
128 let (value, encoded) = match cast!(input, &mut BytesCursor) {
129 Ok(input) => {
130 let mut encoded = input.remaining().clone();
131 let value = T::decode(input)?;
132 encoded.truncate(encoded.len() - input.infallible_remaining_len());
133 (value, encoded)
134 },
135 Err(input) => {
136 let mut input = RecordedInput::new(input);
137 let value = T::decode(&mut input)?;
138 debug_assert!(!input.failed());
139 let encoded: Vec<_> = input.into_record();
140 (value, encoded.into())
141 },
142 };
143 let hash = H::hash(&encoded);
144 Ok(Self { value, encoded, hash })
145 }
146
147 fn skip<I: Input>(input: &mut I) -> Result<(), codec::Error> {
148 T::skip(input)
149 }
150
151 fn encoded_fixed_size() -> Option<usize> {
152 T::encoded_fixed_size()
153 }
154}
155
156impl<T, H> Encode for Immutable<T, H> {
157 fn size_hint(&self) -> usize {
158 self.encoded.len()
159 }
160
161 fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
162 f(&self.encoded)
163 }
164
165 fn encoded_size(&self) -> usize {
166 self.encoded.len()
167 }
168}
169
170impl<T: MaxEncodedLen, H> MaxEncodedLen for Immutable<T, H> {
171 fn max_encoded_len() -> usize {
172 T::max_encoded_len()
173 }
174}
175
176#[derive(Clone, Debug)]
179pub struct ImmutableWrap;
180
181impl Wrap for ImmutableWrap {
182 type Wrap<T> = Immutable<T>;
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use codec::DecodeAll;
189 use jam_types::NoWrap;
190
191 #[derive(Encode, Decode, Debug, PartialEq, Eq)]
192 struct Inner(Bytes);
193
194 #[derive(Encode, Decode, Debug, PartialEq, Eq)]
195 struct WrappedOuter<W: Wrap> {
196 a: W::Wrap<Inner>,
197 b: W::Wrap<Inner>,
198 }
199
200 type Outer = WrappedOuter<NoWrap>;
201 type ImmutableOuter = Immutable<WrappedOuter<ImmutableWrap>, Hash>;
202
203 fn contains(outer: &[u8], inner: &[u8]) -> bool {
204 let outer = outer.as_ptr_range();
205 let inner = inner.as_ptr_range();
206 (outer.start <= inner.start) && (inner.end <= outer.end)
207 }
208
209 #[test]
210 fn basic_operation() {
211 let outer =
212 Outer { a: Inner(Bytes::from_static(b"polka")), b: Inner(Bytes::from_static(b"jam!")) };
213 let encoded_outer = outer.encode();
214 assert_eq!(outer, Outer::decode_all(&mut encoded_outer.as_slice()).unwrap());
215
216 let encoded_outer = Bytes::from(encoded_outer);
217 let immutable_outer: ImmutableOuter =
218 BytesCursor::from(encoded_outer.clone()).decode_all().unwrap();
219 assert_eq!(immutable_outer.a.0, outer.a.0);
220 assert_eq!(immutable_outer.b.0, outer.b.0);
221 assert_eq!(immutable_outer.encoded(), &encoded_outer);
222 assert_eq!(immutable_outer.hash(), hash_raw(&encoded_outer));
223 assert_eq!(immutable_outer.a.encoded(), &outer.a.encode());
224 assert_eq!(immutable_outer.b.encoded(), &outer.b.encode());
225 assert!(contains(&encoded_outer, immutable_outer.encoded()));
226 assert!(contains(&encoded_outer, immutable_outer.a.encoded()));
227 assert!(contains(&encoded_outer, immutable_outer.b.encoded()));
228 assert!(contains(&encoded_outer, &immutable_outer.a.0));
229 assert!(contains(&encoded_outer, &immutable_outer.b.0));
230 }
231}