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