gmt_dos_actors_clients_interface/
filing.rs1use std::{
6 env::{self, VarError},
7 fmt::Debug,
8 fs::File,
9 io::{Read, Write},
10 path::{Path, PathBuf},
11};
12
13use serde::{Deserialize, Serialize};
14
15#[derive(Debug, thiserror::Error)]
16pub enum FilingError {
17 #[error("filing error")]
18 IO(#[from] std::io::Error),
19 #[error("can't create file {0:?}")]
20 Create(#[source] std::io::Error, PathBuf),
21 #[error("can't open file {0:?}")]
22 Open(#[source] std::io::Error, PathBuf),
23 #[cfg(not(feature = "serde-pickle"))]
24 #[error("decoder error")]
25 Decoder(#[from] bincode::error::DecodeError),
26 #[cfg(feature = "serde-pickle")]
27 #[error("decoder error")]
28 PickleCodec(#[from] serde_pickle::error::Error),
29 #[cfg(not(feature = "serde-pickle"))]
30 #[error("encoder error")]
31 Encoder(#[from] bincode::error::EncodeError),
32 #[error("builder error: {0}")]
33 Builder(String),
34 #[error("DATA_REPO not set")]
35 DataRepo(#[from] VarError),
36}
37
38pub type Result<T> = std::result::Result<T, FilingError>;
39
40pub trait Codec
42where
43 Self: Sized + serde::ser::Serialize + for<'de> serde::de::Deserialize<'de>,
44{
45 #[inline]
47 #[cfg(not(feature = "serde-pickle"))]
48 fn decode<R>(reader: &mut R) -> Result<Self>
49 where
50 R: Read,
51 {
52 Ok(bincode::serde::decode_from_std_read(
53 reader,
54 bincode::config::standard(),
55 )?)
56 }
57 #[inline]
58 #[cfg(feature = "serde-pickle")]
59 fn decode<R>(reader: &mut R) -> Result<Self>
60 where
61 R: Read,
62 {
63 Ok(serde_pickle::from_reader(reader, Default::default())?)
64 }
65
66 #[inline]
68 #[cfg(not(feature = "serde-pickle"))]
69 fn encode<W>(&self, writer: &mut W) -> Result<()>
70 where
71 W: Write,
72 {
73 bincode::serde::encode_into_std_write(self, writer, bincode::config::standard())?;
74 Ok(())
75 }
76 #[inline]
77 #[cfg(feature = "serde-pickle")]
78 fn encode<W>(&self, writer: &mut W) -> Result<()>
79 where
80 W: Write,
81 {
82 serde_pickle::to_writer(writer, self, Default::default())?;
83 Ok(())
84 }
85}
86
87impl<T> Filing for T where
88 T: Sized + Codec + serde::ser::Serialize + for<'de> serde::de::Deserialize<'de>
89{
90}
91
92pub trait Filing: Codec
94where
95 Self: Sized + serde::ser::Serialize + for<'de> serde::de::Deserialize<'de>,
96{
97 fn from_path<P>(path: P) -> Result<Self>
99 where
100 P: AsRef<Path> + Debug,
101 {
102 log::info!("decoding from {path:?}");
103 let file =
104 File::open(&path).map_err(|e| FilingError::Open(e, path.as_ref().to_path_buf()))?;
105 let mut buffer = std::io::BufReader::new(file);
106 Self::decode(&mut buffer)
107 }
108
109 fn from_data_repo(file_name: impl AsRef<Path>) -> Result<Self> {
112 let data_repo = env::var("DATA_REPO")?;
113 let path = Path::new(&data_repo).join(file_name);
114 Self::from_path(path)
115 }
116
117 fn to_path<P>(&self, path: P) -> Result<()>
119 where
120 P: AsRef<Path> + Debug,
121 {
122 log::info!("encoding to {path:?}");
123 let file =
124 File::create(&path).map_err(|e| FilingError::Create(e, path.as_ref().to_path_buf()))?;
125 let mut buffer = std::io::BufWriter::new(file);
126 self.encode(&mut buffer)?;
127 Ok(())
128 }
129
130 fn to_data_repo(&self, file_name: impl AsRef<Path>) -> Result<()> {
133 let data_repo = env::var("DATA_REPO")?;
134 let path = Path::new(&data_repo).join(file_name);
135 Self::to_path(self, path)
136 }
137
138 fn from_path_or_else<P, F, B>(path: P, builder: F) -> Result<Self>
140 where
141 P: AsRef<Path> + Debug,
142 F: FnOnce() -> B,
143 Self: TryFrom<B>,
144 <Self as TryFrom<B>>::Error: std::fmt::Debug,
145 {
146 Self::from_path(&path).or_else(|e| {
147 log::warn!("{e:?}");
148 let this =
149 Self::try_from(builder()).map_err(|e| FilingError::Builder(format!("{e:?}")))?;
150 this.to_path(path)?;
151 Ok(this)
152 })
153 }
154
155 fn from_data_repo_or_else<P, F, B>(file_name: P, builder: F) -> Result<Self>
158 where
159 P: AsRef<Path>,
160 F: FnOnce() -> B,
161 Self: TryFrom<B>,
162 <Self as TryFrom<B>>::Error: std::fmt::Debug,
163 {
164 let data_repo = env::var("DATA_REPO")?;
165 let path = Path::new(&data_repo).join(file_name);
166 Self::from_path_or_else(path, builder)
167 }
168
169 fn from_path_or_default<P, F, B>(path: P) -> Result<Self>
171 where
172 P: AsRef<Path> + Debug,
173 B: Default,
174 F: FnOnce() -> B,
175 Self: TryFrom<B>,
176 <Self as TryFrom<B>>::Error: std::fmt::Debug,
177 {
178 Self::from_path_or_else(path, Default::default)
179 }
180
181 fn from_data_repo_or_default<P, F, B>(file_name: P) -> Result<Self>
184 where
185 P: AsRef<Path>,
186 B: Default,
187 F: FnOnce() -> B,
188 Self: TryFrom<B>,
189 <Self as TryFrom<B>>::Error: std::fmt::Debug,
190 {
191 Self::from_data_repo_or_else(file_name, Default::default)
192 }
193 fn from_path_or<P, B>(path: P, current_builder: B) -> Result<Self>
198 where
199 P: AsRef<Path> + Debug,
200 Self: TryFrom<B> + serde::ser::Serialize + for<'de> serde::de::Deserialize<'de>,
201 B: Clone + PartialEq + serde::ser::Serialize + for<'de> serde::de::Deserialize<'de>,
202 <Self as TryFrom<B>>::Error: std::fmt::Debug,
203 {
204 match <ObjectAndBuilder<Self, B> as Filing>::from_path(&path) {
205 Ok(ObjectAndBuilder { object, builder }) if builder == current_builder => Ok(object),
206 _ => {
207 let object = Self::try_from(current_builder.clone())
208 .map_err(|e| FilingError::Builder(format!("{e:?}")))?;
209 let this = ObjectAndBuilder {
210 object,
211 builder: current_builder,
212 };
213 this.to_path(path)?;
214 let ObjectAndBuilder { object, .. } = this;
215 Ok(object)
216 }
217 }
218 }
219 fn from_data_repo_or<P, B>(file_name: P, current_builder: B) -> Result<Self>
225 where
226 P: AsRef<Path>,
227 Self: TryFrom<B> + serde::ser::Serialize + for<'de> serde::de::Deserialize<'de>,
228 B: Clone + PartialEq + serde::ser::Serialize + for<'de> serde::de::Deserialize<'de>,
229 <Self as TryFrom<B>>::Error: std::fmt::Debug,
230 {
231 let data_repo = env::var("DATA_REPO")?;
232 let path = Path::new(&data_repo).join(file_name);
233 Self::from_path_or(path, current_builder)
234 }
235}
236
237#[derive(Serialize, Deserialize)]
239struct ObjectAndBuilder<T, B>
240where
241 T: TryFrom<B>,
242{
243 object: T,
244 builder: B,
245}
246
247impl<T, B> Codec for ObjectAndBuilder<T, B>
248where
249 T: TryFrom<B> + serde::ser::Serialize + for<'de> serde::de::Deserialize<'de>,
250 B: serde::ser::Serialize + for<'de> serde::de::Deserialize<'de>,
251{
252}