1use std::fmt::{self, Debug, Display};
2use std::ops::RangeBounds;
3
4use async_trait::async_trait;
5use celestia_types::ExtendedHeader;
6use celestia_types::hash::Hash;
7use cid::Cid;
8use libp2p::identity::Keypair;
9
10use crate::store::{BlockRanges, Result, SamplingMetadata, Store, VerifiedExtendedHeaders};
11
12pub enum EitherStore<L, R>
20where
21 L: Store,
22 R: Store,
23{
24 Left(L),
26 Right(R),
28}
29
30impl<L, R> EitherStore<L, R>
31where
32 L: Store,
33 R: Store,
34{
35 pub fn is_left(&self) -> bool {
37 match self {
38 EitherStore::Left(_) => true,
39 EitherStore::Right(_) => false,
40 }
41 }
42
43 pub fn is_right(&self) -> bool {
45 match self {
46 EitherStore::Left(_) => false,
47 EitherStore::Right(_) => true,
48 }
49 }
50
51 pub fn left(&self) -> Option<&L> {
53 match self {
54 EitherStore::Left(store) => Some(store),
55 EitherStore::Right(_) => None,
56 }
57 }
58
59 pub fn right(&self) -> Option<&R> {
61 match self {
62 EitherStore::Left(_) => None,
63 EitherStore::Right(store) => Some(store),
64 }
65 }
66
67 pub fn left_mut(&mut self) -> Option<&mut L> {
69 match self {
70 EitherStore::Left(store) => Some(store),
71 EitherStore::Right(_) => None,
72 }
73 }
74
75 pub fn right_mut(&mut self) -> Option<&mut R> {
77 match self {
78 EitherStore::Left(_) => None,
79 EitherStore::Right(store) => Some(store),
80 }
81 }
82
83 pub fn into_left(self) -> Option<L> {
85 match self {
86 EitherStore::Left(store) => Some(store),
87 EitherStore::Right(_) => None,
88 }
89 }
90
91 pub fn into_right(self) -> Option<R> {
93 match self {
94 EitherStore::Left(_) => None,
95 EitherStore::Right(store) => Some(store),
96 }
97 }
98}
99
100impl<L, R> Clone for EitherStore<L, R>
101where
102 L: Store + Clone,
103 R: Store + Clone,
104{
105 fn clone(&self) -> Self {
106 match self {
107 EitherStore::Left(store) => EitherStore::Left(store.clone()),
108 EitherStore::Right(store) => EitherStore::Right(store.clone()),
109 }
110 }
111
112 fn clone_from(&mut self, source: &Self) {
113 match source {
114 EitherStore::Left(source_store) => match self {
115 EitherStore::Left(self_store) => self_store.clone_from(source_store),
116 EitherStore::Right(_) => *self = EitherStore::Left(source_store.clone()),
117 },
118 EitherStore::Right(source_store) => match self {
119 EitherStore::Left(_) => *self = EitherStore::Right(source_store.clone()),
120 EitherStore::Right(self_store) => self_store.clone_from(source_store),
121 },
122 };
123 }
124}
125
126impl<L, R> Debug for EitherStore<L, R>
127where
128 L: Store + Debug,
129 R: Store + Debug,
130{
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 match self {
133 EitherStore::Left(store) => Debug::fmt(store, f),
134 EitherStore::Right(store) => Debug::fmt(store, f),
135 }
136 }
137}
138
139impl<L, R> Display for EitherStore<L, R>
140where
141 L: Store + Display,
142 R: Store + Display,
143{
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 match self {
146 EitherStore::Left(store) => Display::fmt(store, f),
147 EitherStore::Right(store) => Display::fmt(store, f),
148 }
149 }
150}
151
152macro_rules! call {
153 ($self:ident, $method:ident($($param:expr),*)) => {
154 match $self {
155 EitherStore::Left(store) => store.$method($($param),*).await,
156 EitherStore::Right(store) => store.$method($($param),*).await,
157 }
158 };
159}
160
161#[async_trait]
162impl<L, R> Store for EitherStore<L, R>
163where
164 L: Store,
165 R: Store,
166{
167 async fn get_head(&self) -> Result<ExtendedHeader> {
168 call!(self, get_head())
169 }
170
171 async fn get_by_hash(&self, hash: &Hash) -> Result<ExtendedHeader> {
172 call!(self, get_by_hash(hash))
173 }
174
175 async fn get_by_height(&self, height: u64) -> Result<ExtendedHeader> {
176 call!(self, get_by_height(height))
177 }
178
179 async fn wait_new_head(&self) -> u64 {
180 call!(self, wait_new_head())
181 }
182
183 async fn wait_height(&self, height: u64) -> Result<()> {
184 call!(self, wait_height(height))
185 }
186
187 async fn get_range<RB>(&self, range: RB) -> Result<Vec<ExtendedHeader>>
188 where
189 RB: RangeBounds<u64> + Send,
190 {
191 call!(self, get_range(range))
192 }
193
194 async fn head_height(&self) -> Result<u64> {
195 call!(self, head_height())
196 }
197
198 async fn has(&self, hash: &Hash) -> bool {
199 call!(self, has(hash))
200 }
201
202 async fn has_at(&self, height: u64) -> bool {
203 call!(self, has_at(height))
204 }
205
206 async fn update_sampling_metadata(&self, height: u64, cids: Vec<Cid>) -> Result<()> {
207 call!(self, update_sampling_metadata(height, cids))
208 }
209
210 async fn get_sampling_metadata(&self, height: u64) -> Result<Option<SamplingMetadata>> {
211 call!(self, get_sampling_metadata(height))
212 }
213
214 async fn mark_as_sampled(&self, height: u64) -> Result<()> {
215 call!(self, mark_as_sampled(height))
216 }
217
218 async fn insert<H>(&self, headers: H) -> Result<()>
219 where
220 H: TryInto<VerifiedExtendedHeaders> + Send,
221 <H as TryInto<VerifiedExtendedHeaders>>::Error: Display,
222 {
223 call!(self, insert(headers))
224 }
225
226 async fn get_stored_header_ranges(&self) -> Result<BlockRanges> {
227 call!(self, get_stored_header_ranges())
228 }
229
230 async fn get_sampled_ranges(&self) -> Result<BlockRanges> {
231 call!(self, get_sampled_ranges())
232 }
233
234 async fn get_pruned_ranges(&self) -> Result<BlockRanges> {
235 call!(self, get_pruned_ranges())
236 }
237
238 async fn remove_height(&self, height: u64) -> Result<()> {
239 call!(self, remove_height(height))
240 }
241
242 async fn get_identity(&self) -> Result<Keypair> {
243 call!(self, get_identity())
244 }
245
246 async fn close(self) -> Result<()> {
247 call!(self, close())
248 }
249}