2024-01-29 22:32:16 +00:00
pub use bytes ;
pub use paste ::paste ;
2024-03-20 20:58:12 +00:00
/// Macro to derive [`EpeeObject`](crate::EpeeObject) for structs.
///
/// ### Basic Usage:
///
/// ```rust
/// // mod visibility is here because of Rust visibility weirdness, you shouldn't need this unless defined in a function.
/// // see: <https://github.com/rust-lang/rust/issues/64079>
/// mod visibility {
///
2024-06-24 01:30:47 +00:00
/// use cuprate_epee_encoding::epee_object;
2024-03-20 20:58:12 +00:00
///
/// struct Example {
/// a: u8
/// }
///
/// epee_object!(
/// Example,
/// a: u8,
/// );
/// }
/// ```
///
/// ### Advanced Usage:
///
/// ```rust
/// // mod visibility is here because of Rust visibility weirdness, you shouldn't need this unless defined in a function.
/// // see: <https://github.com/rust-lang/rust/issues/64079>
/// mod visibility {
///
2024-06-24 01:30:47 +00:00
/// use cuprate_epee_encoding::epee_object;
2024-03-20 20:58:12 +00:00
///
/// struct Example {
/// a: u8,
/// b: u8,
/// c: u8,
/// d: u8,
/// e_f: Example2
/// }
///
/// struct Example2 {
/// e: u8
/// }
///
/// epee_object!(
/// Example2,
/// e: u8,
/// );
///
/// epee_object!(
/// Example,
/// // `("ALT-NAME")` changes the name of the field in the encoded data.
/// a("A"): u8,
/// // `= VALUE` sets a default value that this field will be set to if not in the data
/// // when encoding this field will be skipped if equal to the default.
/// b: u8 = 0,
/// // `as ALT-TYPE` encodes the data using the alt type, the alt type must impl Into<Type> and From<&Type>
/// c: u8 as u8,
/// // `=> read_fn, write_fn, should_write_fn,` allows you to specify alt field encoding functions.
/// // for the required args see the default functions, which are used here:
2024-06-24 01:30:47 +00:00
/// d: u8 => cuprate_epee_encoding::read_epee_value, cuprate_epee_encoding::write_field, <u8 as cuprate_epee_encoding::EpeeValue>::should_write,
2024-03-20 20:58:12 +00:00
/// // `!flatten` can be used on fields which are epee objects, and it flattens the fields of that object into this object.
/// // So for this example `e_f` will not appear in the data but e will.
/// // You can't use the other options with this.
/// !flatten: e_f: Example2,
/// );
/// }
/// ```
///
///
2024-01-29 22:32:16 +00:00
#[ macro_export ]
2024-03-20 20:58:12 +00:00
macro_rules ! epee_object {
// ------------------------------------------------------------------------ internal_try_right_then_left
// All this does is return the second (right) arg if present otherwise the left is returned.
(
@ internal_try_right_then_left
$a :expr , $b :expr
) = > {
$b
} ;
(
@ internal_try_right_then_left
$a :expr ,
) = > {
$a
} ;
// ------------------------------------------------------------------------ internal_field_name
// Returns the alt_name if present otherwise stringifies the field ident.
(
@ internal_field_name
$field : tt , $alt_name : tt
) = > {
2024-01-29 22:32:16 +00:00
$alt_name
} ;
2024-03-20 20:58:12 +00:00
(
@ internal_field_name
$field : ident ,
) = > {
2024-01-29 22:32:16 +00:00
stringify! ( $field )
} ;
2024-03-20 20:58:12 +00:00
// ------------------------------------------------------------------------ internal_field_type
// All this does is return the second (right) arg if present otherwise the left is returned.
(
@ internal_field_type
$ty :ty , $ty_as :ty
) = > {
2024-01-29 22:32:16 +00:00
$ty_as
} ;
2024-03-20 20:58:12 +00:00
(
@ internal_field_type
$ty :ty ,
) = > {
2024-01-29 22:32:16 +00:00
$ty
} ;
2024-03-20 20:58:12 +00:00
// ------------------------------------------------------------------------ Entry Point
2024-01-29 22:32:16 +00:00
(
$obj :ident ,
2024-03-20 20:58:12 +00:00
$( $field : ident $( ( $alt_name : literal ) ) ? : $ty :ty $( as $ty_as :ty ) ? $( = $default :expr ) ? $( = > $read_fn :expr , $write_fn :expr , $should_write_fn :expr ) ? , ) *
$( ! flatten : $flat_field : ident : $flat_ty :ty , ) *
2024-01-29 22:32:16 +00:00
) = > {
2024-06-24 01:30:47 +00:00
cuprate_epee_encoding ::macros ::paste! (
2024-01-29 22:32:16 +00:00
#[ allow(non_snake_case) ]
mod [ < __epee_builder_ $obj > ] {
use super ::* ;
#[ derive(Default) ]
pub struct [ < __Builder $obj > ] {
2024-06-24 01:30:47 +00:00
$( $field : Option < cuprate_epee_encoding ::epee_object! ( @ internal_field_type $ty , $( $ty_as ) ? ) > , ) *
$( $flat_field : < $flat_ty as cuprate_epee_encoding ::EpeeObject > ::Builder , ) *
2024-01-29 22:32:16 +00:00
}
2024-06-24 01:30:47 +00:00
impl cuprate_epee_encoding ::EpeeObjectBuilder < $obj > for [ < __Builder $obj > ] {
fn add_field < B : cuprate_epee_encoding ::macros ::bytes ::Buf > ( & mut self , name : & str , b : & mut B ) -> cuprate_epee_encoding ::error ::Result < bool > {
2024-01-29 22:32:16 +00:00
match name {
2024-06-24 01:30:47 +00:00
$( cuprate_epee_encoding ::epee_object! ( @ internal_field_name $field , $( $alt_name ) ? ) = > {
2024-01-30 16:09:54 +00:00
if core ::mem ::replace ( & mut self . $field , Some (
2024-06-24 01:30:47 +00:00
cuprate_epee_encoding ::epee_object! ( @ internal_try_right_then_left cuprate_epee_encoding ::read_epee_value ( b ) ? , $( $read_fn ( b ) ? ) ? )
2024-01-30 16:09:54 +00:00
) ) . is_some ( ) {
2024-06-24 01:30:47 +00:00
Err ( cuprate_epee_encoding ::error ::Error ::Value ( format! ( " Duplicate field in data: {} " , cuprate_epee_encoding ::epee_object! ( @ internal_field_name $field , $( $alt_name ) ? ) ) ) ) ? ;
2024-01-29 22:32:16 +00:00
}
Ok ( true )
2024-03-20 20:58:12 +00:00
} , ) *
2024-01-29 22:32:16 +00:00
_ = > {
2024-03-20 20:58:12 +00:00
$( if self . $flat_field . add_field ( name , b ) ? {
return Ok ( true ) ;
} ) *
2024-01-29 22:32:16 +00:00
Ok ( false )
}
}
}
2024-06-24 01:30:47 +00:00
fn finish ( self ) -> cuprate_epee_encoding ::error ::Result < $obj > {
2024-01-29 22:32:16 +00:00
Ok (
$obj {
$(
2024-01-30 16:09:54 +00:00
$field : {
2024-06-24 01:30:47 +00:00
let epee_default_value = cuprate_epee_encoding ::epee_object! ( @ internal_try_right_then_left cuprate_epee_encoding ::EpeeValue ::epee_default_value ( ) , $( {
2024-01-30 16:09:54 +00:00
let _ = $should_write_fn ;
None
} ) ? ) ;
self . $field
2024-01-29 22:32:16 +00:00
$( . or ( Some ( $default ) ) ) ?
2024-01-30 16:09:54 +00:00
. or ( epee_default_value )
2024-01-29 22:32:16 +00:00
$( . map ( < $ty_as > ::into ) ) ?
2024-06-24 01:30:47 +00:00
. ok_or ( cuprate_epee_encoding ::error ::Error ::Value ( format! ( " Missing field in data: {} " , cuprate_epee_encoding ::epee_object! ( @ internal_field_name $field , $( $alt_name ) ? ) ) ) ) ?
2024-01-30 16:09:54 +00:00
} ,
2024-03-20 20:58:12 +00:00
) *
2024-01-29 22:32:16 +00:00
$(
$flat_field : self . $flat_field . finish ( ) ? ,
2024-03-20 20:58:12 +00:00
) *
2024-01-29 22:32:16 +00:00
}
)
}
}
}
2024-06-24 01:30:47 +00:00
impl cuprate_epee_encoding ::EpeeObject for $obj {
2024-01-29 22:32:16 +00:00
type Builder = [ < __epee_builder_ $obj > ] ::[ < __Builder $obj > ] ;
fn number_of_fields ( & self ) -> u64 {
let mut fields = 0 ;
$(
2024-06-24 01:30:47 +00:00
let field = cuprate_epee_encoding ::epee_object! ( @ internal_try_right_then_left & self . $field , $( < & $ty_as > ::from ( & self . $field ) ) ? ) ;
2024-01-30 16:09:54 +00:00
2024-06-24 01:30:47 +00:00
if $( ( field ) ! = & $default & & ) ? cuprate_epee_encoding ::epee_object! ( @ internal_try_right_then_left cuprate_epee_encoding ::EpeeValue ::should_write , $( $should_write_fn ) ? ) ( field )
2024-01-30 16:09:54 +00:00
{
2024-01-29 22:32:16 +00:00
fields + = 1 ;
}
2024-03-20 20:58:12 +00:00
) *
2024-01-29 22:32:16 +00:00
$(
2024-03-20 20:58:12 +00:00
fields + = self . $flat_field . number_of_fields ( ) ;
) *
2024-01-29 22:32:16 +00:00
fields
}
2024-06-24 01:30:47 +00:00
fn write_fields < B : cuprate_epee_encoding ::macros ::bytes ::BufMut > ( self , w : & mut B ) -> cuprate_epee_encoding ::error ::Result < ( ) > {
2024-01-29 22:32:16 +00:00
$(
2024-06-24 01:30:47 +00:00
let field = cuprate_epee_encoding ::epee_object! ( @ internal_try_right_then_left self . $field , $( < $ty_as > ::from ( self . $field ) ) ? ) ;
2024-01-30 16:09:54 +00:00
2024-06-24 01:30:47 +00:00
if $( field ! = $default & & ) ? cuprate_epee_encoding ::epee_object! ( @ internal_try_right_then_left cuprate_epee_encoding ::EpeeValue ::should_write , $( $should_write_fn ) ? ) ( & field )
2024-01-30 16:09:54 +00:00
{
2024-06-24 01:30:47 +00:00
cuprate_epee_encoding ::epee_object! ( @ internal_try_right_then_left cuprate_epee_encoding ::write_field , $( $write_fn ) ? ) ( ( field ) , cuprate_epee_encoding ::epee_object! ( @ internal_field_name $field , $( $alt_name ) ? ) , w ) ? ;
2024-01-29 22:32:16 +00:00
}
2024-03-20 20:58:12 +00:00
) *
2024-01-29 22:32:16 +00:00
$(
self . $flat_field . write_fields ( w ) ? ;
2024-03-20 20:58:12 +00:00
) *
2024-01-29 22:32:16 +00:00
Ok ( ( ) )
}
}
) ;
} ;
}