fedimint_client/module/
recovery.rs1use std::any::Any;
2use std::fmt::{self, Debug};
3
4use fedimint_core::core::{IntoDynInstance, ModuleInstanceId, ModuleKind};
5use fedimint_core::encoding::{Decodable, DynEncodable, Encodable};
6use fedimint_core::task::{MaybeSend, MaybeSync};
7use fedimint_core::{
8 maybe_add_send_sync, module_plugin_dyn_newtype_clone_passthrough,
9 module_plugin_dyn_newtype_define, module_plugin_dyn_newtype_encode_decode,
10 module_plugin_dyn_newtype_eq_passthrough,
11};
12use serde::{Deserialize, Serialize};
13
14pub trait IModuleBackup: Debug + DynEncodable {
15 fn as_any(&self) -> &(maybe_add_send_sync!(dyn Any));
16 fn module_kind(&self) -> Option<ModuleKind>;
17 fn clone(&self, instance_id: ModuleInstanceId) -> DynModuleBackup;
18 fn erased_eq_no_instance_id(&self, other: &DynModuleBackup) -> bool;
19}
20
21pub trait ModuleBackup:
22 std::fmt::Debug
23 + IntoDynInstance<DynType = DynModuleBackup>
24 + std::cmp::PartialEq
25 + DynEncodable
26 + Decodable
27 + Clone
28 + MaybeSend
29 + MaybeSync
30 + 'static
31{
32 const KIND: Option<ModuleKind>;
33}
34
35impl IModuleBackup for ::fedimint_core::core::DynUnknown {
36 fn as_any(&self) -> &(maybe_add_send_sync!(dyn Any)) {
37 self
38 }
39
40 fn module_kind(&self) -> Option<ModuleKind> {
41 None
42 }
43
44 fn clone(&self, instance_id: ::fedimint_core::core::ModuleInstanceId) -> DynModuleBackup {
45 DynModuleBackup::from_typed(instance_id, <Self as Clone>::clone(self))
46 }
47
48 fn erased_eq_no_instance_id(&self, other: &DynModuleBackup) -> bool {
49 let other: &Self = other
50 .as_any()
51 .downcast_ref()
52 .expect("Type is ensured in previous step");
53
54 self == other
55 }
56}
57
58impl<T> IModuleBackup for T
59where
60 T: ModuleBackup,
61{
62 fn as_any(&self) -> &(maybe_add_send_sync!(dyn Any)) {
63 self
64 }
65
66 fn module_kind(&self) -> Option<ModuleKind> {
67 T::KIND
68 }
69
70 fn clone(&self, instance_id: ::fedimint_core::core::ModuleInstanceId) -> DynModuleBackup {
71 DynModuleBackup::from_typed(instance_id, <Self as Clone>::clone(self))
72 }
73
74 fn erased_eq_no_instance_id(&self, other: &DynModuleBackup) -> bool {
75 let other: &Self = other
76 .as_any()
77 .downcast_ref()
78 .expect("Type is ensured in previous step");
79
80 self == other
81 }
82}
83
84module_plugin_dyn_newtype_define! {
85 pub DynModuleBackup(Box<IModuleBackup>)
86}
87
88module_plugin_dyn_newtype_encode_decode!(DynModuleBackup);
89
90module_plugin_dyn_newtype_clone_passthrough!(DynModuleBackup);
91
92module_plugin_dyn_newtype_eq_passthrough!(DynModuleBackup);
93
94#[derive(Clone, PartialEq, Eq, Debug, Encodable, Decodable)]
98pub enum NoModuleBackup {
99 NoModuleBackup,
100 #[encodable_default]
101 Default {
102 variant: u64,
103 bytes: Vec<u8>,
104 },
105}
106
107impl ModuleBackup for NoModuleBackup {
108 const KIND: Option<ModuleKind> = None;
109}
110
111impl IntoDynInstance for NoModuleBackup {
112 type DynType = DynModuleBackup;
113
114 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType {
115 DynModuleBackup::from_typed(instance_id, self)
116 }
117}
118
119#[derive(Debug, Copy, Clone, Encodable, Decodable, Serialize, Deserialize)]
124pub struct RecoveryProgress {
125 pub complete: u32,
126 pub total: u32,
127}
128
129impl RecoveryProgress {
130 pub fn is_done(self) -> bool {
131 !self.is_none() && self.total <= self.complete
132 }
133
134 pub fn none() -> RecoveryProgress {
135 Self {
136 complete: 0,
137 total: 0,
138 }
139 }
140
141 pub fn is_none(self) -> bool {
142 self.total == 0
143 }
144
145 pub fn to_complete(self) -> RecoveryProgress {
146 if self.is_none() {
147 Self {
149 complete: 1,
150 total: 1,
151 }
152 } else {
153 Self {
154 complete: self.total,
155 total: self.total,
156 }
157 }
158 }
159}
160
161impl fmt::Display for RecoveryProgress {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163 f.write_fmt(format_args!("{}/{}", self.complete, self.total))
164 }
165}