66 std:: any:: type_name,
77} ;
88
9+ // The most important trait for the abi digesting. This trait is used to create any complexities of
10+ // object graph to generate the abi digest. The frozen abi test harness calls T::example() to
11+ // instantiate the tested root type and traverses its fields recursively, abusing the
12+ // serde::serialize().
13+ //
14+ // This trait applicability is similar to the Default trait. That means all referenced types must
15+ // implement this trait. AbiExample is implemented for almost all common types in this file.
16+ //
17+ // When implementing AbiExample manually, you need to return a _minimally-populated_ value
18+ // from it to actually generate a meaningful digest. This impl semantics is unlike Default, which
19+ // usually returns something empty. See actual impls for inspiration.
20+ //
21+ // The requirement of AbiExample impls even applies to those types of `#[serde(skip)]`-ed fields.
22+ // That's because the abi digesting needs a properly initialized object to enter into the
23+ // serde::serialize() to begin with, even knowning they aren't used for serialization and thus abi
24+ // digest. Luckily, `#[serde(skip)]`-ed fields' AbiExample impls can just delegate to T::default(),
25+ // exploiting the nature of this artificial impl requirement as an exception from the usual
26+ // AbiExample semantics.
927pub trait AbiExample : Sized {
1028 fn example ( ) -> Self ;
1129}
@@ -137,25 +155,12 @@ tuple_example_impls! {
137155 }
138156}
139157
140- // Source: https://github.com/rust-lang/rust/blob/ba18875557aabffe386a2534a1aa6118efb6ab88/src/libcore/array/mod.rs#L417
141- macro_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- } ;
158+ impl < const N : usize , T : AbiExample > AbiExample for [ T ; N ] {
159+ fn example ( ) -> Self {
160+ std:: array:: from_fn ( |_| T :: example ( ) )
161+ }
155162}
156163
157- array_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-
159164// Source: https://github.com/rust-lang/rust/blob/ba18875557aabffe386a2534a1aa6118efb6ab88/src/libcore/default.rs#L137
160165macro_rules! example_impls {
161166 ( $t: ty, $v: expr) => {
@@ -232,7 +237,14 @@ impl<T: BlockType> AbiExample for BitVec<T> {
232237}
233238
234239impl < T : BlockType > IgnoreAsHelper for BitVec < T > { }
235- impl < T : BlockType > EvenAsOpaque for BitVec < T > { }
240+ // This (EvenAsOpaque) marker trait is needed for BitVec because we can't impl AbiExample for its
241+ // private type:
242+ // thread '...TestBitVec_frozen_abi...' panicked at ...:
243+ // derive or implement AbiExample/AbiEnumVisitor for
244+ // bv::bit_vec::inner::Inner<u64>
245+ impl < T : BlockType > EvenAsOpaque for BitVec < T > {
246+ const TYPE_NAME_MATCHER : & ' static str = "bv::bit_vec::inner::" ;
247+ }
236248
237249pub ( crate ) fn normalize_type_name ( type_name : & str ) -> String {
238250 type_name. chars ( ) . filter ( |c| * c != '&' ) . collect ( )
@@ -329,13 +341,38 @@ impl<T: AbiExample> AbiExample for std::sync::Arc<T> {
329341 }
330342}
331343
344+ // When T is weakly owned by the likes of `std::{sync, rc}::Weak`s, we need to uphold the ownership
345+ // of T in some way at least during abi digesting... However, there's no easy way. Stashing them
346+ // into static is confronted with Send/Sync issue. Stashing them into thread_local is confronted
347+ // with not enough (T + 'static) lifetime bound.. So, just leak the examples. This should be
348+ // tolerated, considering ::example() should ever be called inside tests, not in production code...
349+ fn leak_and_inhibit_drop < ' a , T > ( t : T ) -> & ' a mut T {
350+ Box :: leak ( Box :: new ( t) )
351+ }
352+
353+ impl < T : AbiExample > AbiExample for std:: sync:: Weak < T > {
354+ fn example ( ) -> Self {
355+ info ! ( "AbiExample for (Arc's Weak<T>): {}" , type_name:: <Self >( ) ) ;
356+ // leaking is needed otherwise Arc::upgrade() will always return None...
357+ std:: sync:: Arc :: downgrade ( leak_and_inhibit_drop ( std:: sync:: Arc :: new ( T :: example ( ) ) ) )
358+ }
359+ }
360+
332361impl < T : AbiExample > AbiExample for std:: rc:: Rc < T > {
333362 fn example ( ) -> Self {
334363 info ! ( "AbiExample for (Rc<T>): {}" , type_name:: <Self >( ) ) ;
335364 std:: rc:: Rc :: new ( T :: example ( ) )
336365 }
337366}
338367
368+ impl < T : AbiExample > AbiExample for std:: rc:: Weak < T > {
369+ fn example ( ) -> Self {
370+ info ! ( "AbiExample for (Rc's Weak<T>): {}" , type_name:: <Self >( ) ) ;
371+ // leaking is needed otherwise Rc::upgrade() will always return None...
372+ std:: rc:: Rc :: downgrade ( leak_and_inhibit_drop ( std:: rc:: Rc :: new ( T :: example ( ) ) ) )
373+ }
374+ }
375+
339376impl < T : AbiExample > AbiExample for std:: sync:: Mutex < T > {
340377 fn example ( ) -> Self {
341378 info ! ( "AbiExample for (Mutex<T>): {}" , type_name:: <Self >( ) ) ;
@@ -457,6 +494,13 @@ impl AbiExample for std::path::PathBuf {
457494 }
458495}
459496
497+ #[ cfg( not( target_os = "solana" ) ) ]
498+ impl AbiExample for std:: time:: SystemTime {
499+ fn example ( ) -> Self {
500+ std:: time:: SystemTime :: UNIX_EPOCH
501+ }
502+ }
503+
460504use std:: net:: { IpAddr , Ipv4Addr , SocketAddr } ;
461505impl AbiExample for SocketAddr {
462506 fn example ( ) -> Self {
@@ -470,13 +514,22 @@ impl AbiExample for IpAddr {
470514 }
471515}
472516
473- // This is a control flow indirection needed for digesting all variants of an enum
517+ // This is a control flow indirection needed for digesting all variants of an enum.
518+ //
519+ // All of types (including non-enums) will be processed by this trait, albeit the
520+ // name of this trait.
521+ // User-defined enums usually just need to impl this with namesake derive macro (AbiEnumVisitor).
522+ //
523+ // Note that sometimes this indirection doesn't work for various reasons. For that end, there are
524+ // hacks with marker traits (IgnoreAsHelper/EvenAsOpaque).
474525pub trait AbiEnumVisitor : Serialize {
475526 fn visit_for_abi ( & self , digester : & mut AbiDigester ) -> DigestResult ;
476527}
477528
478529pub trait IgnoreAsHelper { }
479- pub trait EvenAsOpaque { }
530+ pub trait EvenAsOpaque {
531+ const TYPE_NAME_MATCHER : & ' static str ;
532+ }
480533
481534impl < T : Serialize + ?Sized > AbiEnumVisitor for T {
482535 default fn visit_for_abi ( & self , _digester : & mut AbiDigester ) -> DigestResult {
@@ -489,7 +542,9 @@ impl<T: Serialize + ?Sized> AbiEnumVisitor for T {
489542
490543impl < T : Serialize + ?Sized + AbiExample > AbiEnumVisitor for T {
491544 default fn visit_for_abi ( & self , digester : & mut AbiDigester ) -> DigestResult {
492- info ! ( "AbiEnumVisitor for (default): {}" , type_name:: <T >( ) ) ;
545+ info ! ( "AbiEnumVisitor for T: {}" , type_name:: <T >( ) ) ;
546+ // not calling self.serialize(...) is intentional here as the most generic impl
547+ // consider IgnoreAsHelper and EvenAsOpaque if you're stuck on this....
493548 T :: example ( )
494549 . serialize ( digester. create_new ( ) )
495550 . map_err ( DigestError :: wrap_by_type :: < T > )
@@ -501,7 +556,7 @@ impl<T: Serialize + ?Sized + AbiExample> AbiEnumVisitor for T {
501556// relevant test: TestVecEnum
502557impl < T : Serialize + ?Sized + AbiEnumVisitor > AbiEnumVisitor for & T {
503558 default fn visit_for_abi ( & self , digester : & mut AbiDigester ) -> DigestResult {
504- info ! ( "AbiEnumVisitor for (&default) : {}" , type_name:: <T >( ) ) ;
559+ info ! ( "AbiEnumVisitor for &T : {}" , type_name:: <T >( ) ) ;
505560 // Don't call self.visit_for_abi(...) to avoid the infinite recursion!
506561 T :: visit_for_abi ( self , digester)
507562 }
@@ -521,9 +576,13 @@ impl<T: Serialize + IgnoreAsHelper> AbiEnumVisitor for &T {
521576// inability of implementing AbiExample for private structs from other crates
522577impl < T : Serialize + IgnoreAsHelper + EvenAsOpaque > AbiEnumVisitor for & T {
523578 default fn visit_for_abi ( & self , digester : & mut AbiDigester ) -> DigestResult {
524- info ! ( "AbiEnumVisitor for (IgnoreAsOpaque): {}" , type_name:: <T >( ) ) ;
525- let top_scope = type_name :: < T > ( ) . split ( "::" ) . next ( ) . unwrap ( ) ;
526- self . serialize ( digester. create_new_opaque ( top_scope) )
579+ let type_name = type_name :: < T > ( ) ;
580+ let matcher = T :: TYPE_NAME_MATCHER ;
581+ info ! (
582+ "AbiEnumVisitor for (EvenAsOpaque): {}: matcher: {}" ,
583+ type_name, matcher
584+ ) ;
585+ self . serialize ( digester. create_new_opaque ( matcher) )
527586 . map_err ( DigestError :: wrap_by_type :: < T > )
528587 }
529588}
0 commit comments