1#![no_std]
2
3pub use bobcat_maths::U;
4
5#[cfg(not(feature = "shadow"))]
6use array_concat::concat_arrays;
7
8#[cfg(feature = "alloc")]
9extern crate alloc;
10
11#[cfg(feature = "alloc")]
12use alloc::vec::Vec;
13
14#[cfg(all(target_family = "wasm", target_os = "unknown"))]
15use bobcat_host as impls;
16
17#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
18#[allow(unused)]
19mod impls {
20 pub(crate) unsafe fn emit_log(_: *const u8, _: usize, _: usize) {}
21 pub(crate) unsafe fn write_result(_: *const u8, _: usize) {}
22}
23
24pub fn emit_log(data: &[u8], topics: usize) {
25 unsafe { impls::emit_log(data.as_ptr(), data.len(), topics) }
26}
27
28#[derive(Debug, Clone, PartialEq)]
32#[repr(C)]
33struct ShadowTable<const DATA: usize> {
34 magic: u8,
35 topics_len: usize,
36 data_len: usize,
37 topics: [U; 4],
38 data: [u8; DATA],
39}
40
41#[cfg(feature = "alloc")]
42#[derive(Debug, Clone, PartialEq)]
43#[repr(C)]
44struct ShadowTableVec {
45 magic: u8,
46 topics_len: usize,
47 data_len: usize,
48 topics: [U; 4],
49 data: Vec<u8>,
50}
51
52const SHADOW_MAGIC_BYTE: u8 = 0xee;
53
54impl<const DATA: usize> Default for ShadowTable<DATA> {
55 fn default() -> Self {
56 Self {
57 magic: SHADOW_MAGIC_BYTE,
58 topics_len: 0,
59 data_len: 0,
60 topics: [U::ZERO; 4],
61 data: [0u8; DATA],
62 }
63 }
64}
65
66#[cfg(feature = "alloc")]
67impl Default for ShadowTableVec {
68 fn default() -> Self {
69 Self {
70 magic: SHADOW_MAGIC_BYTE,
71 topics_len: 0,
72 data_len: 0,
73 topics: [U::ZERO; 4],
74 data: Vec::new(),
75 }
76 }
77}
78
79pub fn shadow_log_0_slice<const D: usize, const ALL: usize>(t0: &U, d: [u8; D]) {
80 let mut t = ShadowTable {
81 data_len: D,
82 data: d,
83 ..ShadowTable::<D>::default()
84 };
85 t.topics[0] = *t0;
86 unsafe {
87 impls::write_result(&t as *const _ as *const u8, 0);
88 }
89}
90
91pub fn shadow_log_1_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, d: [u8; D]) {
92 let mut t = ShadowTable {
93 topics_len: 1,
94 data_len: D,
95 data: d,
96 ..ShadowTable::<D>::default()
97 };
98 t.topics[0] = *t0;
99 t.topics[1] = *t1;
100 unsafe {
101 impls::write_result(&t as *const _ as *const u8, 0);
102 }
103}
104
105pub fn shadow_log_2_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, t2: &U, d: [u8; D]) {
106 let mut t = ShadowTable {
107 topics_len: 2,
108 data_len: D,
109 data: d,
110 ..ShadowTable::<D>::default()
111 };
112 t.topics[0] = *t0;
113 t.topics[1] = *t1;
114 t.topics[2] = *t2;
115 unsafe {
116 impls::write_result(&t as *const _ as *const u8, 0);
117 }
118}
119
120pub fn shadow_log_3_slice<const D: usize, const ALL: usize>(
121 t0: &U,
122 t1: &U,
123 t2: &U,
124 t3: &U,
125 d: [u8; D],
126) {
127 let mut t = ShadowTable {
128 topics_len: 3,
129 data_len: D,
130 data: d,
131 ..ShadowTable::<D>::default()
132 };
133 t.topics[0] = *t0;
134 t.topics[1] = *t1;
135 t.topics[2] = *t2;
136 t.topics[3] = *t3;
137 unsafe {
138 impls::write_result(&t as *const _ as *const u8, 0);
139 }
140}
141
142#[cfg(feature = "alloc")]
143pub fn shadow_log_count(topics: [U; 4], topics_len: usize, data: &[u8]) {
144 let t = ShadowTableVec {
145 topics,
146 topics_len,
147 data_len: data.len(),
148 data: data.to_vec(),
149 ..ShadowTableVec::default()
150 };
151 unsafe {
152 impls::write_result(&t as *const _ as *const u8, 0);
153 }
154}
155
156#[cfg(not(feature = "shadow"))]
157pub fn emit_log_0_slice<const D: usize, const ALL: usize>(t0: &U, d: [u8; D]) {
158 assert_eq!(ALL, D + 32, "not properly sized: {}", D + 32);
159 let x: [u8; ALL] = concat_arrays!(t0.0, d);
160 unsafe {
161 impls::emit_log(x.as_ptr(), x.len(), 1);
162 }
163}
164
165#[cfg(feature = "shadow")]
166pub fn emit_log_0_slice<const D: usize, const ALL: usize>(t0: &U, d: [u8; D]) {
167 shadow_log_0_slice::<D, ALL>(t0, d);
168}
169
170#[cfg(not(feature = "shadow"))]
171pub fn emit_log_1_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, d: [u8; D]) {
172 assert_eq!(ALL, D + 32 * 2, "not properly sized: {}", D + 64);
173 let x: [u8; ALL] = concat_arrays!(t0.0, t1.0, d);
174 unsafe {
175 impls::emit_log(x.as_ptr(), x.len(), 2);
176 }
177}
178
179#[cfg(feature = "shadow")]
180pub fn emit_log_1_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, d: [u8; D]) {
181 shadow_log_1_slice::<D, ALL>(t0, t1, d);
182}
183
184#[cfg(not(feature = "shadow"))]
185pub fn emit_log_2_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, t2: &U, d: [u8; D]) {
186 assert_eq!(ALL, D + 32 * 3, "not properly sized: {}", D + 96);
187 let x: [u8; ALL] = concat_arrays!(t0.0, t1.0, t2.0, d);
188 unsafe {
189 impls::emit_log(x.as_ptr(), x.len(), 3);
190 }
191}
192
193#[cfg(feature = "shadow")]
194pub fn emit_log_2_slice<const D: usize, const ALL: usize>(t0: &U, t1: &U, t2: &U, d: [u8; D]) {
195 shadow_log_2_slice::<D, ALL>(t0, t1, t2, d);
196}
197
198#[cfg(not(feature = "shadow"))]
199pub fn emit_log_3_slice<const D: usize, const ALL: usize>(
200 t0: &U,
201 t1: &U,
202 t2: &U,
203 t3: &U,
204 d: [u8; D],
205) {
206 assert_eq!(ALL, D + 32 * 4, "not properly sized: {}", D + 128);
207 let x: [u8; ALL] = concat_arrays!(t0.0, t1.0, t2.0, t3.0, d);
208 unsafe {
209 impls::emit_log(x.as_ptr(), x.len(), 4);
210 }
211}
212
213#[cfg(feature = "shadow")]
214pub fn emit_log_3_slice<const D: usize, const ALL: usize>(
215 t0: &U,
216 t1: &U,
217 t2: &U,
218 t3: &U,
219 d: [u8; D],
220) {
221 shadow_log_3_slice::<D, ALL>(t0, t1, t2, t3, d);
222}
223
224#[cfg(all(feature = "alloc", not(feature = "shadow")))]
228pub fn emit_log_count(topics: [U; 4], topics_len: usize, data: &[u8]) {
229 let mut d = Vec::with_capacity(topics_len * 32 + data.len());
230 for t in &topics[..topics_len] {
231 d.extend_from_slice(t.as_slice());
232 }
233 d.extend_from_slice(data);
234 unsafe {
235 impls::emit_log(d.as_ptr(), data.len(), topics_len);
236 }
237}
238
239#[cfg(all(feature = "alloc", feature = "shadow"))]
240pub fn emit_log_count(topics: [U; 4], topics_len: usize, data: &[u8]) {
241 shadow_log_count(topics, topics_len, data);
242}
243
244#[cfg(feature = "alloc")]
245pub fn emit_log_0_vec(t0: &U, d: &[u8]) {
246 let mut x = t0.to_vec();
247 x.extend_from_slice(d);
248 unsafe {
249 impls::emit_log(x.as_ptr(), x.len(), 1);
250 }
251}
252
253#[cfg(feature = "alloc")]
254pub fn emit_log_1_vec(t0: &U, t1: &U, d: &[u8]) {
255 let mut x = t0.to_vec();
256 x.extend_from_slice(&t1.0);
257 x.extend_from_slice(d);
258 unsafe {
259 impls::emit_log(x.as_ptr(), x.len(), 2);
260 }
261}
262
263#[cfg(feature = "alloc")]
264pub fn emit_log_2_vec(t0: &U, t1: &U, t2: &U, d: &[u8]) {
265 let mut x = t0.to_vec();
266 x.extend_from_slice(&t1.0);
267 x.extend_from_slice(&t2.0);
268 x.extend_from_slice(d);
269 unsafe {
270 impls::emit_log(x.as_ptr(), x.len(), 3);
271 }
272}
273
274#[cfg(feature = "alloc")]
275pub fn emit_log_3_vec(t0: &U, t1: &U, t2: &U, t3: &U, d: &[u8]) {
276 let mut x = t0.to_vec();
277 x.extend_from_slice(&t1.0);
278 x.extend_from_slice(&t2.0);
279 x.extend_from_slice(&t3.0);
280 x.extend_from_slice(d);
281 unsafe {
282 impls::emit_log(x.as_ptr(), x.len(), 4);
283 }
284}
285
286#[macro_export]
289macro_rules! emit {
290 ($t0:expr) => {{
291 const DATA_LEN: usize = 0;
292 const ALL_LEN: usize = 32;
293 let t0: $crate::U = $t0.into();
294 $crate::emit_log_0_slice::<DATA_LEN, ALL_LEN>(&t0, [])
295 }};
296
297 ($t0:expr, data: $data:expr) => {{
298 let t0: $crate::U = $t0.into();
299 $crate::emit_log_0_vec(&t0, $data)
300 }};
301
302 ($t0:expr, data: $data:expr, $data_len:expr) => {{
303 const DATA_LEN: usize = $data_len;
304 const ALL_LEN: usize = DATA_LEN + 32;
305 let t0: $crate::U = $t0.into();
306 $crate::emit_log_0_slice::<DATA_LEN, ALL_LEN>(&t0, $data)
307 }};
308
309 ($t0:expr, $t1:expr) => {{
310 const DATA_LEN: usize = 0;
311 const ALL_LEN: usize = 32 * 2;
312 let t0: $crate::U = $t0.into();
313 let t1: $crate::U = $t1.into();
314 $crate::emit_log_1_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, [])
315 }};
316
317 ($t0:expr, $t1:expr, data: $data:expr) => {{
318 let t0: $crate::U = $t0.into();
319 let t1: $crate::U = $t1.into();
320 $crate::emit_log_1_vec(&t0, &t1, $data)
321 }};
322
323 ($t0:expr, $t1:expr, data: $data:expr, $data_len:expr) => {{
324 const DATA_LEN: usize = $data_len;
325 const ALL_LEN: usize = DATA_LEN + 32 * 2;
326 let t0: $crate::U = $t0.into();
327 let t1: $crate::U = $t1.into();
328 $crate::emit_log_1_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, $data)
329 }};
330
331 ($t0:expr, $t1:expr, $t2:expr) => {{
332 const DATA_LEN: usize = 0;
333 const ALL_LEN: usize = 32 * 3;
334 let t0: $crate::U = $t0.into();
335 let t1: $crate::U = $t1.into();
336 let t2: $crate::U = $t2.into();
337 $crate::emit_log_2_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, [])
338 }};
339
340 ($t0:expr, $t1:expr, $t2:expr, data: $data:expr) => {{
341 let t0: $crate::U = $t0.into();
342 let t1: $crate::U = $t1.into();
343 let t2: $crate::U = $t2.into();
344 $crate::emit_log_2_vec(&t0, &t1, &t2, $data)
345 }};
346
347 ($t0:expr, $t1:expr, $t2:expr, data: $data:expr, $data_len:expr) => {{
348 const DATA_LEN: usize = $data_len;
349 const ALL_LEN: usize = DATA_LEN + 32 * 3;
350 let t0: $crate::U = $t0.into();
351 let t1: $crate::U = $t1.into();
352 let t2: $crate::U = $t2.into();
353 $crate::emit_log_2_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, $data)
354 }};
355
356 ($t0:expr, $t1:expr, $t2:expr, $t3:expr) => {{
357 const DATA_LEN: usize = 0;
358 const ALL_LEN: usize = 32 * 4;
359 let t0: $crate::U = $t0.into();
360 let t1: $crate::U = $t1.into();
361 let t2: $crate::U = $t2.into();
362 let t3: $crate::U = $t3.into();
363 $crate::emit_log_3_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, &t3, [])
364 }};
365
366 ($t0:expr, $t1:expr, $t2:expr, $t3:expr, data: $data:expr) => {{
367 let t0: $crate::U = $t0.into();
368 let t1: $crate::U = $t1.into();
369 let t2: $crate::U = $t2.into();
370 let t3: $crate::U = $t3.into();
371 $crate::emit_log_3_vec(&t0, &t1, &t2, &t3, $data)
372 }};
373
374 ($t0:expr, $t1:expr, $t2:expr, $t3:expr, data: $data:expr, $data_len:expr) => {{
375 const DATA_LEN: usize = $data_len;
376 const ALL_LEN: usize = DATA_LEN + 32 * 4;
377 let t0: $crate::U = $t0.into();
378 let t1: $crate::U = $t1.into();
379 let t2: $crate::U = $t2.into();
380 let t3: $crate::U = $t3.into();
381 $crate::emit_log_3_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, &t3, $data)
382 }};
383}
384
385#[macro_export]
386macro_rules! shadow {
387 ($t0:expr) => {{
388 const DATA_LEN: usize = 0;
389 const ALL_LEN: usize = 32;
390 let t0: $crate::U = $t0.into();
391 $crate::shadow_log_0_slice::<DATA_LEN, ALL_LEN>(&t0, [])
392 }};
393
394 ($t0:expr, data: $data:expr) => {{
395 let t0: $crate::U = $t0.into();
396 $crate::shadow_log_0_vec(&t0, $data)
397 }};
398
399 ($t0:expr, data: $data:expr, $data_len:expr) => {{
400 const DATA_LEN: usize = $data_len;
401 const ALL_LEN: usize = DATA_LEN + 32;
402 let t0: $crate::U = $t0.into();
403 $crate::shadow_log_0_slice::<DATA_LEN, ALL_LEN>(&t0, $data)
404 }};
405
406 ($t0:expr, $t1:expr) => {{
407 const DATA_LEN: usize = 0;
408 const ALL_LEN: usize = 32 * 2;
409 let t0: $crate::U = $t0.into();
410 let t1: $crate::U = $t1.into();
411 $crate::shadow_log_1_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, [])
412 }};
413
414 ($t0:expr, $t1:expr, data: $data:expr) => {{
415 let t0: $crate::U = $t0.into();
416 let t1: $crate::U = $t1.into();
417 $crate::shadow_log_1_vec(&t0, &t1, $data)
418 }};
419
420 ($t0:expr, $t1:expr, data: $data:expr, $data_len:expr) => {{
421 const DATA_LEN: usize = $data_len;
422 const ALL_LEN: usize = DATA_LEN + 32 * 2;
423 let t0: $crate::U = $t0.into();
424 let t1: $crate::U = $t1.into();
425 $crate::shadow_log_1_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, $data)
426 }};
427
428 ($t0:expr, $t1:expr, $t2:expr) => {{
429 const DATA_LEN: usize = 0;
430 const ALL_LEN: usize = 32 * 3;
431 let t0: $crate::U = $t0.into();
432 let t1: $crate::U = $t1.into();
433 let t2: $crate::U = $t2.into();
434 $crate::shadow_log_2_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, [])
435 }};
436
437 ($t0:expr, $t1:expr, $t2:expr, data: $data:expr) => {{
438 let t0: $crate::U = $t0.into();
439 let t1: $crate::U = $t1.into();
440 let t2: $crate::U = $t2.into();
441 $crate::shadow_log_2_vec(&t0, &t1, &t2, $data)
442 }};
443
444 ($t0:expr, $t1:expr, $t2:expr, data: $data:expr, $data_len:expr) => {{
445 const DATA_LEN: usize = $data_len;
446 const ALL_LEN: usize = DATA_LEN + 32 * 3;
447 let t0: $crate::U = $t0.into();
448 let t1: $crate::U = $t1.into();
449 let t2: $crate::U = $t2.into();
450 $crate::shadow_log_2_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, $data)
451 }};
452
453 ($t0:expr, $t1:expr, $t2:expr, $t3:expr) => {{
454 const DATA_LEN: usize = 0;
455 const ALL_LEN: usize = 32 * 4;
456 let t0: $crate::U = $t0.into();
457 let t1: $crate::U = $t1.into();
458 let t2: $crate::U = $t2.into();
459 let t3: $crate::U = $t3.into();
460 $crate::shadow_log_3_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, &t3, [])
461 }};
462
463 ($t0:expr, $t1:expr, $t2:expr, $t3:expr, data: $data:expr) => {{
464 let t0: $crate::U = $t0.into();
465 let t1: $crate::U = $t1.into();
466 let t2: $crate::U = $t2.into();
467 let t3: $crate::U = $t3.into();
468 $crate::shadow_log_3_vec(&t0, &t1, &t2, &t3, $data)
469 }};
470
471 ($t0:expr, $t1:expr, $t2:expr, $t3:expr, data: $data:expr, $data_len:expr) => {{
472 const DATA_LEN: usize = $data_len;
473 const ALL_LEN: usize = DATA_LEN + 32 * 4;
474 let t0: $crate::U = $t0.into();
475 let t1: $crate::U = $t1.into();
476 let t2: $crate::U = $t2.into();
477 let t3: $crate::U = $t3.into();
478 $crate::shadow_log_3_slice::<DATA_LEN, ALL_LEN>(&t0, &t1, &t2, &t3, $data)
479 }};
480}