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