fuel_compression/
impls.rs

1//! Trait impls for Rust types
2
3use super::traits::*;
4use crate::RegistryKey;
5use core::mem::MaybeUninit;
6use fuel_types::{
7    Address,
8    AssetId,
9    BlobId,
10    BlockHeight,
11    Bytes32,
12    ContractId,
13    Nonce,
14    Salt,
15};
16
17macro_rules! identity_compression {
18    ($t:ty) => {
19        impl Compressible for $t {
20            type Compressed = Self;
21        }
22
23        impl<Ctx> CompressibleBy<Ctx> for $t
24        where
25            Ctx: ContextError,
26        {
27            async fn compress_with(&self, _: &mut Ctx) -> Result<Self, Ctx::Error> {
28                Ok(*self)
29            }
30        }
31
32        impl<Ctx> DecompressibleBy<Ctx> for $t
33        where
34            Ctx: ContextError,
35        {
36            async fn decompress_with(
37                c: Self::Compressed,
38                _: &Ctx,
39            ) -> Result<Self, Ctx::Error> {
40                Ok(c)
41            }
42        }
43    };
44}
45
46identity_compression!(u8);
47identity_compression!(u16);
48identity_compression!(u32);
49identity_compression!(u64);
50identity_compression!(u128);
51
52identity_compression!(BlockHeight);
53identity_compression!(BlobId);
54identity_compression!(Bytes32);
55identity_compression!(Salt);
56identity_compression!(Nonce);
57
58impl Compressible for Address {
59    type Compressed = RegistryKey;
60}
61
62impl Compressible for ContractId {
63    type Compressed = RegistryKey;
64}
65
66impl Compressible for AssetId {
67    type Compressed = RegistryKey;
68}
69
70impl<const S: usize, T> Compressible for [T; S]
71where
72    T: Compressible,
73{
74    type Compressed = [T::Compressed; S];
75}
76
77impl<const S: usize, T, Ctx> CompressibleBy<Ctx> for [T; S]
78where
79    T: CompressibleBy<Ctx>,
80    Ctx: ContextError,
81{
82    #[allow(unsafe_code)]
83    async fn compress_with(&self, ctx: &mut Ctx) -> Result<Self::Compressed, Ctx::Error> {
84        // SAFETY: we are claiming to have initialized an array of `MaybeUninit`s,
85        // which do not require initialization.
86        let mut tmp: [MaybeUninit<T::Compressed>; S] =
87            unsafe { MaybeUninit::uninit().assume_init() };
88
89        let mut i = 0;
90        while i < self.len() {
91            match self[i].compress_with(ctx).await {
92                Ok(value) => {
93                    // SAFETY: MaybeUninit can be safely overwritten.
94                    tmp[i].write(value);
95                }
96                Err(e) => {
97                    // Drop the already initialized elements, so we don't leak the memory
98                    for initialized_item in tmp.iter_mut().take(i) {
99                        // Safety: First i elements have been initialized successfully.
100                        unsafe {
101                            initialized_item.assume_init_drop();
102                        }
103                    }
104                    return Err(e);
105                }
106            }
107            i += 1;
108        }
109
110        // SAFETY: Every element is initialized. In case of error, we have returned
111        // instead.
112        let result = tmp.map(|v| unsafe { v.assume_init() });
113        Ok(result)
114    }
115}
116
117impl<const S: usize, T, Ctx> DecompressibleBy<Ctx> for [T; S]
118where
119    T: DecompressibleBy<Ctx>,
120    Ctx: ContextError,
121{
122    #[allow(unsafe_code)]
123    async fn decompress_with(c: Self::Compressed, ctx: &Ctx) -> Result<Self, Ctx::Error> {
124        // SAFETY: we are claiming to have initialized an array of `MaybeUninit`s,
125        // which do not require initialization.
126        let mut tmp: [MaybeUninit<T>; S] = unsafe { MaybeUninit::uninit().assume_init() };
127
128        for (i, c) in c.into_iter().enumerate() {
129            match T::decompress_with(c, ctx).await {
130                Ok(value) => {
131                    // SAFETY: MaybeUninit can be safely overwritten.
132                    tmp[i].write(value);
133                }
134                Err(e) => {
135                    // Drop the already initialized elements, so we don't leak the memory
136                    for initialized_item in tmp.iter_mut().take(i) {
137                        // Safety: First i elements have been initialized successfully.
138                        unsafe {
139                            initialized_item.assume_init_drop();
140                        }
141                    }
142                    return Err(e);
143                }
144            }
145        }
146
147        // SAFETY: Every element is initialized.
148        let result = tmp.map(|v| unsafe { v.assume_init() });
149        Ok(result)
150    }
151}
152
153impl<T> Compressible for Vec<T>
154where
155    T: Compressible,
156{
157    type Compressed = Vec<T::Compressed>;
158}
159
160impl<T, Ctx> CompressibleBy<Ctx> for Vec<T>
161where
162    T: CompressibleBy<Ctx>,
163    Ctx: ContextError,
164{
165    async fn compress_with(&self, ctx: &mut Ctx) -> Result<Self::Compressed, Ctx::Error> {
166        let mut result = Vec::with_capacity(self.len());
167        for item in self {
168            result.push(item.compress_with(ctx).await?);
169        }
170        Ok(result)
171    }
172}
173
174impl<T, Ctx> DecompressibleBy<Ctx> for Vec<T>
175where
176    T: DecompressibleBy<Ctx>,
177    Ctx: ContextError,
178{
179    async fn decompress_with(c: Self::Compressed, ctx: &Ctx) -> Result<Self, Ctx::Error> {
180        let mut result = Vec::with_capacity(c.len());
181        for item in c {
182            result.push(T::decompress_with(item, ctx).await?);
183        }
184        Ok(result)
185    }
186}