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 let mut d = f.debug_struct(stringify!($name));
209 d.field("id", &self.module_instance_id);
210 if let Some(kind) = self.module_kind() {
211 d.field("kind", &kind);
212 } else {
213 d.field("kind", &"?");
214
215 }
216 d
217 .field("inner", &self.inner)
218 .finish()
219 }
220 }
221 };
222 ( $(#[$outer:meta])*
223 $vis:vis $name:ident<$lifetime:lifetime>($container:ident<$trait:ident>)
224 ) => {
225 $(#[$outer])*
226 $vis struct $name<$lifetime>{ inner: $container<dyn $trait<$lifetime> + Send + $lifetime>, module_instance_id: ModuleInstanceId }
227
228 impl $name {
229 pub fn module_instance_id(&self) -> ::fedimint_core::core::ModuleInstanceId {
230 self.1
231 }
232
233 pub fn from_typed<I>(module_instance_id: ::fedimint_core::core::ModuleInstanceId, typed: I) -> Self
234 where
235 I: $trait + $crate::task::MaybeSend + $crate::task::MaybeSync + 'static {
236
237 Self { inner: $container::new(typed), module_instance_id }
238 }
239 }
240
241 impl<$lifetime> std::ops::Deref for $name<$lifetime> {
242 type Target = $crate::maybe_add_send_sync!(dyn $trait + 'static);
243
244 fn deref(&self) -> &<Self as std::ops::Deref>::Target {
245 &*self.inner
246 }
247 }
248 };
249}
250
251#[macro_export]
252macro_rules! _dyn_newtype_impl_deref_mut {
253 ($name:ident<$lifetime:lifetime>) => {
254 impl<$lifetime> std::ops::DerefMut for $name<$lifetime> {
255 fn deref_mut(&mut self) -> &mut <Self as std::ops::Deref>::Target {
256 &mut *self.inner
257 }
258 }
259 };
260 ($name:ident) => {
261 impl std::ops::DerefMut for $name {
262 fn deref_mut(&mut self) -> &mut <Self as std::ops::Deref>::Target {
263 &mut *self.inner
264 }
265 }
266 };
267}
268
269#[macro_export]
284macro_rules! dyn_newtype_impl_dyn_clone_passthrough {
285 ($name:ident) => {
286 impl Clone for $name {
287 fn clone(&self) -> Self {
288 self.0.clone()
289 }
290 }
291 };
292}
293
294#[macro_export]
295macro_rules! module_plugin_dyn_newtype_clone_passthrough {
296 ($name:ident) => {
297 impl Clone for $name {
298 fn clone(&self) -> Self {
299 self.inner.clone(self.module_instance_id)
300 }
301 }
302 };
303}
304
305#[macro_export]
310macro_rules! module_plugin_dyn_newtype_encode_decode {
311 ($name:ident) => {
312 impl Encodable for $name {
313 fn consensus_encode<W: std::io::Write>(
314 &self,
315 writer: &mut W,
316 ) -> Result<(), std::io::Error> {
317 self.module_instance_id.consensus_encode(writer)?;
318
319 let mut buf = Vec::with_capacity(512);
320 self.inner.consensus_encode_dyn(&mut buf)?;
321
322 buf.consensus_encode(writer)?;
323
324 Ok(())
325 }
326 }
327
328 impl Decodable for $name {
329 fn consensus_decode_partial_from_finite_reader<R: std::io::Read>(
330 reader: &mut R,
331 decoders: &$crate::module::registry::ModuleDecoderRegistry,
332 ) -> Result<Self, fedimint_core::encoding::DecodeError> {
333 let module_instance_id =
334 fedimint_core::core::ModuleInstanceId::consensus_decode_partial_from_finite_reader(
335 reader, decoders,
336 )?;
337 let val = match decoders.get(module_instance_id) {
338 Some(decoder) => {
339 let total_len_u64 =
340 u64::consensus_decode_partial_from_finite_reader(reader, decoders)?;
341 decoder.decode_complete(
342 reader,
343 total_len_u64,
344 module_instance_id,
345 decoders,
346 )?
347 }
348 None => match decoders.decoding_mode() {
349 $crate::module::registry::DecodingMode::Reject => {
350 return Err(fedimint_core::encoding::DecodeError::new_custom(
351 anyhow::anyhow!(
352 "Module decoder not available for module instance: {module_instance_id} when decoding {}", std::any::type_name::<Self>()
353 ),
354 ));
355 }
356 $crate::module::registry::DecodingMode::Fallback => $name::from_typed(
357 module_instance_id,
358 $crate::core::DynUnknown(
359 Vec::<u8>::consensus_decode_partial_from_finite_reader(
360 reader,
361 &Default::default(),
362 )?,
363 ),
364 ),
365 },
366 };
367
368 Ok(val)
369 }
370 }
371 };
372}
373
374#[macro_export]
385macro_rules! module_plugin_static_trait_define{
386 ( $(#[$outer:meta])*
387 $dyn_newtype:ident, $static_trait:ident, $dyn_trait:ident, { $($extra_methods:tt)* }, { $($extra_impls:tt)* }
388 ) => {
389 pub trait $static_trait:
390 std::fmt::Debug + std::fmt::Display + std::cmp::PartialEq + std::hash::Hash + DynEncodable + Decodable + Encodable + Clone + IntoDynInstance<DynType = $dyn_newtype> + Send + Sync + 'static
391 {
392 const KIND : ModuleKind;
393
394 $($extra_methods)*
395 }
396
397 impl $dyn_trait for ::fedimint_core::core::DynUnknown {
398 fn as_any(&self) -> &(dyn Any + Send + Sync) {
399 self
400 }
401
402 fn module_kind(&self) -> Option<ModuleKind> {
403 None
404 }
405
406 fn clone(&self, instance_id: ::fedimint_core::core::ModuleInstanceId) -> $dyn_newtype {
407 $dyn_newtype::from_typed(instance_id, <Self as Clone>::clone(self))
408 }
409
410 fn dyn_hash(&self) -> u64 {
411 use std::hash::Hash;
412 let mut s = std::collections::hash_map::DefaultHasher::new();
413 self.hash(&mut s);
414 std::hash::Hasher::finish(&s)
415 }
416
417 $($extra_impls)*
418 }
419
420 impl<T> $dyn_trait for T
421 where
422 T: $static_trait + DynEncodable + 'static + Send + Sync,
423 {
424 fn as_any(&self) -> &(dyn Any + Send + Sync) {
425 self
426 }
427
428 fn module_kind(&self) -> Option<ModuleKind> {
429 Some(<Self as $static_trait>::KIND)
430 }
431
432 fn clone(&self, instance_id: ::fedimint_core::core::ModuleInstanceId) -> $dyn_newtype {
433 $dyn_newtype::from_typed(instance_id, <Self as Clone>::clone(self))
434 }
435
436 fn dyn_hash(&self) -> u64 {
437 let mut s = std::collections::hash_map::DefaultHasher::new();
438 self.hash(&mut s);
439 std::hash::Hasher::finish(&s)
440 }
441
442 $($extra_impls)*
443 }
444
445 impl std::hash::Hash for $dyn_newtype {
446 fn hash<H>(&self, state: &mut H)
447 where
448 H: std::hash::Hasher
449 {
450 self.module_instance_id.hash(state);
451 self.inner.dyn_hash().hash(state);
452 }
453 }
454 };
455}
456
457#[macro_export]
463macro_rules! module_plugin_static_trait_define_config{
464 ( $(#[$outer:meta])*
465 $dyn_newtype:ident, $static_trait:ident, $dyn_trait:ident, { $($extra_methods:tt)* }, { $($extra_impls:tt)* }, { $($extra_impls_unknown:tt)* }
466 ) => {
467 pub trait $static_trait:
468 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
469 {
470 const KIND : ::fedimint_core::core::ModuleKind;
471 $($extra_methods)*
472 }
473
474 impl $dyn_trait for ::fedimint_core::core::DynUnknown {
475 fn as_any(&self) -> &(dyn Any + Send + Sync) {
476 self
477 }
478
479 fn module_kind(&self) -> Option<::fedimint_core::core::ModuleKind> {
480 None
481 }
482
483 fn clone(&self, instance_id: ::fedimint_core::core::ModuleInstanceId) -> $dyn_newtype {
484 $dyn_newtype::from_typed(instance_id, <Self as Clone>::clone(self))
485 }
486
487 fn dyn_hash(&self) -> u64 {
488 use std::hash::Hash;
489 let mut s = std::collections::hash_map::DefaultHasher::new();
490 self.hash(&mut s);
491 std::hash::Hasher::finish(&s)
492 }
493
494 $($extra_impls_unknown)*
495 }
496
497 impl<T> $dyn_trait for T
498 where
499 T: $static_trait + DynEncodable + 'static + Send + Sync,
500 {
501 fn as_any(&self) -> &(dyn Any + Send + Sync) {
502 self
503 }
504
505 fn module_kind(&self) -> Option<::fedimint_core::core::ModuleKind> {
506 Some(<T as $static_trait>::KIND)
507 }
508
509 fn clone(&self, instance_id: ::fedimint_core::core::ModuleInstanceId) -> $dyn_newtype {
510 $dyn_newtype::from_typed(instance_id, <Self as Clone>::clone(self))
511 }
512
513 fn dyn_hash(&self) -> u64 {
514 let mut s = std::collections::hash_map::DefaultHasher::new();
515 self.hash(&mut s);
516 std::hash::Hasher::finish(&s)
517 }
518
519 $($extra_impls)*
520 }
521
522 impl std::hash::Hash for $dyn_newtype {
523 fn hash<H>(&self, state: &mut H)
524 where
525 H: std::hash::Hasher
526 {
527 self.module_instance_id.hash(state);
528 self.inner.dyn_hash().hash(state);
529 }
530 }
531 };
532}
533
534#[macro_export]
537macro_rules! plugin_types_trait_impl_config {
538 ($common_gen:ty, $cfg:ty, $cfg_private:ty, $cfg_consensus:ty, $cfg_client:ty) => {
539 impl fedimint_core::config::TypedServerModuleConsensusConfig for $cfg_consensus {
540 fn kind(&self) -> fedimint_core::core::ModuleKind {
541 <$common_gen as fedimint_core::module::CommonModuleInit>::KIND
542 }
543
544 fn version(&self) -> fedimint_core::module::ModuleConsensusVersion {
545 <$common_gen as fedimint_core::module::CommonModuleInit>::CONSENSUS_VERSION
546 }
547 }
548
549 impl fedimint_core::config::TypedServerModuleConfig for $cfg {
550 type Private = $cfg_private;
551 type Consensus = $cfg_consensus;
552
553 fn from_parts(private: Self::Private, consensus: Self::Consensus) -> Self {
554 Self { private, consensus }
555 }
556
557 fn to_parts(self) -> (ModuleKind, Self::Private, Self::Consensus) {
558 (
559 <$common_gen as fedimint_core::module::CommonModuleInit>::KIND,
560 self.private,
561 self.consensus,
562 )
563 }
564 }
565 };
566}
567
568#[macro_export]
571macro_rules! plugin_types_trait_impl_common {
572 ($kind:expr_2021, $types:ty, $client_config:ty, $input:ty, $output:ty, $outcome:ty, $ci:ty, $input_error:ty, $output_error:ty) => {
573 impl fedimint_core::module::ModuleCommon for $types {
574 type ClientConfig = $client_config;
575 type Input = $input;
576 type Output = $output;
577 type OutputOutcome = $outcome;
578 type ConsensusItem = $ci;
579 type InputError = $input_error;
580 type OutputError = $output_error;
581 }
582
583 impl fedimint_core::core::ClientConfig for $client_config {
584 const KIND: ModuleKind = $kind;
585 }
586
587 impl fedimint_core::core::IntoDynInstance for $client_config {
588 type DynType = fedimint_core::core::DynClientConfig;
589
590 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
591 fedimint_core::core::DynClientConfig::from_typed(instance_id, self)
592 }
593 }
594
595 impl fedimint_core::core::Input for $input {
596 const KIND: ModuleKind = $kind;
597 }
598
599 impl fedimint_core::core::IntoDynInstance for $input {
600 type DynType = fedimint_core::core::DynInput;
601
602 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
603 fedimint_core::core::DynInput::from_typed(instance_id, self)
604 }
605 }
606
607 impl fedimint_core::core::Output for $output {
608 const KIND: ModuleKind = $kind;
609 }
610
611 impl fedimint_core::core::IntoDynInstance for $output {
612 type DynType = fedimint_core::core::DynOutput;
613
614 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
615 fedimint_core::core::DynOutput::from_typed(instance_id, self)
616 }
617 }
618
619 impl fedimint_core::core::OutputOutcome for $outcome {
620 const KIND: ModuleKind = $kind;
621 }
622
623 impl fedimint_core::core::IntoDynInstance for $outcome {
624 type DynType = fedimint_core::core::DynOutputOutcome;
625
626 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
627 fedimint_core::core::DynOutputOutcome::from_typed(instance_id, self)
628 }
629 }
630
631 impl fedimint_core::core::ModuleConsensusItem for $ci {
632 const KIND: ModuleKind = $kind;
633 }
634
635 impl fedimint_core::core::IntoDynInstance for $ci {
636 type DynType = fedimint_core::core::DynModuleConsensusItem;
637
638 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
639 fedimint_core::core::DynModuleConsensusItem::from_typed(instance_id, self)
640 }
641 }
642
643 impl fedimint_core::core::InputError for $input_error {
644 const KIND: ModuleKind = $kind;
645 }
646
647 impl fedimint_core::core::IntoDynInstance for $input_error {
648 type DynType = fedimint_core::core::DynInputError;
649
650 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
651 fedimint_core::core::DynInputError::from_typed(instance_id, self)
652 }
653 }
654
655 impl fedimint_core::core::OutputError for $output_error {
656 const KIND: ModuleKind = $kind;
657 }
658
659 impl fedimint_core::core::IntoDynInstance for $output_error {
660 type DynType = fedimint_core::core::DynOutputError;
661
662 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
663 fedimint_core::core::DynOutputError::from_typed(instance_id, self)
664 }
665 }
666 };
667}
668
669#[macro_export]
670macro_rules! erased_eq_no_instance_id {
671 ($newtype:ty) => {
672 fn erased_eq_no_instance_id(&self, other: &$newtype) -> bool {
673 let other: &Self = other
674 .as_any()
675 .downcast_ref()
676 .expect("Type is ensured in previous step");
677
678 self == other
679 }
680 };
681}
682
683#[macro_export]
684macro_rules! module_plugin_dyn_newtype_eq_passthrough {
685 ($newtype:ty) => {
686 impl PartialEq for $newtype {
687 fn eq(&self, other: &Self) -> bool {
688 if self.module_instance_id != other.module_instance_id {
689 return false;
690 }
691 self.erased_eq_no_instance_id(other)
692 }
693 }
694
695 impl Eq for $newtype {}
696 };
697}
698
699#[macro_export]
700macro_rules! module_plugin_dyn_newtype_display_passthrough {
701 ($newtype:ty) => {
702 impl std::fmt::Display for $newtype {
703 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
704 f.write_fmt(format_args!("{}-{}", self.module_instance_id, self.inner))
705 }
706 }
707 };
708}
709
710#[macro_export]
723macro_rules! extensible_associated_module_type {
724 ($name:ident, $name_v0:ident, $error:ident) => {
725 #[derive(
726 Clone,
727 Eq,
728 PartialEq,
729 Hash,
730 serde::Deserialize,
731 serde::Serialize,
732 fedimint_core::encoding::Encodable,
733 fedimint_core::encoding::Decodable,
734 )]
735 pub enum $name {
736 V0($name_v0),
737 #[encodable_default]
738 Default {
739 variant: u64,
740 bytes: Vec<u8>,
741 },
742 }
743
744 impl $name {
745 pub fn maybe_v0_ref(&self) -> Option<&$name_v0> {
746 match self {
747 $name::V0(v0) => Some(v0),
748 $name::Default { .. } => None,
749 }
750 }
751
752 pub fn ensure_v0_ref(&self) -> Result<&$name_v0, $error> {
753 match self {
754 $name::V0(v0) => Ok(v0),
755 $name::Default { variant, .. } => Err($error { variant: *variant }),
756 }
757 }
758 }
759
760 impl std::convert::From<$name_v0> for $name {
761 fn from(v: $name_v0) -> Self {
762 Self::V0(v)
763 }
764 }
765
766 impl std::fmt::Debug for $name {
767 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
768 use $crate::bitcoin::hashes::hex::DisplayHex;
769 match self {
770 $name::V0(v0) => {
771 std::fmt::Debug::fmt(v0, f)?;
772 }
773 $name::Default { variant, bytes } => {
774 f.debug_struct(stringify!($name))
775 .field("variant", variant)
776 .field("bytes", &bytes.as_hex())
777 .finish()?;
778 }
779 }
780 Ok(())
781 }
782 }
783
784 #[derive(
785 Debug,
786 thiserror::Error,
787 Clone,
788 Eq,
789 PartialEq,
790 Hash,
791 serde::Deserialize,
792 serde::Serialize,
793 fedimint_core::encoding::Encodable,
794 fedimint_core::encoding::Decodable,
795 )]
796 #[error("Unknown {} variant {variant}", stringify!($name))]
797 pub struct $error {
798 pub variant: u64,
799 }
800
801 impl std::fmt::Display for $name {
802 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
803 match self {
804 $name::V0(inner) => std::fmt::Display::fmt(inner, f),
805 $name::Default { variant, .. } => {
806 write!(f, "Unknown {} (variant={variant})", stringify!($name))
807 }
808 }
809 }
810 }
811 };
812}