1use crate::{AddressError, AddressErrorKind, Bincode, Csv, Io};
4use indicatif::{ProgressBar, ProgressStyle};
5use serde::de::{Deserialize, DeserializeOwned, Deserializer};
6use serde::Serialize;
7use std::fs;
8use std::path::{Path, PathBuf};
9use std::time::Duration;
10use tracing::info;
11use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
12
13pub fn deserialize_arcgis_data<'de, D: Deserializer<'de>>(
16 de: D,
17) -> Result<Option<String>, D::Error> {
18 let intermediate = Deserialize::deserialize(de)?;
19
20 match intermediate {
21 None => Ok(None),
22 Some("<Null>") => Ok(None),
23 Some(other_value) => Ok(Some(other_value.to_string())),
24 }
25}
26
27pub fn to_csv<T: Serialize + Clone>(item: &mut [T], path: PathBuf) -> Result<(), AddressErrorKind> {
30 match csv::Writer::from_path(&path) {
31 Ok(mut wtr) => {
32 for i in item {
33 wtr.serialize(i)
34 .map_err(|source| Csv::new(path.clone(), source, line!(), file!().into()))?;
35 }
36 wtr.flush()
37 .map_err(|source| Io::new(path.clone(), source, line!(), file!().into()))?;
38 Ok(())
39 }
40 Err(source) => Err(Csv::new(path, source, line!(), file!().to_string()).into()),
41 }
42}
43
44pub fn from_csv<T: DeserializeOwned + Clone, P: AsRef<std::path::Path>>(
47 path: P,
48) -> Result<Vec<T>, Io> {
49 let mut records = Vec::new();
50 match std::fs::File::open(&path) {
51 Ok(file) => {
52 let mut rdr = csv::Reader::from_reader(file);
53
54 let mut dropped = 0;
55 for result in rdr.deserialize() {
56 match result {
57 Ok(record) => records.push(record),
58 Err(e) => {
59 tracing::trace!("Dropping: {}", e.to_string());
60 dropped += 1;
61 }
62 }
63 }
64 tracing::info!("{} records dropped.", dropped);
65
66 Ok(records)
67 }
68 Err(source) => Err(Io::new(
69 path.as_ref().into(),
70 source,
71 line!(),
72 file!().into(),
73 )),
74 }
75}
76
77pub fn to_bin<T: Serialize, P: AsRef<Path>>(data: &T, path: P) -> Result<(), AddressError> {
80 info!("Serializing to binary.");
81 let encode =
82 bincode::serialize(data).map_err(|source| Bincode::new(source, line!(), file!().into()))?;
83 info!("Writing to file.");
84 std::fs::write(&path, encode)
85 .map_err(|source| Io::new(path.as_ref().into(), source, line!(), file!().into()))?;
86 Ok(())
87}
88
89pub fn from_bin<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, Io> {
93 info!("Loading from binary.");
94 let bar = ProgressBar::new_spinner();
95 bar.enable_steady_tick(Duration::from_millis(120));
96 bar.set_style(
97 ProgressStyle::with_template("{spinner:.blue} {msg}")
98 .unwrap()
99 .tick_strings(&[
100 "▹▹▹▹▹",
101 "▸▹▹▹▹",
102 "▹▸▹▹▹",
103 "▹▹▸▹▹",
104 "▹▹▹▸▹",
105 "▹▹▹▹▸",
106 "▪▪▪▪▪",
107 ]),
108 );
109 bar.set_message("Loading...");
110 match fs::read(path.as_ref()) {
111 Ok(vec) => {
112 bar.finish_with_message("Loaded!");
113 Ok(vec)
114 }
115 Err(source) => Err(Io::new(
116 path.as_ref().into(),
117 source,
118 line!(),
119 file!().into(),
120 )),
121 }
122}
123
124pub trait IntoCsv<T> {
126 fn from_csv<P: AsRef<Path>>(path: P) -> Result<T, Io>;
128 fn to_csv<P: AsRef<Path>>(&mut self, path: P) -> Result<(), AddressErrorKind>;
130}
131
132pub trait IntoBin<T> {
134 fn load<P: AsRef<Path>>(path: P) -> Result<T, AddressError>;
136 fn save<P: AsRef<Path>>(&self, path: P) -> Result<(), AddressError>;
138}
139
140pub fn trace_init() {
142 if tracing_subscriber::registry()
143 .with(
144 tracing_subscriber::EnvFilter::try_from_default_env()
145 .unwrap_or_else(|_| "address=info".into()),
146 )
147 .with(tracing_subscriber::fmt::layer())
148 .try_init()
149 .is_ok()
150 {};
151 info!("Subscriber initialized.");
152}