revm_state/
account_extension.rs1use core::{cmp::Ordering, ops::Deref};
4use primitives::Bytes;
5use std::vec::Vec;
6use triomphe::ThinArc;
7
8#[derive(Clone, Debug, Default)]
16pub struct AccountExtension(Option<ThinArc<(), u8>>);
17
18impl AccountExtension {
19 pub fn from_shared(payload: Option<ThinArc<(), u8>>) -> Self {
21 Self(payload.filter(|arc| !arc.slice.is_empty()))
22 }
23
24 pub fn into_shared(self) -> Option<ThinArc<(), u8>> {
26 self.0
27 }
28
29 pub const fn new() -> Self {
31 Self(None)
32 }
33
34 pub fn copy_from_slice(bytes: &[u8]) -> Self {
36 Self((!bytes.is_empty()).then(|| ThinArc::from_header_and_slice((), bytes)))
37 }
38
39 pub fn new_with(len: usize, write: impl FnOnce(&mut [u8])) -> Self {
43 if len == 0 {
44 write(&mut []);
45 return Self::new();
46 }
47 let mut arc = ThinArc::from_header_and_iter((), core::iter::repeat_n(0, len));
48 arc.with_arc_mut(|arc| {
49 let unique = triomphe::Arc::get_mut(arc).expect("new allocation is unique");
50 write(unique.slice_mut());
51 });
52 Self(Some(arc))
53 }
54
55 pub const fn is_empty(&self) -> bool {
57 self.0.is_none()
58 }
59}
60
61impl AsRef<[u8]> for AccountExtension {
62 fn as_ref(&self) -> &[u8] {
63 self.0.as_ref().map_or(&[], |arc| &arc.slice)
64 }
65}
66
67impl Deref for AccountExtension {
68 type Target = [u8];
69 fn deref(&self) -> &[u8] {
70 self.as_ref()
71 }
72}
73
74impl From<Bytes> for AccountExtension {
75 fn from(bytes: Bytes) -> Self {
76 Self::copy_from_slice(&bytes)
77 }
78}
79
80impl From<Vec<u8>> for AccountExtension {
81 fn from(bytes: Vec<u8>) -> Self {
82 Self::copy_from_slice(&bytes)
83 }
84}
85
86impl PartialEq for AccountExtension {
87 fn eq(&self, other: &Self) -> bool {
88 self.0 == other.0
89 }
90}
91impl Eq for AccountExtension {}
92
93impl core::hash::Hash for AccountExtension {
94 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
95 core::hash::Hash::hash(self.as_ref(), state);
96 }
97}
98
99impl PartialOrd for AccountExtension {
100 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
101 Some(self.cmp(other))
102 }
103}
104
105impl Ord for AccountExtension {
106 fn cmp(&self, other: &Self) -> Ordering {
107 self.as_ref().cmp(other.as_ref())
109 }
110}
111
112#[cfg(feature = "serde")]
113impl serde::Serialize for AccountExtension {
114 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
115 if serializer.is_human_readable() {
116 primitives::hex::serialize(self.as_ref(), serializer)
117 } else {
118 serializer.serialize_bytes(self.as_ref())
119 }
120 }
121}
122
123#[cfg(feature = "serde")]
124impl<'de> serde::Deserialize<'de> for AccountExtension {
125 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
126 Bytes::deserialize(deserializer).map(Self::from)
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn shared_payload_and_in_place_encoding() {
136 assert_eq!(size_of::<AccountExtension>(), size_of::<usize>());
137 let payload = AccountExtension::new_with(32, |out| out.fill(42));
138 let cloned = payload.clone();
139 assert_eq!(payload.as_ref(), &[42; 32]);
140 assert_eq!(payload.as_ptr(), cloned.as_ptr());
141 assert_eq!(payload, AccountExtension::copy_from_slice(&[42; 32]));
142 assert!(AccountExtension::new_with(0, |out| assert!(out.is_empty())).is_empty());
143 assert!(
144 AccountExtension::copy_from_slice(&[0, 255]) < AccountExtension::copy_from_slice(&[1])
145 );
146 }
147
148 #[test]
149 #[cfg(feature = "serde")]
150 fn byte_wire_format() {
151 for payload in [&[][..], &[0x82, 0xaa][..], &[42; 256][..]] {
152 let bytes = Bytes::copy_from_slice(payload);
153 let extension = AccountExtension::from(bytes.clone());
154 let json = serde_json::to_vec(&bytes).unwrap();
155 assert_eq!(serde_json::to_vec(&extension).unwrap(), json);
156 assert_eq!(
157 serde_json::from_slice::<AccountExtension>(&json).unwrap(),
158 extension
159 );
160 let binary = postcard::to_allocvec(&bytes).unwrap();
161 assert_eq!(postcard::to_allocvec(&extension).unwrap(), binary);
162 assert_eq!(
163 postcard::from_bytes::<AccountExtension>(&binary).unwrap(),
164 extension
165 );
166 let pair = (extension.clone(), 42u8);
167 let encoded = postcard::to_allocvec(&pair).unwrap();
168 assert_eq!(
169 postcard::from_bytes::<(AccountExtension, u8)>(&encoded).unwrap(),
170 pair
171 );
172 if !payload.is_empty() {
173 assert!(
174 postcard::from_bytes::<AccountExtension>(&binary[..binary.len() - 1]).is_err()
175 );
176 }
177 }
178 }
179}