1use crate::filters::{FilterDefZoned, FilterDefinition};
10use crate::metadata::Checksum;
11use crate::txn_ts;
12use jiff::Zoned;
13use jiff::tz::TimeZone;
14use serde::Serialize;
15
16#[doc(hidden)]
17pub type MetadataItems = Vec<MetadataItem>;
18
19#[doc(hidden)]
20pub trait Text: std::fmt::Debug {
21 #[must_use]
23 fn text(&self, tz: TimeZone) -> Vec<String>;
24}
25
26#[doc(hidden)]
27#[derive(Serialize, Debug, Clone)]
28pub enum MetadataItem {
29 #[doc(hidden)]
30 TxnSetChecksum(TxnSetChecksum),
31 #[doc(hidden)]
32 TimeZoneInfo(TimeZoneInfo),
33 #[doc(hidden)]
34 AccountSelectorChecksum(AccountSelectorChecksum),
35 #[doc(hidden)]
36 GitInputReference(GitInputReference),
37 #[doc(hidden)]
38 TxnFilterDescription(TxnFilterDescription),
39 #[doc(hidden)]
40 PriceRecords(PriceRecords),
41}
42
43impl MetadataItem {
44 pub const ITEM_PAD: usize = 15;
45}
46
47impl Text for MetadataItem {
48 fn text(&self, tz: TimeZone) -> Vec<String> {
49 match self {
50 Self::GitInputReference(gif) => gif.text(tz),
51 Self::TxnSetChecksum(tscs) => tscs.text(tz),
52 Self::TimeZoneInfo(tzinfo) => tzinfo.text(tz),
53 Self::AccountSelectorChecksum(asc) => asc.text(tz),
54 Self::TxnFilterDescription(tfd) => tfd.text(tz),
55 Self::PriceRecords(pr) => pr.text(tz),
56 }
57 }
58}
59
60#[derive(Serialize, Debug, Clone)]
62pub struct TxnSetChecksum {
63 pub size: usize,
65 pub hash: Checksum,
67}
68impl Text for TxnSetChecksum {
69 fn text(&self, _tz: TimeZone) -> Vec<String> {
70 let pad = MetadataItem::ITEM_PAD;
72 vec![
73 format!("Txn Set Checksum"),
74 format!("{:>pad$} : {}", self.hash.algorithm, &self.hash.value),
75 format!("{:>pad$} : {}", "set size", self.size),
76 ]
77 }
78}
79
80#[derive(Serialize, Debug, Clone)]
93pub struct AccountSelectorChecksum {
94 pub hash: Checksum,
96 pub selectors: Vec<String>,
98}
99impl Text for AccountSelectorChecksum {
100 fn text(&self, _tz: TimeZone) -> Vec<String> {
101 let pad = MetadataItem::ITEM_PAD;
103 let mut t = vec![
104 format!("Account Selector Checksum"),
105 format!("{:>pad$} : {}", self.hash.algorithm, &self.hash.value),
106 ];
107 if !self.selectors.is_empty() {
108 let sel_txt = if self.selectors.len() > 1 {
109 "selectors"
110 } else {
111 "selector"
112 };
113 let l = format!(
114 "{:>pad$} : '{}'",
115 sel_txt,
116 &self.selectors.first().unwrap()
117 );
118 t.push(l);
119 for s in self.selectors.iter().skip(1) {
120 let l = format!("{:>pad$} | '{}'", "", s);
121 t.push(l);
122 }
123 }
124 t
125 }
126}
127
128#[derive(Serialize, Debug, Clone)]
130pub struct TimeZoneInfo {
131 #[serde(rename = "zoneId")]
133 pub zone_id: String,
134}
135impl Text for TimeZoneInfo {
136 fn text(&self, _tz: TimeZone) -> Vec<String> {
137 let pad = MetadataItem::ITEM_PAD;
138 vec![
139 "Report Time Zone".to_string(),
140 format!("{:>pad$} : {}", "TZ name", &self.zone_id),
141 ]
142 }
143}
144#[derive(Serialize, Debug, Clone)]
147pub struct TxnFilterDescription {
148 #[doc(hidden)]
149 #[serde(rename = "txnFilterDef")]
150 txn_filter_def: FilterDefinition,
151}
152
153impl TxnFilterDescription {
154 #[must_use]
157 pub fn from(tf: FilterDefinition) -> TxnFilterDescription {
158 TxnFilterDescription { txn_filter_def: tf }
159 }
160}
161impl Text for TxnFilterDescription {
162 fn text(&self, tz: TimeZone) -> Vec<String> {
163 format!(
166 "{}",
167 FilterDefZoned {
168 filt_def: &self.txn_filter_def,
169 tz
170 }
171 )
172 .trim_end()
173 .split("\n")
174 .map(String::from)
175 .collect::<Vec<String>>()
176 }
177}
178
179#[derive(Serialize, Debug, Clone)]
182pub struct GitInputReference {
183 pub commit: String,
185
186 #[serde(rename = "ref")]
188 #[serde(skip_serializing_if = "Option::is_none")]
189 pub reference: Option<String>,
190
191 pub dir: String,
193
194 pub extension: String,
196
197 pub author: String,
199
200 pub date: String,
202
203 pub subject: String,
205}
206
207impl Text for GitInputReference {
208 fn text(&self, _tz: TimeZone) -> Vec<String> {
209 let pad = MetadataItem::ITEM_PAD;
210 vec![
211 format!("Git Storage"),
212 format!(
213 "{:>pad$} : {}",
214 "reference",
215 self.reference
216 .as_ref()
217 .unwrap_or(&"FIXED by commit".to_string())
218 ),
219 format!("{:>pad$} : {}", "directory", self.dir),
220 format!("{:>pad$} : {}", "extension", self.extension),
221 format!("{:>pad$} : {}", "commit", self.commit),
222 format!("{:>pad$} : {}", "author", self.author),
223 format!("{:>pad$} : {}", "date", self.date),
224 format!("{:>pad$} : {}", "subject", self.subject),
225 ]
226 }
227}
228
229#[derive(Serialize, Debug, Clone)]
231pub struct PriceRecord {
232 #[serde(skip_serializing_if = "Option::is_none")]
234 pub ts: Option<Zoned>,
235 pub source: String,
237 #[serde(skip_serializing_if = "Option::is_none")]
239 pub rate: Option<String>,
240 pub target: String,
242}
243impl Text for PriceRecord {
244 fn text(&self, tz: TimeZone) -> Vec<String> {
245 let pad = MetadataItem::ITEM_PAD;
246 vec![
247 format!(
248 "{:>pad$} : {}",
249 "Time",
250 self.ts.as_ref().map_or("At txn time".to_string(), |ts| {
251 txn_ts::as_tz_full(ts, tz)
252 })
253 ),
254 format!("{:>pad$} : {}", "Commodity", self.source),
255 format!(
256 "{:>pad$} : {} {}",
257 "Value",
258 self.rate.clone().map_or("-".to_string(), |v| v),
259 self.target
260 ),
261 ]
262 }
263}
264#[derive(Serialize, Debug, Clone)]
266pub struct PriceRecords {
267 pub rates: Vec<PriceRecord>,
269}
270impl Text for PriceRecords {
271 fn text(&self, tz: TimeZone) -> Vec<String> {
272 let pad = MetadataItem::ITEM_PAD;
273
274 let mut txt = Vec::new();
275
276 if let Some(pr) = self.rates.first() {
277 txt.push("Commodity Prices".to_string());
278 txt.extend(pr.text(tz.clone()));
279
280 if self.rates.len() > 1 {
281 for pr in &self.rates[1..] {
282 txt.push(format!("{:>pad$} -", ""));
283 txt.extend(pr.text(tz.clone()));
284 }
285 }
286 }
287 txt
288 }
289}