everscale_types/cell/cell_impl/
sync.rs1use std::alloc::Layout;
2use std::borrow::Borrow;
3use std::sync::atomic::AtomicUsize;
4use std::sync::{Arc, OnceLock, Weak};
5
6use super::{
7 EmptyOrdinaryCell, HeaderWithData, LibraryReference, OrdinaryCell, OrdinaryCellHeader,
8 PrunedBranch, PrunedBranchHeader, VirtualCell, ALL_ONES_CELL, ALL_ZEROS_CELL,
9};
10use crate::cell::cell_context::{CellContext, CellParts, LoadMode};
11use crate::cell::{CellFamily, CellImpl, CellType, DynCell, HashBytes};
12use crate::error::Error;
13use crate::util::TryAsMut;
14
15#[derive(Clone, Eq)]
17#[repr(transparent)]
18pub struct Cell(pub(crate) CellInner);
19
20pub type CellInner<T = DynCell> = Arc<T>;
22
23impl Cell {
24 #[inline]
26 pub fn untrack(self) -> Self {
27 self.0.untrack()
28 }
29
30 pub fn downgrade(this: &Cell) -> WeakCell {
32 WeakCell(Arc::downgrade(&this.0))
33 }
34}
35
36impl Default for Cell {
37 #[inline]
38 fn default() -> Self {
39 Cell::empty_cell()
40 }
41}
42
43impl std::ops::Deref for Cell {
44 type Target = DynCell;
45
46 #[inline]
47 fn deref(&self) -> &Self::Target {
48 self.0.as_ref()
49 }
50}
51
52impl AsRef<DynCell> for Cell {
53 #[inline]
54 fn as_ref(&self) -> &DynCell {
55 self.0.as_ref()
56 }
57}
58
59impl Borrow<DynCell> for Cell {
60 #[inline]
61 fn borrow(&self) -> &DynCell {
62 self.0.borrow()
63 }
64}
65
66impl std::fmt::Debug for Cell {
67 #[inline]
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 std::fmt::Debug::fmt(self.0.as_ref(), f)
70 }
71}
72
73impl PartialEq for Cell {
74 fn eq(&self, other: &Self) -> bool {
75 self.0.as_ref() == other.0.as_ref()
76 }
77}
78
79impl From<Cell> for CellInner {
80 #[inline]
81 fn from(value: Cell) -> Self {
82 value.0
83 }
84}
85
86impl From<CellInner> for Cell {
87 #[inline]
88 fn from(value: CellInner) -> Self {
89 Self(value)
90 }
91}
92
93impl<T: CellImpl + Send + Sync + 'static> From<CellInner<T>> for Cell {
94 #[inline]
95 fn from(value: CellInner<T>) -> Self {
96 Self(value as CellInner)
97 }
98}
99
100impl CellFamily for Cell {
101 type EmptyCellContext = EmptyCellContext;
102
103 fn empty_cell() -> Cell {
104 static EMPTY_CELL: OnceLock<Cell> = OnceLock::new();
105 EMPTY_CELL
106 .get_or_init(|| Cell(Arc::new(EmptyOrdinaryCell)))
107 .clone()
108 }
109
110 #[inline]
111 fn empty_cell_ref() -> &'static DynCell {
112 &EmptyOrdinaryCell
113 }
114
115 #[inline]
116 fn empty_context() -> Self::EmptyCellContext {
117 EmptyCellContext
118 }
119
120 #[inline]
121 fn all_zeros_ref() -> &'static DynCell {
122 &ALL_ZEROS_CELL
123 }
124
125 #[inline]
126 fn all_ones_ref() -> &'static DynCell {
127 &ALL_ONES_CELL
128 }
129
130 fn virtualize(cell: Cell) -> Cell {
131 let descriptor = cell.as_ref().descriptor();
132 if descriptor.level_mask().is_empty() {
133 cell
134 } else {
135 Cell(Arc::new(VirtualCell(cell)))
136 }
137 }
138}
139
140impl<T: ?Sized> TryAsMut<T> for Arc<T> {
141 #[inline]
142 fn try_as_mut(&mut self) -> Option<&mut T> {
143 Arc::get_mut(self)
144 }
145}
146
147impl TryAsMut<DynCell> for Cell {
148 #[inline]
149 fn try_as_mut(&mut self) -> Option<&mut DynCell> {
150 Arc::get_mut(&mut self.0)
151 }
152}
153
154#[derive(Clone)]
156#[repr(transparent)]
157pub struct WeakCell(Weak<DynCell>);
158
159impl WeakCell {
160 #[inline]
165 pub fn upgrade(&self) -> Option<Cell> {
166 self.0.upgrade().map(Cell)
167 }
168}
169
170#[derive(Debug, Default, Clone, Copy)]
172pub struct EmptyCellContext;
173
174impl CellContext for EmptyCellContext {
175 fn finalize_cell(&mut self, ctx: CellParts) -> Result<Cell, Error> {
176 let hashes = ok!(ctx.compute_hashes());
177 Ok(unsafe { make_cell(ctx, hashes) })
179 }
180
181 #[inline]
182 fn load_cell(&mut self, cell: Cell, _: LoadMode) -> Result<Cell, Error> {
183 Ok(cell)
184 }
185
186 #[inline]
187 fn load_dyn_cell<'a>(&mut self, cell: &'a DynCell, _: LoadMode) -> Result<&'a DynCell, Error> {
188 Ok(cell)
189 }
190}
191
192unsafe fn make_cell(ctx: CellParts, hashes: Vec<(HashBytes, u16)>) -> Cell {
193 match ctx.descriptor.cell_type() {
194 CellType::PrunedBranch => {
195 debug_assert!(hashes.len() == 1);
196 let repr = hashes.get_unchecked(0);
197
198 make_pruned_branch(
199 PrunedBranchHeader {
200 repr_hash: repr.0,
201 level: ctx.descriptor.level_mask().level(),
202 descriptor: ctx.descriptor,
203 },
204 ctx.data,
205 )
206 }
207 CellType::LibraryReference => {
208 debug_assert!(hashes.len() == 1);
209 let repr = hashes.get_unchecked(0);
210
211 debug_assert!(ctx.descriptor.byte_len() == 33);
212 debug_assert!(ctx.data.len() == 33);
213
214 Cell(Arc::new(LibraryReference {
215 repr_hash: repr.0,
216 descriptor: ctx.descriptor,
217 data: *(ctx.data.as_ptr() as *const [u8; 33]),
218 }))
219 }
220 CellType::Ordinary if ctx.descriptor.d1 == 0 && ctx.descriptor.d2 == 0 => {
221 Cell(Arc::new(EmptyOrdinaryCell))
222 }
223 _ => make_ordinary_cell(
224 OrdinaryCellHeader {
225 bit_len: ctx.bit_len,
226 #[cfg(feature = "stats")]
227 stats: ctx.stats,
228 hashes,
229 descriptor: ctx.descriptor,
230 references: ctx.references.into_inner(),
231 without_first: false,
232 },
233 ctx.data,
234 ),
235 }
236}
237
238unsafe fn make_ordinary_cell(header: OrdinaryCellHeader, data: &[u8]) -> Cell {
246 define_gen_vtable_ptr!((const N: usize) => OrdinaryCell<N>);
247
248 const VTABLES: [*const (); 9] = [
249 gen_vtable_ptr::<0>(),
250 gen_vtable_ptr::<8>(), gen_vtable_ptr::<8>(), gen_vtable_ptr::<8>(), gen_vtable_ptr::<8>(),
254 gen_vtable_ptr::<16>(),
255 gen_vtable_ptr::<32>(),
256 gen_vtable_ptr::<64>(),
257 gen_vtable_ptr::<128>(),
258 ];
259
260 type EmptyCell = OrdinaryCell<0>;
261
262 let raw_data_len = data.len();
264 debug_assert!(raw_data_len <= 128);
265
266 let (target_data_len, vtable) = if raw_data_len == 0 {
268 (0, VTABLES[0])
269 } else {
270 let len = std::cmp::max(raw_data_len, 8).next_power_of_two();
271 let vtable = *VTABLES.get_unchecked(1 + len.trailing_zeros() as usize);
272 (len, vtable)
273 };
274 debug_assert!(raw_data_len <= target_data_len);
275
276 type InnerOrdinaryCell<const N: usize> = ArcInner<AtomicUsize, OrdinaryCell<N>>;
278
279 const ALIGN: usize = std::mem::align_of::<InnerOrdinaryCell<0>>();
280 const _: () = assert!(
281 ALIGN == std::mem::align_of::<InnerOrdinaryCell<8>>()
282 && ALIGN == std::mem::align_of::<InnerOrdinaryCell<16>>()
283 && ALIGN == std::mem::align_of::<InnerOrdinaryCell<32>>()
284 && ALIGN == std::mem::align_of::<InnerOrdinaryCell<64>>()
285 && ALIGN == std::mem::align_of::<InnerOrdinaryCell<128>>()
286 );
287
288 const ARC_DATA_OFFSET: usize =
289 offset_of!(ArcInner<usize, EmptyCell>, obj) + offset_of!(EmptyCell, data);
290
291 let size = (ARC_DATA_OFFSET + target_data_len + ALIGN - 1) & !(ALIGN - 1);
292 let layout = Layout::from_size_align_unchecked(size, ALIGN).pad_to_align();
293
294 make_arc_cell::<OrdinaryCellHeader, 0>(layout, header, data.as_ptr(), raw_data_len, vtable)
296}
297
298unsafe fn make_pruned_branch(header: PrunedBranchHeader, data: &[u8]) -> Cell {
299 define_gen_vtable_ptr!((const N: usize) => PrunedBranch<N>);
300
301 const LENGTHS: [usize; 3] = [
302 PrunedBranchHeader::cell_data_len(1),
303 PrunedBranchHeader::cell_data_len(2),
304 PrunedBranchHeader::cell_data_len(3),
305 ];
306
307 const VTABLES: [*const (); 3] = [
308 gen_vtable_ptr::<{ LENGTHS[0] }>(),
309 gen_vtable_ptr::<{ LENGTHS[1] }>(),
310 gen_vtable_ptr::<{ LENGTHS[2] }>(),
311 ];
312
313 type EmptyCell = PrunedBranch<{ LENGTHS[0] }>;
314
315 let data_len = PrunedBranchHeader::cell_data_len(header.level as usize);
317 debug_assert!((1..=3).contains(&header.level));
318 debug_assert_eq!(data_len, data.len());
319 debug_assert_eq!(data_len, header.descriptor.byte_len() as usize);
320
321 let vtable = *VTABLES.get_unchecked((header.level - 1) as usize);
322
323 type InnerPrunedBranch<const N: usize> = ArcInner<AtomicUsize, PrunedBranch<N>>;
325
326 const ALIGN: usize = std::mem::align_of::<InnerPrunedBranch<{ LENGTHS[0] }>>();
327 const _: () = assert!(
328 ALIGN == std::mem::align_of::<InnerPrunedBranch<{ LENGTHS[1] }>>()
329 && ALIGN == std::mem::align_of::<InnerPrunedBranch<{ LENGTHS[2] }>>()
330 );
331
332 const ARC_DATA_OFFSET: usize =
333 offset_of!(ArcInner<usize, EmptyCell>, obj) + offset_of!(EmptyCell, data);
334
335 let size = (ARC_DATA_OFFSET + data_len + ALIGN - 1) & !(ALIGN - 1);
336 let layout = Layout::from_size_align_unchecked(size, ALIGN).pad_to_align();
337
338 make_arc_cell::<PrunedBranchHeader, { LENGTHS[0] }>(
340 layout,
341 header,
342 data.as_ptr(),
343 data_len,
344 vtable,
345 )
346}
347
348#[inline]
349unsafe fn make_arc_cell<H, const N: usize>(
350 layout: Layout,
351 header: H,
352 data_ptr: *const u8,
353 data_len: usize,
354 vtable: *const (),
355) -> Cell
356where
357 HeaderWithData<H, N>: CellImpl,
358{
359 let buffer = std::alloc::alloc(layout);
361 if buffer.is_null() {
362 std::alloc::handle_alloc_error(layout);
363 }
364
365 let ptr = buffer as *mut ArcInner<AtomicUsize, HeaderWithData<H, N>>;
367 std::ptr::write(std::ptr::addr_of_mut!((*ptr).strong), AtomicUsize::new(1));
368 std::ptr::write(std::ptr::addr_of_mut!((*ptr).weak), AtomicUsize::new(1));
369 std::ptr::write(std::ptr::addr_of_mut!((*ptr).obj.header), header);
370 std::ptr::copy_nonoverlapping(
371 data_ptr,
372 std::ptr::addr_of_mut!((*ptr).obj.data) as *mut u8,
373 data_len,
374 );
375
376 let data = std::ptr::addr_of!((*ptr).obj) as *const ();
378 let ptr: *const DynCell = std::mem::transmute([data, vtable]);
379
380 Cell(Arc::from_raw(ptr))
382}
383
384#[repr(C)]
386struct ArcInner<A, T: ?Sized> {
387 strong: A,
388 weak: A,
389 obj: T,
390}