solana_frozen_abi/
abi_example.rs

1use {
2    crate::abi_digester::{AbiDigester, DigestError, DigestResult},
3    serde::Serialize,
4    std::any::type_name,
5};
6
7// The most important trait for the abi digesting. This trait is used to create any complexities of
8// object graph to generate the abi digest. The frozen abi test harness calls T::example() to
9// instantiate the tested root type and traverses its fields recursively, abusing the
10// serde::serialize().
11//
12// This trait applicability is similar to the Default trait. That means all referenced types must
13// implement this trait. AbiExample is implemented for almost all common types in this file.
14//
15// When implementing AbiExample manually, you need to return a _minimally-populated_ value
16// from it to actually generate a meaningful digest. This impl semantics is unlike Default, which
17// usually returns something empty. See actual impls for inspiration.
18//
19// The requirement of AbiExample impls even applies to those types of `#[serde(skip)]`-ed fields.
20// That's because the abi digesting needs a properly initialized object to enter into the
21// serde::serialize() to begin with, even knowing they aren't used for serialization and thus abi
22// digest. Luckily, `#[serde(skip)]`-ed fields' AbiExample impls can just delegate to T::default(),
23// exploiting the nature of this artificial impl requirement as an exception from the usual
24// AbiExample semantics.
25pub trait AbiExample: Sized {
26    fn example() -> Self;
27}
28
29// Following code snippets are copied and adapted from the official rustc implementation to
30// implement AbiExample trait for most of basic types.
31// These are licensed under Apache-2.0 + MIT (compatible because we're Apache-2.0)
32
33// Source: https://github.com/rust-lang/rust/blob/ba18875557aabffe386a2534a1aa6118efb6ab88/src/libcore/tuple.rs#L7
34macro_rules! tuple_example_impls {
35    ($(
36        $Tuple:ident {
37            $(($idx:tt) -> $T:ident)+
38        }
39    )+) => {
40        $(
41            impl<$($T:AbiExample),+> AbiExample for ($($T,)+) {
42                fn example() -> Self {
43                        ($({ let x: $T = AbiExample::example(); x},)+)
44                }
45            }
46        )+
47    }
48}
49
50// Source: https://github.com/rust-lang/rust/blob/ba18875557aabffe386a2534a1aa6118efb6ab88/src/libcore/tuple.rs#L110
51tuple_example_impls! {
52    Tuple1 {
53        (0) -> A
54    }
55    Tuple2 {
56        (0) -> A
57        (1) -> B
58    }
59    Tuple3 {
60        (0) -> A
61        (1) -> B
62        (2) -> C
63    }
64    Tuple4 {
65        (0) -> A
66        (1) -> B
67        (2) -> C
68        (3) -> D
69    }
70    Tuple5 {
71        (0) -> A
72        (1) -> B
73        (2) -> C
74        (3) -> D
75        (4) -> E
76    }
77    Tuple6 {
78        (0) -> A
79        (1) -> B
80        (2) -> C
81        (3) -> D
82        (4) -> E
83        (5) -> F
84    }
85    Tuple7 {
86        (0) -> A
87        (1) -> B
88        (2) -> C
89        (3) -> D
90        (4) -> E
91        (5) -> F
92        (6) -> G
93    }
94    Tuple8 {
95        (0) -> A
96        (1) -> B
97        (2) -> C
98        (3) -> D
99        (4) -> E
100        (5) -> F
101        (6) -> G
102        (7) -> H
103    }
104    Tuple9 {
105        (0) -> A
106        (1) -> B
107        (2) -> C
108        (3) -> D
109        (4) -> E
110        (5) -> F
111        (6) -> G
112        (7) -> H
113        (8) -> I
114    }
115    Tuple10 {
116        (0) -> A
117        (1) -> B
118        (2) -> C
119        (3) -> D
120        (4) -> E
121        (5) -> F
122        (6) -> G
123        (7) -> H
124        (8) -> I
125        (9) -> J
126    }
127    Tuple11 {
128        (0) -> A
129        (1) -> B
130        (2) -> C
131        (3) -> D
132        (4) -> E
133        (5) -> F
134        (6) -> G
135        (7) -> H
136        (8) -> I
137        (9) -> J
138        (10) -> K
139    }
140    Tuple12 {
141        (0) -> A
142        (1) -> B
143        (2) -> C
144        (3) -> D
145        (4) -> E
146        (5) -> F
147        (6) -> G
148        (7) -> H
149        (8) -> I
150        (9) -> J
151        (10) -> K
152        (11) -> L
153    }
154}
155
156impl<const N: usize, T: AbiExample> AbiExample for [T; N] {
157    fn example() -> Self {
158        std::array::from_fn(|_| T::example())
159    }
160}
161
162// Source: https://github.com/rust-lang/rust/blob/ba18875557aabffe386a2534a1aa6118efb6ab88/src/libcore/default.rs#L137
163macro_rules! example_impls {
164    ($t:ty, $v:expr) => {
165        impl AbiExample for $t {
166            fn example() -> Self {
167                $v
168            }
169        }
170    };
171}
172
173example_impls! { (), () }
174example_impls! { bool, false }
175example_impls! { char, '\x00' }
176
177example_impls! { usize, 0 }
178example_impls! { u8, 0 }
179example_impls! { u16, 0 }
180example_impls! { u32, 0 }
181example_impls! { u64, 0 }
182example_impls! { u128, 0 }
183
184example_impls! { isize, 0 }
185example_impls! { i8, 0 }
186example_impls! { i16, 0 }
187example_impls! { i32, 0 }
188example_impls! { i64, 0 }
189example_impls! { i128, 0 }
190
191example_impls! { f32, 0.0f32 }
192example_impls! { f64, 0.0f64 }
193example_impls! { String, String::new() }
194example_impls! { std::time::Duration, std::time::Duration::from_secs(0) }
195example_impls! { std::sync::Once, std::sync::Once::new() }
196
197example_impls! { bytes::Bytes, bytes::Bytes::new() }
198
199use std::sync::atomic::*;
200
201// Source: https://github.com/rust-lang/rust/blob/ba18875557aabffe386a2534a1aa6118efb6ab88/src/libcore/sync/atomic.rs#L1199
202macro_rules! atomic_example_impls {
203    ($atomic_type: ident) => {
204        impl AbiExample for $atomic_type {
205            fn example() -> Self {
206                Self::new(AbiExample::example())
207            }
208        }
209    };
210}
211atomic_example_impls! { AtomicU8 }
212atomic_example_impls! { AtomicU16 }
213atomic_example_impls! { AtomicU32 }
214atomic_example_impls! { AtomicU64 }
215atomic_example_impls! { AtomicUsize }
216atomic_example_impls! { AtomicI8 }
217atomic_example_impls! { AtomicI16 }
218atomic_example_impls! { AtomicI32 }
219atomic_example_impls! { AtomicI64 }
220atomic_example_impls! { AtomicIsize }
221atomic_example_impls! { AtomicBool }
222
223use bv::{BitVec, BlockType};
224impl<T: BlockType> AbiExample for BitVec<T> {
225    fn example() -> Self {
226        Self::default()
227    }
228}
229
230impl<T: BlockType> TransparentAsHelper for BitVec<T> {}
231// This (EvenAsOpaque) marker trait is needed for BitVec because we can't impl AbiExample for its
232// private type:
233// thread '...TestBitVec_frozen_abi...' panicked at ...:
234//   derive or implement AbiExample/AbiEnumVisitor for
235//   bv::bit_vec::inner::Inner<u64>
236impl<T: BlockType> EvenAsOpaque for BitVec<T> {
237    const TYPE_NAME_MATCHER: &'static str = "bv::bit_vec::inner::";
238}
239
240use serde_with::ser::SerializeAsWrap;
241impl<T: ?Sized, U: ?Sized> TransparentAsHelper for SerializeAsWrap<'_, T, U> {}
242// This (EvenAsOpaque) marker trait is needed for serde_with's serde_as(...) because this struct is
243// basically a wrapper struct.
244impl<T: ?Sized, U: ?Sized> EvenAsOpaque for SerializeAsWrap<'_, T, U> {
245    const TYPE_NAME_MATCHER: &'static str = "serde_with::ser::SerializeAsWrap<";
246}
247
248pub(crate) fn normalize_type_name(type_name: &str) -> String {
249    type_name.chars().filter(|c| *c != '&').collect()
250}
251
252type Placeholder = ();
253
254impl<T: Sized> AbiExample for T {
255    default fn example() -> Self {
256        <Placeholder>::type_erased_example()
257    }
258}
259
260// this works like a type erasure and a hatch to escape type error to runtime error
261trait TypeErasedExample<T> {
262    fn type_erased_example() -> T;
263}
264
265impl<T: Sized> TypeErasedExample<T> for Placeholder {
266    default fn type_erased_example() -> T {
267        panic!(
268            "derive or implement AbiExample/AbiEnumVisitor for {}",
269            type_name::<T>()
270        );
271    }
272}
273
274impl<T: Default + Serialize> TypeErasedExample<T> for Placeholder {
275    default fn type_erased_example() -> T {
276        let original_type_name = type_name::<T>();
277        let normalized_type_name = normalize_type_name(original_type_name);
278
279        if normalized_type_name.starts_with("solana") {
280            panic!("derive or implement AbiExample/AbiEnumVisitor for {original_type_name}");
281        } else {
282            panic!("new unrecognized type for ABI digest!: {original_type_name}")
283        }
284    }
285}
286
287impl<T: AbiExample> AbiExample for Option<T> {
288    fn example() -> Self {
289        println!("AbiExample for (Option<T>): {}", type_name::<Self>());
290        Some(T::example())
291    }
292}
293
294impl<O: AbiExample, E: AbiExample> AbiExample for Result<O, E> {
295    fn example() -> Self {
296        println!("AbiExample for (Result<O, E>): {}", type_name::<Self>());
297        Ok(O::example())
298    }
299}
300
301impl<T: AbiExample> AbiExample for Box<T> {
302    fn example() -> Self {
303        println!("AbiExample for (Box<T>): {}", type_name::<Self>());
304        Box::new(T::example())
305    }
306}
307
308impl<T> AbiExample for Box<dyn Fn(&mut T) + Sync + Send> {
309    fn example() -> Self {
310        println!("AbiExample for (Box<T>): {}", type_name::<Self>());
311        Box::new(move |_t: &mut T| {})
312    }
313}
314
315impl<T, U> AbiExample for Box<dyn Fn(&mut T, U) + Sync + Send> {
316    fn example() -> Self {
317        println!("AbiExample for (Box<T, U>): {}", type_name::<Self>());
318        Box::new(move |_t: &mut T, _u: U| {})
319    }
320}
321
322impl<T: AbiExample> AbiExample for Box<[T]> {
323    fn example() -> Self {
324        println!("AbiExample for (Box<[T]>): {}", type_name::<Self>());
325        Box::new([T::example()])
326    }
327}
328
329impl<T: AbiExample> AbiExample for std::marker::PhantomData<T> {
330    fn example() -> Self {
331        println!("AbiExample for (PhantomData<T>): {}", type_name::<Self>());
332        std::marker::PhantomData::<T>
333    }
334}
335
336impl<T: AbiExample> AbiExample for std::sync::Arc<T> {
337    fn example() -> Self {
338        println!("AbiExample for (Arc<T>): {}", type_name::<Self>());
339        std::sync::Arc::new(T::example())
340    }
341}
342
343// When T is weakly owned by the likes of `std::{sync, rc}::Weak`s, we need to uphold the ownership
344// of T in some way at least during abi digesting... However, there's no easy way. Stashing them
345// into static is confronted with Send/Sync issue. Stashing them into thread_local is confronted
346// with not enough (T + 'static) lifetime bound..  So, just leak the examples. This should be
347// tolerated, considering ::example() should ever be called inside tests, not in production code...
348fn leak_and_inhibit_drop<'a, T>(t: T) -> &'a mut T {
349    Box::leak(Box::new(t))
350}
351
352impl<T: AbiExample> AbiExample for &T {
353    fn example() -> Self {
354        println!("AbiExample for (&T): {}", type_name::<Self>());
355        leak_and_inhibit_drop(T::example())
356    }
357}
358
359impl<T: AbiExample> AbiExample for &[T] {
360    fn example() -> Self {
361        println!("AbiExample for (&[T]): {}", type_name::<Self>());
362        leak_and_inhibit_drop(vec![T::example()])
363    }
364}
365
366impl<T: AbiExample> AbiExample for std::sync::Weak<T> {
367    fn example() -> Self {
368        println!("AbiExample for (Arc's Weak<T>): {}", type_name::<Self>());
369        // leaking is needed otherwise Arc::upgrade() will always return None...
370        std::sync::Arc::downgrade(leak_and_inhibit_drop(std::sync::Arc::new(T::example())))
371    }
372}
373
374impl<T: AbiExample> AbiExample for std::rc::Rc<T> {
375    fn example() -> Self {
376        println!("AbiExample for (Rc<T>): {}", type_name::<Self>());
377        std::rc::Rc::new(T::example())
378    }
379}
380
381impl<T: AbiExample> AbiExample for std::rc::Weak<T> {
382    fn example() -> Self {
383        println!("AbiExample for (Rc's Weak<T>): {}", type_name::<Self>());
384        // leaking is needed otherwise Rc::upgrade() will always return None...
385        std::rc::Rc::downgrade(leak_and_inhibit_drop(std::rc::Rc::new(T::example())))
386    }
387}
388
389impl<T: AbiExample> AbiExample for std::sync::Mutex<T> {
390    fn example() -> Self {
391        println!("AbiExample for (Mutex<T>): {}", type_name::<Self>());
392        std::sync::Mutex::new(T::example())
393    }
394}
395
396impl<T: AbiExample> AbiExample for std::sync::RwLock<T> {
397    fn example() -> Self {
398        println!("AbiExample for (RwLock<T>): {}", type_name::<Self>());
399        std::sync::RwLock::new(T::example())
400    }
401}
402
403use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
404
405impl<
406        T: std::cmp::Eq + std::hash::Hash + AbiExample,
407        S: AbiExample,
408        H: std::hash::BuildHasher + Default,
409    > AbiExample for HashMap<T, S, H>
410{
411    fn example() -> Self {
412        println!("AbiExample for (HashMap<T, S, H>): {}", type_name::<Self>());
413        let mut map = HashMap::default();
414        map.insert(T::example(), S::example());
415        map
416    }
417}
418
419#[cfg(not(target_os = "solana"))]
420impl<
421        T: Clone + std::cmp::Eq + std::hash::Hash + AbiExample,
422        S: Clone + AbiExample,
423        H: std::hash::BuildHasher + Default,
424    > AbiExample for im::HashMap<T, S, H>
425{
426    fn example() -> Self {
427        println!("AbiExample for (HashMap<T, S, H>): {}", type_name::<Self>());
428        let mut map = im::HashMap::default();
429        map.insert(T::example(), S::example());
430        map
431    }
432}
433
434impl<T: std::cmp::Ord + AbiExample, S: AbiExample> AbiExample for BTreeMap<T, S> {
435    fn example() -> Self {
436        println!("AbiExample for (BTreeMap<T, S>): {}", type_name::<Self>());
437        let mut map = BTreeMap::default();
438        map.insert(T::example(), S::example());
439        map
440    }
441}
442
443impl<T: AbiExample> AbiExample for Vec<T> {
444    fn example() -> Self {
445        println!("AbiExample for (Vec<T>): {}", type_name::<Self>());
446        vec![T::example()]
447    }
448}
449
450impl<T: AbiExample> AbiExample for VecDeque<T> {
451    fn example() -> Self {
452        println!("AbiExample for (Vec<T>): {}", type_name::<Self>());
453        VecDeque::from(vec![T::example()])
454    }
455}
456
457impl<T: std::cmp::Eq + std::hash::Hash + AbiExample, H: std::hash::BuildHasher + Default> AbiExample
458    for HashSet<T, H>
459{
460    fn example() -> Self {
461        println!("AbiExample for (HashSet<T, H>): {}", type_name::<Self>());
462        let mut set: HashSet<T, H> = HashSet::default();
463        set.insert(T::example());
464        set
465    }
466}
467
468impl<T: std::cmp::Ord + AbiExample> AbiExample for BTreeSet<T> {
469    fn example() -> Self {
470        println!("AbiExample for (BTreeSet<T>): {}", type_name::<Self>());
471        let mut set: BTreeSet<T> = BTreeSet::default();
472        set.insert(T::example());
473        set
474    }
475}
476
477#[cfg(not(target_os = "solana"))]
478impl AbiExample for memmap2::MmapMut {
479    fn example() -> Self {
480        memmap2::MmapMut::map_anon(1).expect("failed to map the data file")
481    }
482}
483
484#[cfg(not(target_os = "solana"))]
485impl AbiExample for std::path::PathBuf {
486    fn example() -> Self {
487        std::path::PathBuf::from(String::example())
488    }
489}
490
491#[cfg(not(target_os = "solana"))]
492impl AbiExample for std::time::SystemTime {
493    fn example() -> Self {
494        std::time::SystemTime::UNIX_EPOCH
495    }
496}
497
498use std::net::{IpAddr, Ipv4Addr, SocketAddr};
499impl AbiExample for SocketAddr {
500    fn example() -> Self {
501        SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
502    }
503}
504
505impl AbiExample for IpAddr {
506    fn example() -> Self {
507        IpAddr::V4(Ipv4Addr::UNSPECIFIED)
508    }
509}
510
511// This is a control flow indirection needed for digesting all variants of an enum.
512//
513// All of types (including non-enums) will be processed by this trait, albeit the
514// name of this trait.
515// User-defined enums usually just need to impl this with namesake derive macro (AbiEnumVisitor).
516//
517// Note that sometimes this indirection doesn't work for various reasons. For that end, there are
518// hacks with marker traits (TransparentAsHelper/EvenAsOpaque).
519pub trait AbiEnumVisitor: Serialize {
520    fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult;
521}
522
523pub trait TransparentAsHelper {}
524pub trait EvenAsOpaque {
525    const TYPE_NAME_MATCHER: &'static str;
526}
527
528impl<T: Serialize + ?Sized> AbiEnumVisitor for T {
529    default fn visit_for_abi(&self, _digester: &mut AbiDigester) -> DigestResult {
530        unreachable!(
531            "AbiEnumVisitor must be implemented for {}",
532            type_name::<T>()
533        );
534    }
535}
536
537impl<T: Serialize + AbiExample> AbiEnumVisitor for T {
538    default fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
539        println!("AbiEnumVisitor for T: {}", type_name::<T>());
540        // not calling self.serialize(...) is intentional here as the most generic impl
541        // consider TransparentAsHelper and EvenAsOpaque if you're stuck on this....
542        T::example()
543            .serialize(digester.create_new())
544            .map_err(DigestError::wrap_by_type::<T>)
545    }
546}
547
548// even (experimental) rust specialization isn't enough for us, resort to
549// the autoref hack: https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md
550// relevant test: TestVecEnum
551impl<T: Serialize + ?Sized + AbiEnumVisitor> AbiEnumVisitor for &T {
552    default fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
553        println!("AbiEnumVisitor for &T: {}", type_name::<T>());
554        // Don't call self.visit_for_abi(...) to avoid the infinite recursion!
555        T::visit_for_abi(self, digester)
556    }
557}
558
559// force to call self.serialize instead of T::visit_for_abi() for serialization
560// helper structs like ad-hoc iterator `struct`s
561impl<T: Serialize + TransparentAsHelper> AbiEnumVisitor for &T {
562    default fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
563        println!(
564            "AbiEnumVisitor for (TransparentAsHelper): {}",
565            type_name::<T>()
566        );
567        self.serialize(digester.create_new())
568            .map_err(DigestError::wrap_by_type::<T>)
569    }
570}
571
572// force to call self.serialize instead of T::visit_for_abi() to work around the
573// inability of implementing AbiExample for private structs from other crates
574impl<T: Serialize + TransparentAsHelper + EvenAsOpaque> AbiEnumVisitor for &T {
575    default fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
576        let type_name = type_name::<T>();
577        let matcher = T::TYPE_NAME_MATCHER;
578        println!("AbiEnumVisitor for (EvenAsOpaque): {type_name}: matcher: {matcher}");
579        self.serialize(digester.create_new_opaque(matcher))
580            .map_err(DigestError::wrap_by_type::<T>)
581    }
582}
583
584// Because Option and Result enums are so common enums, provide generic trait implementations
585// The digesting pattern must match with what is derived from #[derive(AbiEnumVisitor)]
586impl<T: AbiEnumVisitor> AbiEnumVisitor for Option<T> {
587    fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
588        println!("AbiEnumVisitor for (Option<T>): {}", type_name::<Self>());
589
590        let variant: Self = Option::Some(T::example());
591        // serde calls serialize_some(); not serialize_variant();
592        // so create_new is correct, not create_enum_child or create_enum_new
593        variant.serialize(digester.create_new())
594    }
595}
596
597impl<O: AbiEnumVisitor, E: AbiEnumVisitor> AbiEnumVisitor for Result<O, E> {
598    fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
599        println!("AbiEnumVisitor for (Result<O, E>): {}", type_name::<Self>());
600
601        digester.update(&["enum Result (variants = 2)"]);
602        let variant: Self = Result::Ok(O::example());
603        variant.serialize(digester.create_enum_child()?)?;
604
605        let variant: Self = Result::Err(E::example());
606        variant.serialize(digester.create_enum_child()?)?;
607
608        digester.create_child()
609    }
610}
611
612#[cfg(not(target_os = "solana"))]
613impl<T: AbiExample> AbiExample for std::sync::OnceLock<T> {
614    fn example() -> Self {
615        Self::from(T::example())
616    }
617}
618
619#[cfg(not(target_os = "solana"))]
620impl<
621        T: std::cmp::Eq + std::hash::Hash + AbiExample,
622        S: AbiExample,
623        H: std::hash::BuildHasher + Default + std::clone::Clone,
624    > AbiExample for dashmap::DashMap<T, S, H>
625{
626    fn example() -> Self {
627        println!("AbiExample for (DashMap<T, S, H>): {}", type_name::<Self>());
628        let map = dashmap::DashMap::default();
629        map.insert(T::example(), S::example());
630        map
631    }
632}
633
634#[cfg(not(target_os = "solana"))]
635impl<T: AbiExample> AbiExample for boxcar::Vec<T> {
636    fn example() -> Self {
637        println!("AbiExample for (boxcar::Vec): {}", type_name::<Self>());
638        let vec = boxcar::Vec::new();
639        vec.push(T::example());
640        vec
641    }
642}