cbe_frozen_abi/
abi_example.rs

1use {
2    crate::abi_digester::{AbiDigester, DigestError, DigestResult},
3    lazy_static::lazy_static,
4    log::*,
5    serde::Serialize,
6    std::any::type_name,
7};
8
9pub trait AbiExample: Sized {
10    fn example() -> Self;
11}
12
13// Following code snippets are copied and adapted from the official rustc implementation to
14// implement AbiExample trait for most of basic types.
15// These are licensed under Apache-2.0 + MIT (compatible because we're Apache-2.0)
16
17// Source: https://github.com/rust-lang/rust/blob/ba18875557aabffe386a2534a1aa6118efb6ab88/src/libcore/tuple.rs#L7
18macro_rules! tuple_example_impls {
19    ($(
20        $Tuple:ident {
21            $(($idx:tt) -> $T:ident)+
22        }
23    )+) => {
24        $(
25            impl<$($T:AbiExample),+> AbiExample for ($($T,)+) {
26                fn example() -> Self {
27                        ($({ let x: $T = AbiExample::example(); x},)+)
28                }
29            }
30        )+
31    }
32}
33
34// Source: https://github.com/rust-lang/rust/blob/ba18875557aabffe386a2534a1aa6118efb6ab88/src/libcore/tuple.rs#L110
35tuple_example_impls! {
36    Tuple1 {
37        (0) -> A
38    }
39    Tuple2 {
40        (0) -> A
41        (1) -> B
42    }
43    Tuple3 {
44        (0) -> A
45        (1) -> B
46        (2) -> C
47    }
48    Tuple4 {
49        (0) -> A
50        (1) -> B
51        (2) -> C
52        (3) -> D
53    }
54    Tuple5 {
55        (0) -> A
56        (1) -> B
57        (2) -> C
58        (3) -> D
59        (4) -> E
60    }
61    Tuple6 {
62        (0) -> A
63        (1) -> B
64        (2) -> C
65        (3) -> D
66        (4) -> E
67        (5) -> F
68    }
69    Tuple7 {
70        (0) -> A
71        (1) -> B
72        (2) -> C
73        (3) -> D
74        (4) -> E
75        (5) -> F
76        (6) -> G
77    }
78    Tuple8 {
79        (0) -> A
80        (1) -> B
81        (2) -> C
82        (3) -> D
83        (4) -> E
84        (5) -> F
85        (6) -> G
86        (7) -> H
87    }
88    Tuple9 {
89        (0) -> A
90        (1) -> B
91        (2) -> C
92        (3) -> D
93        (4) -> E
94        (5) -> F
95        (6) -> G
96        (7) -> H
97        (8) -> I
98    }
99    Tuple10 {
100        (0) -> A
101        (1) -> B
102        (2) -> C
103        (3) -> D
104        (4) -> E
105        (5) -> F
106        (6) -> G
107        (7) -> H
108        (8) -> I
109        (9) -> J
110    }
111    Tuple11 {
112        (0) -> A
113        (1) -> B
114        (2) -> C
115        (3) -> D
116        (4) -> E
117        (5) -> F
118        (6) -> G
119        (7) -> H
120        (8) -> I
121        (9) -> J
122        (10) -> K
123    }
124    Tuple12 {
125        (0) -> A
126        (1) -> B
127        (2) -> C
128        (3) -> D
129        (4) -> E
130        (5) -> F
131        (6) -> G
132        (7) -> H
133        (8) -> I
134        (9) -> J
135        (10) -> K
136        (11) -> L
137    }
138}
139
140// Source: https://github.com/rust-lang/rust/blob/ba18875557aabffe386a2534a1aa6118efb6ab88/src/libcore/array/mod.rs#L417
141macro_rules! array_example_impls {
142    {$n:expr, $t:ident $($ts:ident)*} => {
143        impl<T> AbiExample for [T; $n] where T: AbiExample {
144            fn example() -> Self {
145                [$t::example(), $($ts::example()),*]
146            }
147        }
148        array_example_impls!{($n - 1), $($ts)*}
149    };
150    {$n:expr,} => {
151        impl<T> AbiExample for [T; $n] {
152        fn example() -> Self { [] }
153        }
154    };
155}
156
157array_example_impls! {32, T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T}
158
159// Source: https://github.com/rust-lang/rust/blob/ba18875557aabffe386a2534a1aa6118efb6ab88/src/libcore/default.rs#L137
160macro_rules! example_impls {
161    ($t:ty, $v:expr) => {
162        impl AbiExample for $t {
163            fn example() -> Self {
164                $v
165            }
166        }
167    };
168}
169
170example_impls! { (), () }
171example_impls! { bool, false }
172example_impls! { char, '\x00' }
173
174example_impls! { usize, 0 }
175example_impls! { u8, 0 }
176example_impls! { u16, 0 }
177example_impls! { u32, 0 }
178example_impls! { u64, 0 }
179example_impls! { u128, 0 }
180
181example_impls! { isize, 0 }
182example_impls! { i8, 0 }
183example_impls! { i16, 0 }
184example_impls! { i32, 0 }
185example_impls! { i64, 0 }
186example_impls! { i128, 0 }
187
188example_impls! { f32, 0.0f32 }
189example_impls! { f64, 0.0f64 }
190example_impls! { String, String::new() }
191example_impls! { std::time::Duration, std::time::Duration::from_secs(0) }
192example_impls! { std::sync::Once, std::sync::Once::new() }
193
194use std::sync::atomic::*;
195
196// Source: https://github.com/rust-lang/rust/blob/ba18875557aabffe386a2534a1aa6118efb6ab88/src/libcore/sync/atomic.rs#L1199
197macro_rules! atomic_example_impls {
198    ($atomic_type: ident) => {
199        impl AbiExample for $atomic_type {
200            fn example() -> Self {
201                Self::new(AbiExample::example())
202            }
203        }
204    };
205}
206atomic_example_impls! { AtomicU8 }
207atomic_example_impls! { AtomicU16 }
208atomic_example_impls! { AtomicU32 }
209atomic_example_impls! { AtomicU64 }
210atomic_example_impls! { AtomicUsize }
211atomic_example_impls! { AtomicI8 }
212atomic_example_impls! { AtomicI16 }
213atomic_example_impls! { AtomicI32 }
214atomic_example_impls! { AtomicI64 }
215atomic_example_impls! { AtomicIsize }
216atomic_example_impls! { AtomicBool }
217
218#[cfg(not(target_os = "cbe"))]
219use generic_array::{ArrayLength, GenericArray};
220#[cfg(not(target_os = "cbe"))]
221impl<T: Default, U: ArrayLength<T>> AbiExample for GenericArray<T, U> {
222    fn example() -> Self {
223        Self::default()
224    }
225}
226
227use bv::{BitVec, BlockType};
228impl<T: BlockType> AbiExample for BitVec<T> {
229    fn example() -> Self {
230        Self::default()
231    }
232}
233
234impl<T: BlockType> IgnoreAsHelper for BitVec<T> {}
235impl<T: BlockType> EvenAsOpaque for BitVec<T> {}
236
237pub(crate) fn normalize_type_name(type_name: &str) -> String {
238    type_name.chars().filter(|c| *c != '&').collect()
239}
240
241type Placeholder = ();
242
243impl<T: Sized> AbiExample for T {
244    default fn example() -> Self {
245        <Placeholder>::type_erased_example()
246    }
247}
248
249// this works like a type erasure and a hatch to escape type error to runtime error
250trait TypeErasedExample<T> {
251    fn type_erased_example() -> T;
252}
253
254impl<T: Sized> TypeErasedExample<T> for Placeholder {
255    default fn type_erased_example() -> T {
256        panic!(
257            "derive or implement AbiExample/AbiEnumVisitor for {}",
258            type_name::<T>()
259        );
260    }
261}
262
263impl<T: Default + Serialize> TypeErasedExample<T> for Placeholder {
264    default fn type_erased_example() -> T {
265        let original_type_name = type_name::<T>();
266        let normalized_type_name = normalize_type_name(original_type_name);
267
268        if normalized_type_name.starts_with("cbe") {
269            panic!("derive or implement AbiExample/AbiEnumVisitor for {original_type_name}");
270        } else {
271            panic!("new unrecognized type for ABI digest!: {original_type_name}")
272        }
273    }
274}
275
276impl<T: AbiExample> AbiExample for Option<T> {
277    fn example() -> Self {
278        info!("AbiExample for (Option<T>): {}", type_name::<Self>());
279        Some(T::example())
280    }
281}
282
283impl<O: AbiExample, E: AbiExample> AbiExample for Result<O, E> {
284    fn example() -> Self {
285        info!("AbiExample for (Result<O, E>): {}", type_name::<Self>());
286        Ok(O::example())
287    }
288}
289
290impl<T: AbiExample> AbiExample for Box<T> {
291    fn example() -> Self {
292        info!("AbiExample for (Box<T>): {}", type_name::<Self>());
293        Box::new(T::example())
294    }
295}
296
297impl<T> AbiExample for Box<dyn Fn(&mut T) + Sync + Send> {
298    fn example() -> Self {
299        info!("AbiExample for (Box<T>): {}", type_name::<Self>());
300        Box::new(move |_t: &mut T| {})
301    }
302}
303
304impl<T, U> AbiExample for Box<dyn Fn(&mut T, U) + Sync + Send> {
305    fn example() -> Self {
306        info!("AbiExample for (Box<T, U>): {}", type_name::<Self>());
307        Box::new(move |_t: &mut T, _u: U| {})
308    }
309}
310
311impl<T: AbiExample> AbiExample for Box<[T]> {
312    fn example() -> Self {
313        info!("AbiExample for (Box<[T]>): {}", type_name::<Self>());
314        Box::new([T::example()])
315    }
316}
317
318impl<T: AbiExample> AbiExample for std::marker::PhantomData<T> {
319    fn example() -> Self {
320        info!("AbiExample for (PhantomData<T>): {}", type_name::<Self>());
321        <std::marker::PhantomData<T>>::default()
322    }
323}
324
325impl<T: AbiExample> AbiExample for std::sync::Arc<T> {
326    fn example() -> Self {
327        info!("AbiExample for (Arc<T>): {}", type_name::<Self>());
328        std::sync::Arc::new(T::example())
329    }
330}
331
332impl<T: AbiExample> AbiExample for std::rc::Rc<T> {
333    fn example() -> Self {
334        info!("AbiExample for (Rc<T>): {}", type_name::<Self>());
335        std::rc::Rc::new(T::example())
336    }
337}
338
339impl<T: AbiExample> AbiExample for std::sync::Mutex<T> {
340    fn example() -> Self {
341        info!("AbiExample for (Mutex<T>): {}", type_name::<Self>());
342        std::sync::Mutex::new(T::example())
343    }
344}
345
346impl<T: AbiExample> AbiExample for std::sync::RwLock<T> {
347    fn example() -> Self {
348        info!("AbiExample for (RwLock<T>): {}", type_name::<Self>());
349        std::sync::RwLock::new(T::example())
350    }
351}
352
353use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
354
355impl<
356        T: std::cmp::Eq + std::hash::Hash + AbiExample,
357        S: AbiExample,
358        H: std::hash::BuildHasher + Default,
359    > AbiExample for HashMap<T, S, H>
360{
361    fn example() -> Self {
362        info!("AbiExample for (HashMap<T, S, H>): {}", type_name::<Self>());
363        let mut map = HashMap::default();
364        map.insert(T::example(), S::example());
365        map
366    }
367}
368
369#[cfg(not(target_os = "cbe"))]
370impl<
371        T: Clone + std::cmp::Eq + std::hash::Hash + AbiExample,
372        S: Clone + AbiExample,
373        H: std::hash::BuildHasher + Default,
374    > AbiExample for im::HashMap<T, S, H>
375{
376    fn example() -> Self {
377        info!("AbiExample for (HashMap<T, S, H>): {}", type_name::<Self>());
378        let mut map = im::HashMap::default();
379        map.insert(T::example(), S::example());
380        map
381    }
382}
383
384impl<T: std::cmp::Ord + AbiExample, S: AbiExample> AbiExample for BTreeMap<T, S> {
385    fn example() -> Self {
386        info!("AbiExample for (BTreeMap<T, S>): {}", type_name::<Self>());
387        let mut map = BTreeMap::default();
388        map.insert(T::example(), S::example());
389        map
390    }
391}
392
393impl<T: AbiExample> AbiExample for Vec<T> {
394    fn example() -> Self {
395        info!("AbiExample for (Vec<T>): {}", type_name::<Self>());
396        vec![T::example()]
397    }
398}
399
400lazy_static! {
401    /// we need &Vec<u8>, so we need something with a static lifetime
402    static ref VEC_U8: Vec<u8> = vec![u8::default()];
403}
404
405impl AbiExample for &Vec<u8> {
406    fn example() -> Self {
407        info!("AbiExample for (&Vec<u8>): {}", type_name::<Self>());
408        &VEC_U8
409    }
410}
411
412impl AbiExample for &[u8] {
413    fn example() -> Self {
414        info!("AbiExample for (&[u8]): {}", type_name::<Self>());
415        &VEC_U8[..]
416    }
417}
418
419impl<T: AbiExample> AbiExample for VecDeque<T> {
420    fn example() -> Self {
421        info!("AbiExample for (Vec<T>): {}", type_name::<Self>());
422        VecDeque::from(vec![T::example()])
423    }
424}
425
426impl<T: std::cmp::Eq + std::hash::Hash + AbiExample, H: std::hash::BuildHasher + Default> AbiExample
427    for HashSet<T, H>
428{
429    fn example() -> Self {
430        info!("AbiExample for (HashSet<T, H>): {}", type_name::<Self>());
431        let mut set: HashSet<T, H> = HashSet::default();
432        set.insert(T::example());
433        set
434    }
435}
436
437impl<T: std::cmp::Ord + AbiExample> AbiExample for BTreeSet<T> {
438    fn example() -> Self {
439        info!("AbiExample for (BTreeSet<T>): {}", type_name::<Self>());
440        let mut set: BTreeSet<T> = BTreeSet::default();
441        set.insert(T::example());
442        set
443    }
444}
445
446#[cfg(not(target_os = "cbe"))]
447impl AbiExample for memmap2::MmapMut {
448    fn example() -> Self {
449        memmap2::MmapMut::map_anon(1).expect("failed to map the data file")
450    }
451}
452
453#[cfg(not(target_os = "cbe"))]
454impl AbiExample for std::path::PathBuf {
455    fn example() -> Self {
456        std::path::PathBuf::from(String::example())
457    }
458}
459
460use std::net::{IpAddr, Ipv4Addr, SocketAddr};
461impl AbiExample for SocketAddr {
462    fn example() -> Self {
463        SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
464    }
465}
466
467// This is a control flow indirection needed for digesting all variants of an enum
468pub trait AbiEnumVisitor: Serialize {
469    fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult;
470}
471
472pub trait IgnoreAsHelper {}
473pub trait EvenAsOpaque {}
474
475impl<T: Serialize + ?Sized> AbiEnumVisitor for T {
476    default fn visit_for_abi(&self, _digester: &mut AbiDigester) -> DigestResult {
477        unreachable!(
478            "AbiEnumVisitor must be implemented for {}",
479            type_name::<T>()
480        );
481    }
482}
483
484impl<T: Serialize + ?Sized + AbiExample> AbiEnumVisitor for T {
485    default fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
486        info!("AbiEnumVisitor for (default): {}", type_name::<T>());
487        T::example()
488            .serialize(digester.create_new())
489            .map_err(DigestError::wrap_by_type::<T>)
490    }
491}
492
493// even (experimental) rust specialization isn't enough for us, resort to
494// the autoref hack: https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md
495// relevant test: TestVecEnum
496impl<T: Serialize + ?Sized + AbiEnumVisitor> AbiEnumVisitor for &T {
497    default fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
498        info!("AbiEnumVisitor for (&default): {}", type_name::<T>());
499        // Don't call self.visit_for_abi(...) to avoid the infinite recursion!
500        T::visit_for_abi(self, digester)
501    }
502}
503
504// force to call self.serialize instead of T::visit_for_abi() for serialization
505// helper structs like ad-hoc iterator `struct`s
506impl<T: Serialize + IgnoreAsHelper> AbiEnumVisitor for &T {
507    default fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
508        info!("AbiEnumVisitor for (IgnoreAsHelper): {}", type_name::<T>());
509        self.serialize(digester.create_new())
510            .map_err(DigestError::wrap_by_type::<T>)
511    }
512}
513
514// force to call self.serialize instead of T::visit_for_abi() to work around the
515// inability of implementing AbiExample for private structs from other crates
516impl<T: Serialize + IgnoreAsHelper + EvenAsOpaque> AbiEnumVisitor for &T {
517    default fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
518        info!("AbiEnumVisitor for (IgnoreAsOpaque): {}", type_name::<T>());
519        let top_scope = type_name::<T>().split("::").next().unwrap();
520        self.serialize(digester.create_new_opaque(top_scope))
521            .map_err(DigestError::wrap_by_type::<T>)
522    }
523}
524
525// Because Option and Result enums are so common enums, provide generic trait implementations
526// The digesting pattern must match with what is derived from #[derive(AbiEnumVisitor)]
527impl<T: AbiEnumVisitor> AbiEnumVisitor for Option<T> {
528    fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
529        info!("AbiEnumVisitor for (Option<T>): {}", type_name::<Self>());
530
531        let variant: Self = Option::Some(T::example());
532        // serde calls serialize_some(); not serialize_variant();
533        // so create_new is correct, not create_enum_child or create_enum_new
534        variant.serialize(digester.create_new())
535    }
536}
537
538impl<O: AbiEnumVisitor, E: AbiEnumVisitor> AbiEnumVisitor for Result<O, E> {
539    fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
540        info!("AbiEnumVisitor for (Result<O, E>): {}", type_name::<Self>());
541
542        digester.update(&["enum Result (variants = 2)"]);
543        let variant: Self = Result::Ok(O::example());
544        variant.serialize(digester.create_enum_child()?)?;
545
546        let variant: Self = Result::Err(E::example());
547        variant.serialize(digester.create_enum_child()?)?;
548
549        digester.create_child()
550    }
551}
552
553impl<T: AbiExample> AbiExample for once_cell::sync::OnceCell<T> {
554    fn example() -> Self {
555        Self::with_value(T::example())
556    }
557}