1use std::marker::PhantomData;
2
3use crate::cell::{
4 Cell, CellBuilder, CellContext, CellSlice, DynCell, EquivalentRepr, Load, LoadCell, Size, Store,
5};
6use crate::error::Error;
7use crate::util::{debug_tuple_field1_finish, unlikely};
8
9#[repr(transparent)]
11pub struct Lazy<T, const EXOTIC: bool = false> {
12 cell: Cell,
13 _marker: PhantomData<T>,
14}
15
16pub type LazyExotic<T> = Lazy<T, true>;
18
19impl<T, const EXOTIC: bool> crate::cell::ExactSize for Lazy<T, EXOTIC> {
20 #[inline]
21 fn exact_size(&self) -> Size {
22 Size { bits: 0, refs: 1 }
23 }
24}
25
26impl<T> std::fmt::Debug for Lazy<T, false> {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 debug_tuple_field1_finish(f, "Lazy", &self.cell)
29 }
30}
31
32impl<T> std::fmt::Debug for Lazy<T, true> {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 debug_tuple_field1_finish(f, "LazyExotic", &self.cell)
35 }
36}
37
38impl<T, const EXOTIC: bool> Eq for Lazy<T, EXOTIC> {}
39impl<T, const EXOTIC: bool> PartialEq for Lazy<T, EXOTIC> {
40 #[inline]
41 fn eq(&self, other: &Self) -> bool {
42 self.cell.as_ref().eq(other.cell.as_ref())
43 }
44}
45
46impl<T, const EXOTIC: bool> PartialEq<Cell> for Lazy<T, EXOTIC> {
47 #[inline]
48 fn eq(&self, other: &Cell) -> bool {
49 PartialEq::eq(self.inner(), other)
50 }
51}
52
53impl<T, const EXOTIC: bool> PartialEq<&Cell> for Lazy<T, EXOTIC> {
54 #[inline]
55 fn eq(&self, other: &&Cell) -> bool {
56 PartialEq::eq(self.inner(), *other)
57 }
58}
59
60impl<T, const EXOTIC: bool> PartialEq<Lazy<T, EXOTIC>> for Cell {
61 #[inline]
62 fn eq(&self, other: &Lazy<T, EXOTIC>) -> bool {
63 PartialEq::eq(self, other.inner())
64 }
65}
66
67impl<T, const EXOTIC: bool> PartialEq<&Lazy<T, EXOTIC>> for Cell {
68 #[inline]
69 fn eq(&self, other: &&Lazy<T, EXOTIC>) -> bool {
70 PartialEq::eq(self, other.inner())
71 }
72}
73
74impl<T, const EXOTIC: bool> Clone for Lazy<T, EXOTIC> {
75 #[inline]
76 fn clone(&self) -> Self {
77 Self {
78 cell: self.cell.clone(),
79 _marker: PhantomData,
80 }
81 }
82}
83
84impl<T, const EXOTIC: bool> Lazy<T, EXOTIC> {
85 #[inline]
87 pub fn from_raw(cell: Cell) -> Result<Self, Error> {
88 if unlikely(cell.is_exotic() != EXOTIC) {
89 return Err(if EXOTIC {
90 Error::UnexpectedOrdinaryCell
91 } else {
92 Error::UnexpectedExoticCell
93 });
94 }
95
96 Ok(Self {
97 cell,
98 _marker: PhantomData,
99 })
100 }
101
102 #[inline]
108 pub unsafe fn from_raw_unchecked(cell: Cell) -> Self {
109 Self {
110 cell,
111 _marker: PhantomData,
112 }
113 }
114
115 #[inline]
117 pub fn into_inner(self) -> Cell {
118 self.cell
119 }
120
121 #[inline]
123 pub fn inner(&self) -> &Cell {
124 &self.cell
125 }
126
127 pub fn cast_into<Q>(self) -> Lazy<Q, EXOTIC>
129 where
130 Q: EquivalentRepr<T>,
131 {
132 Lazy {
133 cell: self.cell,
134 _marker: PhantomData,
135 }
136 }
137
138 pub fn cast_ref<Q>(&self) -> &Lazy<Q, EXOTIC>
140 where
141 Q: EquivalentRepr<T>,
142 {
143 unsafe { &*(self as *const Self as *const Lazy<Q, EXOTIC>) }
145 }
146
147 #[cfg(feature = "serde")]
149 pub fn serialize_repr_hash<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
150 where
151 S: serde::Serializer,
152 {
153 serde::Serialize::serialize(self.cell.repr_hash(), serializer)
154 }
155}
156
157impl<T, const EXOTIC: bool> AsRef<DynCell> for Lazy<T, EXOTIC> {
158 #[inline]
159 fn as_ref(&self) -> &DynCell {
160 self.cell.as_ref()
161 }
162}
163
164impl<T, const EXOTIC: bool> std::ops::Deref for Lazy<T, EXOTIC> {
165 type Target = Cell;
166
167 #[inline]
168 fn deref(&self) -> &Self::Target {
169 &self.cell
170 }
171}
172
173impl<T: Store, const EXOTIC: bool> Lazy<T, EXOTIC> {
174 pub fn new(data: &T) -> Result<Self, Error> {
176 Self::from_raw(ok!(CellBuilder::build_from(data)))
177 }
178
179 pub fn set(&mut self, data: &T) -> Result<(), Error> {
181 *self = ok!(Self::new(data));
182 Ok(())
183 }
184}
185
186impl<'a, T: Load<'a> + 'a> Lazy<T, false> {
187 pub fn load(&'a self) -> Result<T, Error> {
189 self.cell.as_ref().parse::<T>()
190 }
191}
192
193impl<'a, T: LoadCell<'a> + 'a> Lazy<T, true> {
194 pub fn load(&'a self) -> Result<T, Error> {
196 self.cell.as_ref().parse_exotic::<T>()
197 }
198}
199
200impl<T, const EXOTIC: bool> Store for Lazy<T, EXOTIC> {
201 fn store_into(&self, builder: &mut CellBuilder, _: &dyn CellContext) -> Result<(), Error> {
202 builder.store_reference(self.cell.clone())
203 }
204}
205
206impl<'a, T, const EXOTIC: bool> Load<'a> for Lazy<T, EXOTIC> {
207 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
208 match slice.load_reference_cloned() {
209 Ok(cell) => Self::from_raw(cell),
210 Err(e) => Err(e),
211 }
212 }
213}
214
215#[cfg(feature = "serde")]
216impl<T> serde::Serialize for Lazy<T, false>
217where
218 for<'a> T: serde::Serialize + Load<'a>,
219{
220 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
221 where
222 S: serde::Serializer,
223 {
224 if serializer.is_human_readable() {
225 let value = ok!(self.load().map_err(serde::ser::Error::custom));
226 value.serialize(serializer)
227 } else {
228 crate::boc::Boc::serialize(&self.cell, serializer)
229 }
230 }
231}
232
233#[cfg(feature = "serde")]
234impl<T> serde::Serialize for Lazy<T, true>
235where
236 for<'a> T: serde::Serialize + LoadCell<'a>,
237{
238 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
239 where
240 S: serde::Serializer,
241 {
242 if serializer.is_human_readable() {
243 let value = ok!(self.load().map_err(serde::ser::Error::custom));
244 value.serialize(serializer)
245 } else {
246 crate::boc::Boc::serialize(&self.cell, serializer)
247 }
248 }
249}
250
251#[cfg(feature = "serde")]
252impl<'de, T, const EXOTIC: bool> serde::Deserialize<'de> for Lazy<T, EXOTIC>
253where
254 T: serde::Deserialize<'de> + Store,
255{
256 fn deserialize<D>(deserializer: D) -> Result<Lazy<T, EXOTIC>, D::Error>
257 where
258 D: serde::Deserializer<'de>,
259 {
260 if deserializer.is_human_readable() {
261 let value = T::deserialize(deserializer)?;
262 Lazy::new(&value)
263 } else {
264 let cell = crate::boc::Boc::deserialize(deserializer)?;
265 Lazy::from_raw(cell)
266 }
267 .map_err(serde::de::Error::custom)
268 }
269}
270
271#[cfg(feature = "arbitrary")]
272impl<'a, T: Store + arbitrary::Arbitrary<'a>> arbitrary::Arbitrary<'a> for Lazy<T, false> {
273 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
274 let inner = u.arbitrary::<T>()?;
275 Lazy::new(&inner).map_err(|_| arbitrary::Error::IncorrectFormat)
276 }
277
278 #[inline]
279 fn size_hint(depth: usize) -> (usize, Option<usize>) {
280 Self::try_size_hint(depth).unwrap_or_default()
281 }
282
283 #[inline]
284 fn try_size_hint(
285 depth: usize,
286 ) -> arbitrary::Result<(usize, Option<usize>), arbitrary::MaxRecursionReached> {
287 <T as arbitrary::Arbitrary>::try_size_hint(depth)
288 }
289}