@@ -794,6 +794,29 @@ macro_rules! decoder_state_machine {
794794///
795795/// # Syntax
796796///
797+ /// There are two invocation patterns:
798+ ///
799+ /// ## Direct Error Wrapping
800+ /// ```ignore
801+ /// decoder_newtype! {
802+ /// /// Documentation for the decoder struct
803+ /// pub struct DecoderName(InnerDecoderType);
804+ ///
805+ /// /// Documentation for the error struct
806+ /// pub struct ErrorName(InnerErrorName);
807+ /// const ERROR_DISPLAY = "output of the Display::fmt function";
808+ ///
809+ /// impl Decode for TargetType {
810+ /// fn convert_inner(output_var) -> Result<_, InnerErrorName> {
811+ /// // Conversion logic -- returns `InnerErrorName` for errors!
812+ /// }
813+ /// }
814+ /// }
815+ /// ```
816+ ///
817+ /// In this case `InnerErrorName` must be an already-existing error type.
818+ ///
819+ /// ## Error Enum Wrapping
797820/// ```ignore
798821/// decoder_newtype! {
799822/// /// Documentation for the decoder struct
@@ -811,12 +834,14 @@ macro_rules! decoder_state_machine {
811834///
812835/// impl Decode for TargetType {
813836/// fn convert_inner(output_var) -> Result<_, ErrorName> {
814- /// // Conversion logic
837+ /// // Conversion logic -- returns `ErrorName` for errors!
815838/// }
816839/// }
817840/// }
818841/// ```
819842///
843+ /// In this case `InnerErrorName` will be generated as a private enum by the macro.
844+ ///
820845/// # Generated Code
821846///
822847/// The macro generates:
@@ -826,8 +851,10 @@ macro_rules! decoder_state_machine {
826851/// - `Decoder` trait implementation with `push_bytes`, `end`, and `read_limit` methods
827852/// - `Decode` trait implementation for the target type
828853///
829- /// The macro does **not** generate a `fmt::Display` or `std::error::Error` impl
830- /// for `ErrorName`, so the user must implement these outside of the macro.
854+ /// **When using the enum pattern, the macro does not generate a `fmt::Display` or
855+ /// `std::error::Error` impl for `ErrorName`. The user must implement these outside
856+ /// of the macro.** When using the non-enum pattern, both `Display` and `Error` are
857+ /// generated by the macro.
831858///
832859/// # Parameters
833860///
@@ -843,9 +870,15 @@ macro_rules! decoder_state_machine {
843870///
844871/// The conversion function:
845872/// - Takes the inner decoder's output as its parameter
846- /// - Returns `Result<TargetType, ErrorName>`
873+ /// - Returns `Result<TargetType, ErrorName>` for enum pattern, `Result<TargetType, InnerErrorName>`
874+ /// for direct-wrapping pattern.
847875/// - Is called automatically when the inner decoder completes
848- /// - Can return custom errors defined in the error enum
876+ /// - Can return custom errors defined in the error enum (enum pattern only)
877+ ///
878+ /// # Pattern Selection
879+ ///
880+ /// - Use **direct error wrapping** when conversion cannot fail or only needs to propagate the inner decoder's errors
881+ /// - Use **error enum wrapping** when conversion can fail with custom error types
849882///
850883/// # Error Handling
851884///
@@ -856,6 +889,37 @@ macro_rules! decoder_state_machine {
856889///
857890/// # Example Usage
858891///
892+ /// ## Direct Error Wrapping
893+ /// ```ignore
894+ /// decoder_newtype! {
895+ /// /// Decoder for the [`TxOut`] type.
896+ /// #[derive(Default)]
897+ /// pub struct TxOutDecoder(Decoder4< crate::confidential::AssetDecoder,
898+ /// crate::confidential::ValueDecoder,
899+ /// crate::confidential::NonceDecoder,
900+ /// crate::script::ScriptDecoder,
901+ /// >);
902+ ///
903+ /// /// Decoder error for the [`TxOut`] type.
904+ /// #[derive(Clone, PartialEq, Eq, Debug)]
905+ /// pub struct TxOutDecoderError(Decoder4Error<
906+ /// crate::confidential::AssetDecoderError,
907+ /// crate::confidential::ValueDecoderError,
908+ /// crate::confidential::NonceDecoderError,
909+ /// crate::script::ScriptDecoderError,
910+ /// >);
911+ /// const ERROR_DISPLAY = "error decoding transaction output witness";
912+ ///
913+ /// impl Decode for TxOut {
914+ /// fn convert_inner(output) -> Result<_, TxOutDecoderErrorInner> {
915+ /// let (asset, value, nonce, script_pubkey) = output;
916+ /// Ok(TxOut { asset, value, nonce, script_pubkey, witness: TxOutWitness::empty() })
917+ /// }
918+ /// }
919+ /// }
920+ /// ```
921+ ///
922+ /// ## Error Enum Wrapping
859923/// ```ignore
860924/// decoder_newtype! {
861925/// /// Decoder for range proofs
@@ -877,6 +941,73 @@ macro_rules! decoder_state_machine {
877941/// }
878942/// ```
879943macro_rules! decoder_newtype {
944+ // With directly wrapped inner error
945+ (
946+ $( #[ $( $struct_attr: tt) * ] ) *
947+ pub struct $outer_ty: ident( $inner_ty: ty) ;
948+
949+ $( #[ $( $error_struct_attr: tt) * ] ) *
950+ pub struct $error_ty: ident( $inner_ty_error: ty) ;
951+
952+ const ERROR_DISPLAY = $error_display: expr;
953+
954+ impl Decode for $target_ty: ty {
955+ fn convert_inner( $output: ident) -> Result <_, $error_inner1: ty> {
956+ $( $output_fn_inner: tt) *
957+ }
958+ }
959+ ) => {
960+ $( #[ $( $struct_attr) * ] ) *
961+ pub struct $outer_ty( $inner_ty) ;
962+
963+ $( #[ $( $error_struct_attr) * ] ) *
964+ pub struct $error_ty( $inner_ty_error) ;
965+
966+ impl core:: fmt:: Display for $error_ty {
967+ fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
968+ f. write_str( $error_display)
969+ }
970+ }
971+
972+ impl std:: error:: Error for $error_ty {
973+ fn source( & self ) -> Option <& ( dyn std:: error:: Error + ' static ) > {
974+ Some ( & self . 0 )
975+ }
976+ }
977+
978+ impl $crate:: encoding:: Decoder for $outer_ty {
979+ type Output = $target_ty;
980+ type Error = $error_ty;
981+
982+ fn push_bytes(
983+ & mut self ,
984+ bytes: & mut & [ u8 ] ,
985+ ) -> Result <$crate:: encoding:: DecoderStatus , Self :: Error > {
986+ self . 0
987+ . push_bytes( bytes)
988+ . map_err( $error_ty)
989+ }
990+
991+ fn end( self ) -> Result <Self :: Output , Self :: Error > {
992+ let $output = self . 0
993+ . end( )
994+ . map_err( $error_ty) ?;
995+ let converted = {
996+ $( $output_fn_inner) *
997+ } ;
998+ converted. map_err( $error_ty)
999+ }
1000+
1001+ fn read_limit( & self ) -> usize {
1002+ self . 0 . read_limit( )
1003+ }
1004+ }
1005+
1006+ impl $crate:: encoding:: Decode for $target_ty{
1007+ type Decoder = $outer_ty;
1008+ }
1009+ } ;
1010+ // With inner error enum
8801011 (
8811012 $( #[ $( $struct_attr: tt) * ] ) *
8821013 pub struct $outer_ty: ident( $inner_ty: ty) ;
0 commit comments