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