1#![cfg_attr(not(feature = "std"), no_std)]
2
3pub use bobcat_storage::{
4 U, const_keccak256_two_off_curve, keccak256, storage_load, storage_store,
5};
6
7pub use bobcat_entry::block_timestamp;
8
9pub use bobcat_interfaces::superposition::make_fn_features;
10
11pub use bobcat_call::static_call_word;
12
13pub use paste::paste;
14
15#[macro_export]
16macro_rules! BOBCAT_FEATURES {
17 ($($feature_name:ident),* $(,)?) => {
18 pub const _FEATURE_COUNT: u8 = 0 $(+ { let _ = stringify!($feature_name); 1 })*;
19
20 const _: [(); 0] = [(); (_FEATURE_COUNT < 255) as usize - 1];
22
23 $(
24 $crate::paste! {
25 pub const [<FEATURE_ID_ $feature_name:upper>]: $crate::U =
26 $crate::const_keccak256_two_off_curve(
27 b"bobcat.features.",
28 stringify!($feature_name).as_bytes()
29 );
30
31 #[allow(unused)]
32 pub fn [<feature_is_ $feature_name:lower>]() -> bool {
33 $crate::storage_load(&[<FEATURE_ID_ $feature_name:upper>]).is_some()
34 }
35
36 pub fn [<feature_set_ $feature_name:lower>](v: bool) {
37 $crate::storage_store(
38 &[<FEATURE_ID_ $feature_name:upper>],
39 &$crate::U::from(v)
40 )
41 }
42
43 #[allow(unused)]
44 macro_rules! [<FEATURE_IF_ $feature_name:upper>] {
45 ($on_block:block else $off_block:block) => {
46 if [<feature_is_ $feature_name:lower>]() {
47 $on_block
48 } else {
49 $off_block
50 }
51 };
52 }
53 }
54 )*
55
56 #[allow(unused)]
57 pub fn feature_pack() -> $crate::U {
58 let mut r = $crate::U::default();
59 let mut i = 1;
60 $(
61 $crate::paste! {
62 if [<feature_is_ $feature_name:lower>]() {
63 let byte_index = 31 - (i / 8);
64 let bit_position = i % 8;
65 r[byte_index] |= 1 << bit_position;
66 }
67 i += 1;
68 }
69 )*
70 let _ = i;
71 r
72 }
73 };
74}
75
76#[macro_export]
77macro_rules! FEATURE_PICK {
78 ($($feature_name:ident($weight:expr)),* $(,)?) => {
79 {
80 let choice = u16::from($crate::keccak256(&$crate::block_timestamp().to_be_bytes())) % 100;
81 let mut cum = 0u16;
82 let mut found = false;
83 $(
84 if !found {
85 if choice < cum + $weight {
86 $crate::paste! {
87 [<feature_set_ $feature_name:lower>](true);
88 }
89 found = true;
90 } else {
91 cum += $weight;
92 }
93 }
94 )*
95 let _ = cum;
96 let _ = found;
97 }
98 };
99}
100
101#[macro_export]
102macro_rules! FEATURE_MATCH {
103 ($($feature:ident => $expr:expr),+ , * => $default:expr $(,)?) => {
104 $crate::paste! {
105 $(
106 if [<feature_is_ $feature:lower>]() {
107 $expr
108 } else
109 )+
110 {
111 $default
112 }
113 }
114 };
115 ($($feature:ident => $expr:expr),+ , _ => $default:expr $(,)?) => {
116 FEATURE_MATCH! {
117 $($feature => $expr,)+
118 * => $default
119 }
120 };
121 ($($feature:ident => $expr:expr),+ $(,)?) => {
122 FEATURE_MATCH! {
123 $($feature => $expr,)+
124 * => ()
125 }
126 };
127}
128
129#[macro_export]
130macro_rules! FEATURE_COPY {
131 ($address:expr, $($feature_name:ident),* $(,)?) => {
132 {
133 let (rc, r) = $crate::static_call_word(
134 $address,
135 &$crate::make_fn_features(),
136 u64::MAX,
137 0
138 );
139 assert!(rc, "features revert");
140 let remote_count = r[0];
141 const COUNT: u8 = 0 $(+ { let _ = stringify!($feature_name); 1 })*;
142 assert_eq!(
143 remote_count, COUNT,
144 "features {remote_count} != {COUNT}"
145 );
146 let mut i = 1;
147 $(
148 $crate::paste! {
149 let byte_index = 31 - (i / 8);
150 let bit_position = i % 8;
151 $crate::storage_store(
152 &$crate::const_keccak256_two_off_curve(
153 b"bobcat.features.",
154 stringify!($feature_name).as_bytes()
155 ),
156 &$crate::U::from((r[byte_index] & (1 << bit_position)) != 0)
157 );
158 i += 1;
159 }
160 )*
161 let _ = i;
162 }
163 };
164}
165
166#[macro_export]
167macro_rules! FEATURE_COPY_NON_ZEROES {
168 ($address:expr, $($feature_name:ident),* $(,)?) => {
169 {
170 let (rc, r) = $crate::static_call_word(
171 $address,
172 &$crate::make_fn_features(),
173 u64::MAX,
174 0
175 );
176 assert!(rc, "features revert");
177 let remote_count = r[0];
178 const COUNT: u8 = 0 $(+ { let _ = stringify!($feature_name); 1 })*;
179 assert_eq!(
180 remote_count, COUNT,
181 "features {remote_count} != {COUNT}"
182 );
183 let mut i = 1;
184 $(
185 $crate::paste! {
186 let byte_index = 31 - (i / 8);
187 let bit_position = i % 8;
188 let setting = (r[byte_index] & (1 << bit_position)) != 0;
189 if setting {
190 $crate::storage_store(
191 &$crate::const_keccak256_two_off_curve(
192 b"bobcat.features.",
193 stringify!($feature_name).as_bytes()
194 ),
195 &$crate::U::from(setting)
196 );
197 }
198 i += 1;
199 }
200 )*
201 let _ = i;
202 }
203 };
204}
205
206#[macro_export]
207macro_rules! FEATURE_PACK {
208 ($($feature_name:ident),* $(,)?) => {
209 {
210 let mut r = $crate::U::default();
211 #[allow(unused_assignments)]
212 let mut i = 1;
213 const COUNT: u8 = 0 $(+ { let _ = stringify!($feature_name); 1 })*;
214 r[0] = COUNT;
215 $(
216 $crate::paste! {
217 if [<feature_is_ $feature_name:lower>]() {
218 let byte_index = 31 - (i / 8);
219 let bit_position = i % 8;
220 r[byte_index] |= 1 << bit_position;
221 }
222 i += 1;
223 }
224 )*
225 let _ = i;
226 r
227 }
228 };
229}
230
231#[cfg(all(test, feature = "std"))]
232mod test_1 {
233 use bobcat_entry::{U, entry_host::set_block_timestamp};
234
235 use bobcat_host::storage_clear;
236
237 BOBCAT_FEATURES!(test123, swag);
238
239 #[test]
240 fn test_features_1() {
241 assert_eq!(2, _FEATURE_COUNT);
242 feature_set_test123(true);
243 assert!(FEATURE_IF_TEST123!({ true } else { false }));
244 feature_set_test123(false);
245 assert!(!feature_is_test123());
246 let mut test123_count = 0;
247 let mut swag_count = 0;
248 let mut else_count = 0;
249 for i in 0..100_000 {
250 set_block_timestamp(i);
251 FEATURE_PICK!(test123(40), swag(30));
252 FEATURE_MATCH! {
253 test123 => test123_count += 1,
254 swag => swag_count += 1,
255 * => else_count += 1
256 };
257 feature_set_test123(false);
258 feature_set_swag(false);
259 }
260 assert!(40_000 >= test123_count || 39_900 <= test123_count);
261 assert!(30_000 >= swag_count || 29_900 <= swag_count);
262 assert!(50_000 >= else_count || 49_900 <= else_count);
263 feature_set_test123(true);
264 feature_set_swag(true);
265 assert_eq!(U::from(6u32), feature_pack());
266 feature_set_swag(false);
267 assert_eq!(U::from(2u32), feature_pack());
268 storage_clear();
269 }
270}
271
272#[cfg(all(test, feature = "std", feature = "alloy-enabled"))]
273mod test_2 {
274 use std::str::FromStr;
275
276 use bobcat_entry::U;
277
278 use bobcat_host::storage_clear;
279
280 BOBCAT_FEATURES!(
281 F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20,
282 F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31, F32, F33, F34, F35, F36, F37, F38,
283 F39, F40, F41, F42, F43, F44, F45, F46, F47, F48, F49, F50, F51, F52, F53, F54, F55, F56,
284 F57, F58, F59, F60, F61, F62, F63, F64, F65, F66, F67, F68, F69, F70, F71, F72, F73, F74,
285 F75, F76, F77, F78, F79, F80, F81, F82, F83, F84, F85, F86, F87, F88, F89, F90, F91, F92,
286 F93, F94, F95, F96, F97, F98, F99, F100, F101, F102, F103, F104, F105, F106, F107, F108,
287 F109, F110, F111, F112, F113, F114, F115, F116, F117, F118, F119, F120, F121, F122, F123,
288 F124, F125, F126, F127, F128, F129, F130, F131, F132, F133, F134, F135, F136, F137, F138,
289 F139, F140, F141, F142, F143, F144, F145, F146, F147, F148, F149, F150, F151, F152, F153,
290 F154, F155, F156, F157, F158, F159, F160, F161, F162, F163, F164, F165, F166, F167, F168,
291 F169, F170, F171, F172, F173, F174, F175, F176, F177, F178, F179, F180, F181, F182, F183,
292 F184, F185, F186, F187, F188, F189, F190, F191, F192, F193, F194, F195, F196, F197, F198,
293 F199, F200, F201, F202, F203, F204, F205, F206, F207, F208, F209, F210, F211, F212, F213,
294 F214, F215, F216, F217, F218, F219, F220, F221, F222, F223, F224, F225, F226, F227, F228,
295 F229, F230, F231, F232, F233, F234, F235, F236, F237, F238, F239, F240, F241, F242, F243,
296 F244, F245, F246, F247, F248, F249, F250, F251, F252, F253, F254,
297 );
298
299 #[test]
300 fn test() {
301 feature_set_f1(true);
302 feature_set_f2(true);
303 feature_set_f3(true);
304 feature_set_f4(true);
305 feature_set_f5(true);
306 feature_set_f6(true);
307 feature_set_f7(true);
308 feature_set_f8(true);
309 feature_set_f9(true);
310 feature_set_f10(true);
311 feature_set_f11(true);
312 feature_set_f12(true);
313 feature_set_f13(true);
314 feature_set_f14(true);
315 feature_set_f15(true);
316 feature_set_f16(true);
317 feature_set_f17(true);
318 feature_set_f18(true);
319 feature_set_f19(true);
320 feature_set_f20(true);
321 feature_set_f21(true);
322 feature_set_f22(true);
323 feature_set_f23(true);
324 feature_set_f24(true);
325 feature_set_f25(true);
326 feature_set_f26(true);
327 feature_set_f27(true);
328 feature_set_f28(true);
329 feature_set_f29(true);
330 feature_set_f30(true);
331 feature_set_f31(true);
332 feature_set_f32(true);
333 feature_set_f33(true);
334 feature_set_f34(true);
335 feature_set_f35(true);
336 feature_set_f36(true);
337 feature_set_f37(true);
338 feature_set_f38(true);
339 feature_set_f39(true);
340 feature_set_f40(true);
341 feature_set_f41(true);
342 feature_set_f42(true);
343 feature_set_f43(true);
344 feature_set_f44(true);
345 feature_set_f45(true);
346 feature_set_f46(true);
347 feature_set_f47(true);
348 feature_set_f48(true);
349 feature_set_f49(true);
350 feature_set_f50(true);
351 feature_set_f51(true);
352 feature_set_f52(true);
353 feature_set_f53(true);
354 feature_set_f54(true);
355 feature_set_f55(true);
356 feature_set_f56(true);
357 feature_set_f57(true);
358 feature_set_f58(true);
359 feature_set_f59(true);
360 feature_set_f60(true);
361 feature_set_f61(true);
362 feature_set_f62(true);
363 feature_set_f63(true);
364 feature_set_f64(true);
365 feature_set_f65(true);
366 feature_set_f66(true);
367 feature_set_f67(true);
368 feature_set_f68(true);
369 feature_set_f69(true);
370 feature_set_f70(true);
371 feature_set_f71(true);
372 feature_set_f72(true);
373 feature_set_f73(true);
374 feature_set_f74(true);
375 feature_set_f75(true);
376 feature_set_f76(true);
377 feature_set_f77(true);
378 feature_set_f78(true);
379 feature_set_f79(true);
380 feature_set_f80(true);
381 feature_set_f81(true);
382 feature_set_f82(true);
383 feature_set_f83(true);
384 feature_set_f84(true);
385 feature_set_f85(true);
386 feature_set_f86(true);
387 feature_set_f87(true);
388 feature_set_f88(true);
389 feature_set_f89(true);
390 feature_set_f90(true);
391 feature_set_f91(true);
392 feature_set_f92(true);
393 feature_set_f93(true);
394 feature_set_f94(true);
395 feature_set_f95(true);
396 feature_set_f96(true);
397 feature_set_f97(true);
398 feature_set_f98(true);
399 feature_set_f99(true);
400 feature_set_f100(true);
401 feature_set_f101(true);
402 feature_set_f102(true);
403 feature_set_f103(true);
404 feature_set_f104(true);
405 feature_set_f105(true);
406 feature_set_f106(true);
407 feature_set_f107(true);
408 feature_set_f108(true);
409 feature_set_f109(true);
410 feature_set_f110(true);
411 feature_set_f111(true);
412 feature_set_f112(true);
413 feature_set_f113(true);
414 feature_set_f114(true);
415 feature_set_f115(true);
416 feature_set_f116(true);
417 feature_set_f117(true);
418 feature_set_f118(true);
419 feature_set_f119(true);
420 feature_set_f120(true);
421 feature_set_f121(true);
422 feature_set_f122(true);
423 feature_set_f123(true);
424 feature_set_f124(true);
425 feature_set_f125(true);
426 feature_set_f126(true);
427 feature_set_f127(true);
428 feature_set_f128(true);
429 feature_set_f129(true);
430 feature_set_f130(true);
431 feature_set_f131(true);
432 feature_set_f132(true);
433 feature_set_f133(true);
434 feature_set_f134(true);
435 feature_set_f135(true);
436 feature_set_f136(true);
437 feature_set_f137(true);
438 feature_set_f138(true);
439 feature_set_f139(true);
440 feature_set_f140(true);
441 feature_set_f141(true);
442 feature_set_f142(true);
443 feature_set_f143(true);
444 feature_set_f144(true);
445 feature_set_f145(true);
446 feature_set_f146(true);
447 feature_set_f147(true);
448 feature_set_f148(true);
449 feature_set_f149(true);
450 feature_set_f150(true);
451 feature_set_f151(true);
452 feature_set_f152(true);
453 feature_set_f153(true);
454 feature_set_f154(true);
455 feature_set_f155(true);
456 feature_set_f156(true);
457 feature_set_f157(true);
458 feature_set_f158(true);
459 feature_set_f159(true);
460 feature_set_f160(true);
461 feature_set_f161(true);
462 feature_set_f162(true);
463 feature_set_f163(true);
464 feature_set_f164(true);
465 feature_set_f165(true);
466 feature_set_f166(true);
467 feature_set_f167(true);
468 feature_set_f168(true);
469 feature_set_f169(true);
470 feature_set_f170(true);
471 feature_set_f171(true);
472 feature_set_f172(true);
473 feature_set_f173(true);
474 feature_set_f174(true);
475 feature_set_f175(true);
476 feature_set_f176(true);
477 feature_set_f177(true);
478 feature_set_f178(true);
479 feature_set_f179(true);
480 feature_set_f180(true);
481 feature_set_f181(true);
482 feature_set_f182(true);
483 feature_set_f183(true);
484 feature_set_f184(true);
485 feature_set_f185(true);
486 feature_set_f186(true);
487 feature_set_f187(true);
488 feature_set_f188(true);
489 feature_set_f189(true);
490 feature_set_f190(true);
491 feature_set_f191(true);
492 feature_set_f192(true);
493 feature_set_f193(true);
494 feature_set_f194(true);
495 feature_set_f195(true);
496 feature_set_f196(true);
497 feature_set_f197(true);
498 feature_set_f198(true);
499 feature_set_f199(true);
500 feature_set_f200(true);
501 feature_set_f201(true);
502 feature_set_f202(true);
503 feature_set_f203(true);
504 feature_set_f204(true);
505 feature_set_f205(true);
506 feature_set_f206(true);
507 feature_set_f207(true);
508 feature_set_f208(true);
509 feature_set_f209(true);
510 feature_set_f210(true);
511 feature_set_f211(true);
512 feature_set_f212(true);
513 feature_set_f213(true);
514 feature_set_f214(true);
515 feature_set_f215(true);
516 feature_set_f216(true);
517 feature_set_f217(true);
518 feature_set_f218(true);
519 feature_set_f219(true);
520 feature_set_f220(true);
521 feature_set_f221(true);
522 feature_set_f222(true);
523 feature_set_f223(true);
524 feature_set_f224(true);
525 feature_set_f225(true);
526 feature_set_f226(true);
527 feature_set_f227(true);
528 feature_set_f228(true);
529 feature_set_f229(true);
530 feature_set_f230(true);
531 feature_set_f231(true);
532 feature_set_f232(true);
533 feature_set_f233(true);
534 feature_set_f234(true);
535 feature_set_f235(true);
536 feature_set_f236(true);
537 feature_set_f237(true);
538 feature_set_f238(true);
539 feature_set_f239(true);
540 feature_set_f240(true);
541 feature_set_f241(true);
542 feature_set_f242(true);
543 feature_set_f243(true);
544 feature_set_f244(true);
545 feature_set_f245(true);
546 feature_set_f246(true);
547 feature_set_f247(true);
548 feature_set_f248(true);
549 feature_set_f249(true);
550 feature_set_f250(true);
551 feature_set_f251(true);
552 feature_set_f252(true);
553 feature_set_f253(true);
554 feature_set_f254(true);
555 assert_eq!(
556 U::from_str(
557 "57896044618658097711785492504343953926634992332820282019728792003956564819966"
558 )
559 .unwrap(),
560 feature_pack()
561 );
562 storage_clear();
563 }
564}