1use super::{
4 boxed::{AscBox, AscNullableBox, AscRef},
5 num::{AscBigDecimal, AscBigInt},
6 str::{AscStr, AscString},
7 types::{AscAddress, AscBytes},
8};
9use std::{
10 mem::{self, ManuallyDrop},
11 slice,
12};
13
14#[repr(C)]
16pub struct AscArray<T> {
17 buffer: AscBox<[T]>,
18 data_start: *const T,
19 byte_length: usize,
20 length: usize,
21}
22
23impl<T> AscArray<T> {
24 pub fn new(items: Vec<T>) -> AscBox<Self> {
26 let length = items.len();
27
28 let buffer = items.into_iter().collect::<AscBox<_>>();
29 let data_start = buffer.as_ptr().cast();
30 let byte_length = length * mem::size_of::<T>();
31
32 AscBox::new(Self {
33 buffer,
34 data_start,
35 byte_length,
36 length,
37 })
38 }
39
40 pub fn as_slice(&self) -> &[T] {
42 unsafe { slice::from_raw_parts(self.data_start, self.length) }
46 }
47}
48
49impl<T> Clone for AscArray<T>
50where
51 T: Clone,
52{
53 fn clone(&self) -> Self {
54 let buffer = self.buffer.clone();
55 let data_start = buffer.as_ptr().cast();
56
57 Self {
58 buffer,
59 data_start,
60 byte_length: self.byte_length,
61 length: self.length,
62 }
63 }
64}
65
66#[repr(C)]
68pub struct AscMap<T> {
69 entries: AscBox<AscArray<AscBox<AscMapEntry<T>>>>,
70}
71
72#[repr(C)]
74pub struct AscMapEntry<T> {
75 key: AscString,
76 value: T,
77}
78
79impl<T> AscMap<T> {
80 pub fn new(entries: Vec<AscBox<AscMapEntry<T>>>) -> AscBox<Self> {
82 AscBox::new(Self {
83 entries: AscArray::new(entries),
84 })
85 }
86
87 pub fn entries(&self) -> &[AscBox<AscMapEntry<T>>] {
89 self.entries.as_asc_ref().as_slice()
90 }
91}
92
93impl<T> AscMapEntry<T> {
94 pub fn new(key: AscString, value: T) -> AscBox<Self> {
96 AscBox::new(Self { key, value })
97 }
98
99 pub fn key(&self) -> &AscStr {
101 self.key.as_asc_str()
102 }
103
104 pub fn value(&self) -> &T {
106 &self.value
107 }
108}
109
110#[repr(C)]
112pub struct AscResult<T, E> {
113 ok: AscNullableBox<T>,
114 err: AscNullableBox<E>,
115}
116
117impl<T, E> AscResult<T, E> {
118 pub fn as_std_result(&self) -> Result<&T, &E> {
121 match (self.ok.as_asc_ref(), self.err.as_asc_ref()) {
122 (Some(ok), None) => Ok(ok),
123 (None, Some(err)) => Err(err),
124 _ => panic!("inconsistent result"),
125 }
126 }
127}
128
129macro_rules! asc_tagged_union {
131 (
132 $(#[$attr:meta])*
133 $value:ident, $kind:ident, $payload:ident, $data:ident {$(
134 $variant:ident , $field:ident ($($type:tt)*) = $tag:literal ,
135
136 )*}
137 ) => {
138 $(#[$attr])*
139 #[repr(C)]
140 pub struct $value {
141 kind: $kind,
142 data: $payload,
143 }
144
145 #[allow(clippy::manual_non_exhaustive, dead_code)]
146 #[derive(Clone, Copy, Debug)]
147 #[non_exhaustive]
148 #[repr(u32)]
149 enum $kind {
150 $(
151 $variant = $tag,
152 )*
153 #[doc(hidden)]
154 _NonExhaustive,
155 }
156
157 #[repr(C)]
158 union $payload {
159 $(
160 $field: asc_tagged_union_field!(field: $($type)*),
161 )*
162 _padding: u64,
163 }
164
165 pub enum $data<'a> {
166 $(
167 $variant(asc_tagged_union_field!(ref 'a: $($type)*)),
168 )*
169 }
170
171 #[allow(dead_code, unused_variables)]
172 impl $value {
173 $(
174 pub fn $field(
176 value: asc_tagged_union_field!(owned: $($type)*),
177 ) -> AscBox<Self> {
178 AscBox::new(Self {
179 kind: $kind::$variant,
180 data: $payload {
181 $field: asc_tagged_union_field!(new(value): $($type)*),
182 },
183 })
184 }
185 )*
186
187 pub fn data(&self) -> $data {
189 match self.kind {
190 $(
191 $kind::$variant => $data::$variant(
192 asc_tagged_union_field!(data(self.data.$field): $($type)*),
193 ),
194 )*
195 _ => panic!("unknown value kind {:#x}", self.kind as u32),
196 }
197 }
198 }
199
200 impl Drop for $value {
201 fn drop(&mut self) {
202 match self.kind {
206 $(
207 $kind::$variant =>
208 asc_tagged_union_field!(drop(self.data.$field): $($type)*),
209 )*
210 _ => ()
211 }
212 }
213 }
214 };
215}
216
217#[rustfmt::skip]
218macro_rules! asc_tagged_union_field {
219 (owned: null) => { () };
220 (ref $a:lifetime: null) => { () };
221 (field: null) => { u64 };
222 (new($f:expr): null) => { 0 };
223 (data($f:expr): null) => { () };
224 (drop($f:expr): null) => { () };
225
226 (owned: string) => { AscString };
227 (ref $a:lifetime: string) => { &$a AscStr };
228 (field: string) => { ManuallyDrop<AscString> };
229 (new($f:expr): string) => { ManuallyDrop::new($f) };
230 (data($f:expr): string) => { unsafe { $f.as_asc_str() } };
231 (drop($f:expr): string) => { unsafe { ManuallyDrop::drop(&mut $f) } };
232
233 (owned: value $type:ty) => { $type };
234 (ref $a:lifetime: value $type:ty) => { $type };
235 (field: value $type:ty) => { $type };
236 (new($f:expr): value $type:ty) => { $f };
237 (data($f:expr): value $type:ty) => { unsafe { $f } };
238 (drop($f:expr): value $type:ty) => { () };
239
240 (owned: boxed $type:ty) => { AscBox<$type> };
241 (ref $a:lifetime: boxed $type:ty) => { &$a AscRef<$type> };
242 (field: boxed $type:ty) => { ManuallyDrop<AscBox<$type>> };
243 (new($f:expr): boxed $type:ty) => { ManuallyDrop::new($f) };
244 (data($f:expr): boxed $type:ty) => { unsafe { $f.as_asc_ref() } };
245 (drop($f:expr): boxed $type:ty) => { unsafe { ManuallyDrop::drop(&mut $f) } };
246}
247
248pub type AscEntity = AscMap<AscBox<AscEntityValue>>;
250
251asc_tagged_union! {
252 AscEntityValue,
254 AscEntityValueKind,
255 AscEntityValuePayload,
256 AscEntityValueData {
257 String, string (string) = 0,
258 Int, int (value i32) = 1,
259 BigDecimal, bigdecimal (boxed AscBigDecimal) = 2,
260 Bool, bool (value bool) = 3,
261 Array, array (boxed AscArray<AscBox<AscEntityValue>>) = 4,
262 Null, null (null) = 5,
263 Bytes, bytes (boxed AscBytes) = 6,
264 BigInt, bigint (boxed AscBigInt) = 7,
265 }
266}
267
268asc_tagged_union! {
269 AscJsonValue,
271 AscJsonValueKind,
272 AscJsonValuePayload,
273 AscJsonValueData {
274 Null, null (null) = 0,
275 Bool, bool (value bool) = 1,
276 Number, number (string) = 2,
277 String, string (string) = 3,
278 Array, array (boxed AscArray<AscBox<AscJsonValue>>) = 4,
279 Object, object (boxed AscMap<AscBox<AscJsonValue>>) = 5,
280 }
281}
282
283asc_tagged_union! {
284 AscEthereumValue,
286 AscEthereumValueKind,
287 AscEthereumValuePayload,
288 AscEthereumValueData {
289 Address, address (boxed AscAddress) = 0,
290 FixedBytes, fixedbytes (boxed AscBytes) = 1,
291 Bytes, bytes (boxed AscBytes) = 2,
292 Int, int (boxed AscBigInt) = 3,
293 Uint, uint (boxed AscBigInt) = 4,
294 Bool, bool (value bool) = 5,
295 String, string (string) = 6,
296 FixedArray, fixedarray (boxed AscArray<AscBox<AscEthereumValue>>) = 7,
297 Array, array (boxed AscArray<AscBox<AscEthereumValue>>) = 8,
298 Tuple, tuple (boxed AscArray<AscBox<AscEthereumValue>>) = 9,
299 }
300}