1#[macro_export]
10macro_rules! dyn_newtype_define {
11 ( $(#[$outer:meta])*
12 $vis:vis $name:ident<$lifetime:lifetime>(Box<$trait:ident>)
13 ) => {
14 $crate::_dyn_newtype_define_inner!{
15 $(#[$outer])*
16 $vis $name<$lifetime>(Box<$trait>)
17 }
18 $crate::_dyn_newtype_impl_deref_mut!($name<$lifetime>);
19 };
20 ( $(#[$outer:meta])*
21 $vis:vis $name:ident(Box<$trait:ident>)
22 ) => {
23 $crate::_dyn_newtype_define_inner!{
24 $(#[$outer])*
25 $vis $name(Box<$trait>)
26 }
27 $crate::_dyn_newtype_impl_deref_mut!($name);
28 };
29 ( $(#[$outer:meta])*
30 $vis:vis $name:ident<$lifetime:lifetime>(Arc<$trait:ident>)
31 ) => {
32 $crate::_dyn_newtype_define_inner!{
33 $(#[$outer])*
34 $vis $name<$lifetime>(Arc<$trait>)
35 }
36 };
37 ( $(#[$outer:meta])*
38 $vis:vis $name:ident(Arc<$trait:ident>)
39 ) => {
40 $crate::_dyn_newtype_define_inner!{
41 $(#[$outer])*
42 $vis $name(Arc<$trait>)
43 }
44 };
45}
46
47#[macro_export]
48macro_rules! _dyn_newtype_define_inner {
49 ( $(#[$outer:meta])*
50 $vis:vis $name:ident($container:ident<$trait:ident>)
51 ) => {
52 $(#[$outer])*
53 $vis struct $name { inner: $container<$crate::maybe_add_send_sync!(dyn $trait + 'static)> }
54
55 impl std::ops::Deref for $name {
56 type Target = $crate::maybe_add_send_sync!(dyn $trait + 'static);
57
58 fn deref(&self) -> &<Self as std::ops::Deref>::Target {
59 &*self.inner
60 }
61
62 }
63
64 impl $name {
65 pub fn get_mut(&mut self) -> Option<&mut <Self as std::ops::Deref>::Target> {
66 Arc::get_mut(&mut self.inner)
67 }
68 }
69
70 impl<I> From<I> for $name
71 where
72 I: $trait + $crate::task::MaybeSend + $crate::task::MaybeSync + 'static,
73 {
74 fn from(i: I) -> Self {
75 Self { inner: $container::new(i) }
76 }
77 }
78
79 impl std::fmt::Debug for $name {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 std::fmt::Debug::fmt(&self.inner, f)
82 }
83 }
84 };
85 ( $(#[$outer:meta])*
86 $vis:vis $name:ident<$lifetime:lifetime>($container:ident<$trait:ident>)
87 ) => {
88 $(#[$outer])*
89 $vis struct $name<$lifetime> { inner: $container<dyn $trait<$lifetime> + Send + $lifetime> }
90
91 impl<$lifetime> std::ops::Deref for $name<$lifetime> {
92 type Target = $crate::maybe_add_send!(dyn $trait<$lifetime> + $lifetime);
93
94 fn deref(&self) -> &<Self as std::ops::Deref>::Target {
95 &*self.inner
96 }
97 }
98
99 impl<$lifetime, I> From<I> for $name<$lifetime>
100 where
101 I: $trait<$lifetime> + $crate::task::MaybeSend + $lifetime,
102 {
103 fn from(i: I) -> Self {
104 Self($container::new(i))
105 }
106 }
107 };
108}
109
110#[macro_export]
113macro_rules! dyn_newtype_display_passthrough {
114 ($newtype:ty) => {
115 impl std::fmt::Display for $newtype {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 std::fmt::Display::fmt(&self.inner, f)
118 }
119 }
120 };
121}
122
123#[macro_export]
126macro_rules! module_plugin_dyn_newtype_define{
127 ( $(#[$outer:meta])*
128 $vis:vis $name:ident<$lifetime:lifetime>(Box<$trait:ident>)
129 ) => {
130 $crate::_dyn_newtype_define_with_instance_id_inner!{
131 $(#[$outer])*
132 $vis $name<$lifetime>(Box<$trait>)
133 }
134 $crate::_dyn_newtype_impl_deref_mut!($name<$lifetime>);
135 };
136 ( $(#[$outer:meta])*
137 $vis:vis $name:ident(Box<$trait:ident>)
138 ) => {
139 $crate::_dyn_newtype_define_with_instance_id_inner!{
140 $(#[$outer])*
141 $vis $name(Box<$trait>)
142 }
143 $crate::_dyn_newtype_impl_deref_mut!($name);
144 };
145 ( $(#[$outer:meta])*
146 $vis:vis $name:ident<$lifetime:lifetime>(Arc<$trait:ident>)
147 ) => {
148 $crate::_dyn_newtype_define_with_instance_id_inner!{
149 $(#[$outer])*
150 $vis $name<$lifetime>(Arc<$trait>)
151 }
152 };
153 ( $(#[$outer:meta])*
154 $vis:vis $name:ident(Arc<$trait:ident>)
155 ) => {
156 $crate::_dyn_newtype_define_with_instance_id_inner!{
157 $(#[$outer])*
158 $vis $name(Arc<$trait>)
159 }
160 };
161}
162
163#[macro_export]
164macro_rules! _dyn_newtype_define_with_instance_id_inner {
165 ( $(#[$outer:meta])*
166 $vis:vis $name:ident($container:ident<$trait:ident>)
167 ) => {
168 $(#[$outer])*
169 $vis struct $name {
170 module_instance_id: $crate::core::ModuleInstanceId,
171 inner: $container<$crate::maybe_add_send_sync!(dyn $trait + 'static)>,
172 }
173
174 impl std::ops::Deref for $name {
175 type Target = $crate::maybe_add_send_sync!(dyn $trait + 'static);
176
177 fn deref(&self) -> &<Self as std::ops::Deref>::Target {
178 &*self.inner
179 }
180
181 }
182
183 impl $name {
184 pub fn module_instance_id(&self) -> ::fedimint_core::core::ModuleInstanceId {
185 self.module_instance_id
186 }
187
188 pub fn from_typed<I>(
189 module_instance_id: ::fedimint_core::core::ModuleInstanceId,
190 typed: I
191 ) -> Self
192 where
193 I: $trait + $crate::task::MaybeSend + $crate::task::MaybeSync + 'static {
194
195 Self { inner: $container::new(typed), module_instance_id }
196 }
197
198 pub fn from_parts(
199 module_instance_id: $crate::core::ModuleInstanceId,
200 dynbox: $container<$crate::maybe_add_send_sync!(dyn $trait + 'static)>
201 ) -> Self {
202 Self { inner: dynbox, module_instance_id }
203 }
204 }
205
206 impl std::fmt::Debug for $name {
207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208 f.debug_struct(stringify!($name))
209 .field("id", &self.module_instance_id)
210 .field("kind", &self.module_kind())
211 .field("inner", &self.inner)
212 .finish()
213 }
214 }
215 };
216 ( $(#[$outer:meta])*
217 $vis:vis $name:ident<$lifetime:lifetime>($container:ident<$trait:ident>)
218 ) => {
219 $(#[$outer])*
220 $vis struct $name<$lifetime>{ inner: $container<dyn $trait<$lifetime> + Send + $lifetime>, module_instance_id: ModuleInstanceId }
221
222 impl $name {
223 pub fn module_instance_id(&self) -> ::fedimint_core::core::ModuleInstanceId {
224 self.1
225 }
226
227 pub fn from_typed<I>(module_instance_id: ::fedimint_core::core::ModuleInstanceId, typed: I) -> Self
228 where
229 I: $trait + $crate::task::MaybeSend + $crate::task::MaybeSync + 'static {
230
231 Self { inner: $container::new(typed), module_instance_id }
232 }
233 }
234
235 impl<$lifetime> std::ops::Deref for $name<$lifetime> {
236 type Target = $crate::maybe_add_send_sync!(dyn $trait + 'static);
237
238 fn deref(&self) -> &<Self as std::ops::Deref>::Target {
239 &*self.inner
240 }
241 }
242 };
243}
244
245#[macro_export]
246macro_rules! _dyn_newtype_impl_deref_mut {
247 ($name:ident<$lifetime:lifetime>) => {
248 impl<$lifetime> std::ops::DerefMut for $name<$lifetime> {
249 fn deref_mut(&mut self) -> &mut <Self as std::ops::Deref>::Target {
250 &mut *self.inner
251 }
252 }
253 };
254 ($name:ident) => {
255 impl std::ops::DerefMut for $name {
256 fn deref_mut(&mut self) -> &mut <Self as std::ops::Deref>::Target {
257 &mut *self.inner
258 }
259 }
260 };
261}
262
263#[macro_export]
278macro_rules! dyn_newtype_impl_dyn_clone_passthrough {
279 ($name:ident) => {
280 impl Clone for $name {
281 fn clone(&self) -> Self {
282 self.0.clone()
283 }
284 }
285 };
286}
287
288#[macro_export]
289macro_rules! module_plugin_dyn_newtype_clone_passthrough {
290 ($name:ident) => {
291 impl Clone for $name {
292 fn clone(&self) -> Self {
293 self.inner.clone(self.module_instance_id)
294 }
295 }
296 };
297}
298
299#[macro_export]
304macro_rules! module_plugin_dyn_newtype_encode_decode {
305 ($name:ident) => {
306 impl Encodable for $name {
307 fn consensus_encode<W: std::io::Write>(
308 &self,
309 writer: &mut W,
310 ) -> Result<usize, std::io::Error> {
311 let mut written = self.module_instance_id.consensus_encode(writer)?;
312
313 let mut buf = Vec::with_capacity(512);
314 let buf_written = self.inner.consensus_encode_dyn(&mut buf)?;
315 assert_eq!(buf.len(), buf_written);
316
317 written += buf.consensus_encode(writer)?;
318
319 Ok(written)
320 }
321 }
322
323 impl Decodable for $name {
324 fn consensus_decode_from_finite_reader<R: std::io::Read>(
325 reader: &mut R,
326 decoders: &$crate::module::registry::ModuleDecoderRegistry,
327 ) -> Result<Self, fedimint_core::encoding::DecodeError> {
328 let module_instance_id =
329 fedimint_core::core::ModuleInstanceId::consensus_decode_from_finite_reader(
330 reader, decoders,
331 )?;
332 let val = match decoders.get(module_instance_id) {
333 Some(decoder) => {
334 let total_len_u64 =
335 u64::consensus_decode_from_finite_reader(reader, decoders)?;
336 decoder.decode_complete(
337 reader,
338 total_len_u64,
339 module_instance_id,
340 decoders,
341 )?
342 }
343 None => match decoders.decoding_mode() {
344 $crate::module::registry::DecodingMode::Reject => {
345 return Err(fedimint_core::encoding::DecodeError::new_custom(
346 anyhow::anyhow!(
347 "Module decoder not available: {module_instance_id} when decoding {}", std::any::type_name::<Self>()
348 ),
349 ));
350 }
351 $crate::module::registry::DecodingMode::Fallback => $name::from_typed(
352 module_instance_id,
353 $crate::core::DynUnknown(
354 Vec::<u8>::consensus_decode_from_finite_reader(
355 reader,
356 &Default::default(),
357 )?,
358 ),
359 ),
360 },
361 };
362
363 Ok(val)
364 }
365 }
366 };
367}
368
369#[macro_export]
380macro_rules! module_plugin_static_trait_define{
381 ( $(#[$outer:meta])*
382 $dyn_newtype:ident, $static_trait:ident, $dyn_trait:ident, { $($extra_methods:tt)* }, { $($extra_impls:tt)* }
383 ) => {
384 pub trait $static_trait:
385 std::fmt::Debug + std::fmt::Display + std::cmp::PartialEq + std::hash::Hash + DynEncodable + Decodable + Encodable + Clone + IntoDynInstance<DynType = $dyn_newtype> + Send + Sync + 'static
386 {
387 const KIND : ModuleKind;
388
389 $($extra_methods)*
390 }
391
392 impl $dyn_trait for ::fedimint_core::core::DynUnknown {
393 fn as_any(&self) -> &(dyn Any + Send + Sync) {
394 self
395 }
396
397 fn module_kind(&self) -> Option<ModuleKind> {
398 None
399 }
400
401 fn clone(&self, instance_id: ::fedimint_core::core::ModuleInstanceId) -> $dyn_newtype {
402 $dyn_newtype::from_typed(instance_id, <Self as Clone>::clone(self))
403 }
404
405 fn dyn_hash(&self) -> u64 {
406 use std::hash::Hash;
407 let mut s = std::collections::hash_map::DefaultHasher::new();
408 self.hash(&mut s);
409 std::hash::Hasher::finish(&s)
410 }
411
412 $($extra_impls)*
413 }
414
415 impl<T> $dyn_trait for T
416 where
417 T: $static_trait + DynEncodable + 'static + Send + Sync,
418 {
419 fn as_any(&self) -> &(dyn Any + Send + Sync) {
420 self
421 }
422
423 fn module_kind(&self) -> Option<ModuleKind> {
424 Some(<Self as $static_trait>::KIND)
425 }
426
427 fn clone(&self, instance_id: ::fedimint_core::core::ModuleInstanceId) -> $dyn_newtype {
428 $dyn_newtype::from_typed(instance_id, <Self as Clone>::clone(self))
429 }
430
431 fn dyn_hash(&self) -> u64 {
432 let mut s = std::collections::hash_map::DefaultHasher::new();
433 self.hash(&mut s);
434 std::hash::Hasher::finish(&s)
435 }
436
437 $($extra_impls)*
438 }
439
440 impl std::hash::Hash for $dyn_newtype {
441 fn hash<H>(&self, state: &mut H)
442 where
443 H: std::hash::Hasher
444 {
445 self.module_instance_id.hash(state);
446 self.inner.dyn_hash().hash(state);
447 }
448 }
449 };
450}
451
452#[macro_export]
458macro_rules! module_plugin_static_trait_define_config{
459 ( $(#[$outer:meta])*
460 $dyn_newtype:ident, $static_trait:ident, $dyn_trait:ident, { $($extra_methods:tt)* }, { $($extra_impls:tt)* }, { $($extra_impls_unknown:tt)* }
461 ) => {
462 pub trait $static_trait:
463 std::fmt::Debug + std::fmt::Display + std::cmp::PartialEq + std::hash::Hash + DynEncodable + Decodable + Encodable + Clone + IntoDynInstance<DynType = $dyn_newtype> + Send + Sync + serde::Serialize + serde::de::DeserializeOwned + 'static
464 {
465 const KIND : ::fedimint_core::core::ModuleKind;
466 $($extra_methods)*
467 }
468
469 impl $dyn_trait for ::fedimint_core::core::DynUnknown {
470 fn as_any(&self) -> &(dyn Any + Send + Sync) {
471 self
472 }
473
474 fn module_kind(&self) -> Option<::fedimint_core::core::ModuleKind> {
475 None
476 }
477
478 fn clone(&self, instance_id: ::fedimint_core::core::ModuleInstanceId) -> $dyn_newtype {
479 $dyn_newtype::from_typed(instance_id, <Self as Clone>::clone(self))
480 }
481
482 fn dyn_hash(&self) -> u64 {
483 use std::hash::Hash;
484 let mut s = std::collections::hash_map::DefaultHasher::new();
485 self.hash(&mut s);
486 std::hash::Hasher::finish(&s)
487 }
488
489 $($extra_impls_unknown)*
490 }
491
492 impl<T> $dyn_trait for T
493 where
494 T: $static_trait + DynEncodable + 'static + Send + Sync,
495 {
496 fn as_any(&self) -> &(dyn Any + Send + Sync) {
497 self
498 }
499
500 fn module_kind(&self) -> Option<::fedimint_core::core::ModuleKind> {
501 Some(<T as $static_trait>::KIND)
502 }
503
504 fn clone(&self, instance_id: ::fedimint_core::core::ModuleInstanceId) -> $dyn_newtype {
505 $dyn_newtype::from_typed(instance_id, <Self as Clone>::clone(self))
506 }
507
508 fn dyn_hash(&self) -> u64 {
509 let mut s = std::collections::hash_map::DefaultHasher::new();
510 self.hash(&mut s);
511 std::hash::Hasher::finish(&s)
512 }
513
514 $($extra_impls)*
515 }
516
517 impl std::hash::Hash for $dyn_newtype {
518 fn hash<H>(&self, state: &mut H)
519 where
520 H: std::hash::Hasher
521 {
522 self.module_instance_id.hash(state);
523 self.inner.dyn_hash().hash(state);
524 }
525 }
526 };
527}
528
529#[macro_export]
532macro_rules! plugin_types_trait_impl_config {
533 ($common_gen:ty, $gen:ty, $gen_local:ty, $gen_consensus:ty, $cfg:ty, $cfg_local:ty, $cfg_private:ty, $cfg_consensus:ty, $cfg_client:ty) => {
534 impl fedimint_core::config::ModuleInitParams for $gen {
535 type Local = $gen_local;
536 type Consensus = $gen_consensus;
537
538 fn from_parts(local: Self::Local, consensus: Self::Consensus) -> Self {
539 Self { local, consensus }
540 }
541
542 fn to_parts(self) -> (Self::Local, Self::Consensus) {
543 (self.local, self.consensus)
544 }
545 }
546
547 impl fedimint_core::config::TypedServerModuleConsensusConfig for $cfg_consensus {
548 fn kind(&self) -> fedimint_core::core::ModuleKind {
549 <$common_gen as fedimint_core::module::CommonModuleInit>::KIND
550 }
551
552 fn version(&self) -> fedimint_core::module::ModuleConsensusVersion {
553 <$common_gen as fedimint_core::module::CommonModuleInit>::CONSENSUS_VERSION
554 }
555 }
556
557 impl fedimint_core::config::TypedServerModuleConfig for $cfg {
558 type Local = $cfg_local;
559 type Private = $cfg_private;
560 type Consensus = $cfg_consensus;
561
562 fn from_parts(
563 local: Self::Local,
564 private: Self::Private,
565 consensus: Self::Consensus,
566 ) -> Self {
567 Self {
568 local,
569 private,
570 consensus,
571 }
572 }
573
574 fn to_parts(self) -> (ModuleKind, Self::Local, Self::Private, Self::Consensus) {
575 (
576 <$common_gen as fedimint_core::module::CommonModuleInit>::KIND,
577 self.local,
578 self.private,
579 self.consensus,
580 )
581 }
582 }
583 };
584}
585
586#[macro_export]
589macro_rules! plugin_types_trait_impl_common {
590 ($kind:expr, $types:ty, $client_config:ty, $input:ty, $output:ty, $outcome:ty, $ci:ty, $input_error:ty, $output_error:ty) => {
591 impl fedimint_core::module::ModuleCommon for $types {
592 type ClientConfig = $client_config;
593 type Input = $input;
594 type Output = $output;
595 type OutputOutcome = $outcome;
596 type ConsensusItem = $ci;
597 type InputError = $input_error;
598 type OutputError = $output_error;
599 }
600
601 impl fedimint_core::core::ClientConfig for $client_config {
602 const KIND: ModuleKind = $kind;
603 }
604
605 impl fedimint_core::core::IntoDynInstance for $client_config {
606 type DynType = fedimint_core::core::DynClientConfig;
607
608 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
609 fedimint_core::core::DynClientConfig::from_typed(instance_id, self)
610 }
611 }
612
613 impl fedimint_core::core::Input for $input {
614 const KIND: ModuleKind = $kind;
615 }
616
617 impl fedimint_core::core::IntoDynInstance for $input {
618 type DynType = fedimint_core::core::DynInput;
619
620 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
621 fedimint_core::core::DynInput::from_typed(instance_id, self)
622 }
623 }
624
625 impl fedimint_core::core::Output for $output {
626 const KIND: ModuleKind = $kind;
627 }
628
629 impl fedimint_core::core::IntoDynInstance for $output {
630 type DynType = fedimint_core::core::DynOutput;
631
632 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
633 fedimint_core::core::DynOutput::from_typed(instance_id, self)
634 }
635 }
636
637 impl fedimint_core::core::OutputOutcome for $outcome {
638 const KIND: ModuleKind = $kind;
639 }
640
641 impl fedimint_core::core::IntoDynInstance for $outcome {
642 type DynType = fedimint_core::core::DynOutputOutcome;
643
644 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
645 fedimint_core::core::DynOutputOutcome::from_typed(instance_id, self)
646 }
647 }
648
649 impl fedimint_core::core::ModuleConsensusItem for $ci {
650 const KIND: ModuleKind = $kind;
651 }
652
653 impl fedimint_core::core::IntoDynInstance for $ci {
654 type DynType = fedimint_core::core::DynModuleConsensusItem;
655
656 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
657 fedimint_core::core::DynModuleConsensusItem::from_typed(instance_id, self)
658 }
659 }
660
661 impl fedimint_core::core::InputError for $input_error {
662 const KIND: ModuleKind = $kind;
663 }
664
665 impl fedimint_core::core::IntoDynInstance for $input_error {
666 type DynType = fedimint_core::core::DynInputError;
667
668 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
669 fedimint_core::core::DynInputError::from_typed(instance_id, self)
670 }
671 }
672
673 impl fedimint_core::core::OutputError for $output_error {
674 const KIND: ModuleKind = $kind;
675 }
676
677 impl fedimint_core::core::IntoDynInstance for $output_error {
678 type DynType = fedimint_core::core::DynOutputError;
679
680 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
681 fedimint_core::core::DynOutputError::from_typed(instance_id, self)
682 }
683 }
684 };
685}
686
687#[macro_export]
688macro_rules! erased_eq_no_instance_id {
689 ($newtype:ty) => {
690 fn erased_eq_no_instance_id(&self, other: &$newtype) -> bool {
691 let other: &Self = other
692 .as_any()
693 .downcast_ref()
694 .expect("Type is ensured in previous step");
695
696 self == other
697 }
698 };
699}
700
701#[macro_export]
702macro_rules! module_plugin_dyn_newtype_eq_passthrough {
703 ($newtype:ty) => {
704 impl PartialEq for $newtype {
705 fn eq(&self, other: &Self) -> bool {
706 if self.module_instance_id != other.module_instance_id {
707 return false;
708 }
709 self.erased_eq_no_instance_id(other)
710 }
711 }
712
713 impl Eq for $newtype {}
714 };
715}
716
717#[macro_export]
718macro_rules! module_plugin_dyn_newtype_display_passthrough {
719 ($newtype:ty) => {
720 impl std::fmt::Display for $newtype {
721 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
722 f.write_fmt(format_args!("{}-{}", self.module_instance_id, self.inner))
723 }
724 }
725 };
726}
727
728#[macro_export]
741macro_rules! extensible_associated_module_type {
742 ($name:ident, $name_v0:ident, $error:ident) => {
743 #[derive(
744 Debug,
745 Clone,
746 Eq,
747 PartialEq,
748 Hash,
749 serde::Deserialize,
750 serde::Serialize,
751 fedimint_core::encoding::Encodable,
752 fedimint_core::encoding::Decodable,
753 )]
754 pub enum $name {
755 V0($name_v0),
756 #[encodable_default]
757 Default {
758 variant: u64,
759 bytes: Vec<u8>,
760 },
761 }
762
763 impl $name {
764 pub fn maybe_v0_ref(&self) -> Option<&$name_v0> {
765 match self {
766 $name::V0(v0) => Some(v0),
767 $name::Default { .. } => None,
768 }
769 }
770
771 pub fn ensure_v0_ref(&self) -> Result<&$name_v0, $error> {
772 match self {
773 $name::V0(v0) => Ok(v0),
774 $name::Default { variant, .. } => Err($error { variant: *variant }),
775 }
776 }
777 }
778
779 #[derive(
780 Debug,
781 thiserror::Error,
782 Clone,
783 Eq,
784 PartialEq,
785 Hash,
786 serde::Deserialize,
787 serde::Serialize,
788 fedimint_core::encoding::Encodable,
789 fedimint_core::encoding::Decodable,
790 )]
791 #[error("Unknown {} variant {variant}", stringify!($name))]
792 pub struct $error {
793 pub variant: u64,
794 }
795
796 impl std::fmt::Display for $name {
797 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
798 match self {
799 $name::V0(inner) => std::fmt::Display::fmt(inner, f),
800 $name::Default { variant, .. } => {
801 write!(f, "Unknown {} (variant={variant})", stringify!($name))
802 }
803 }
804 }
805 }
806 };
807}