use serde::de::{DeserializeOwned, Visitor};
use serde::{self, Deserialize, Deserializer, Serialize};
use std::fmt::{self, Display};
use std::fs;
use std::io;
use std::marker::PhantomData;
use std::path::Path;
use std::str::FromStr;
use crate::errors::{self, ErrorKind, ResultExt};
use crate::util::ConductorPathExt;
pub fn load_yaml<T>(path: &Path) -> Result<T, errors::Error>
where
T: DeserializeOwned,
{
let mkerr = || ErrorKind::CouldNotReadFile(path.to_owned());
let f = fs::File::open(&path).chain_err(&mkerr)?;
serde_yaml::from_reader(io::BufReader::new(f)).chain_err(&mkerr)
}
pub fn dump_yaml<T>(path: &Path, data: &T) -> Result<(), errors::Error>
where
T: Serialize,
{
let mkerr = || ErrorKind::CouldNotWriteFile(path.to_owned());
path.with_guaranteed_parent().chain_err(&mkerr)?;
let f = fs::File::create(&path).chain_err(&mkerr)?;
serde_yaml::to_writer(&mut io::BufWriter::new(f), data).chain_err(&mkerr)
}
pub fn deserialize_parsable<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: FromStr,
<T as FromStr>::Err: Display,
{
String::deserialize(deserializer)?
.parse()
.map_err(|e| serde::de::Error::custom(format!("{}", e)))
}
pub fn deserialize_parsable_opt<'de, D, T>(
deserializer: D,
) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
T: FromStr,
<T as FromStr>::Err: Display,
{
struct Wrap<T>(Option<T>);
#[allow(unused_qualifications)]
impl<'de, T> Deserialize<'de> for Wrap<T>
where
T: FromStr,
<T as FromStr>::Err: Display,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct OptVisitor<T>(PhantomData<T>);
impl<'de, T> Visitor<'de> for OptVisitor<T>
where
T: FromStr,
<T as FromStr>::Err: Display,
{
type Value = Wrap<T>;
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Wrap(None))
}
fn visit_some<D>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserialize_parsable(deserializer).map(|v| Wrap(Some(v)))
}
fn expecting(
&self,
formatter: &mut fmt::Formatter<'_>,
) -> fmt::Result {
formatter.write_str("a string or null")
}
}
deserializer.deserialize_option(OptVisitor(PhantomData))
}
}
Wrap::deserialize(deserializer).map(|wrap| wrap.0)
}
pub(crate) mod seconds_since_epoch {
use serde::{self, ser, Deserialize, Deserializer, Serialize, Serializer};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<SystemTime, D::Error>
where
D: Deserializer<'de>,
{
let secs = u64::deserialize(deserializer)?;
Ok(UNIX_EPOCH + Duration::from_secs(secs))
}
pub(crate) fn serialize<S>(
time: &SystemTime,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let secs = time
.duration_since(UNIX_EPOCH)
.map_err(<S::Error as ser::Error>::custom)?
.as_secs();
secs.serialize(serializer)
}
}