use std::{
io::{Read, Write},
str::FromStr,
};
#[derive(Debug, thiserror::Error, miette::Diagnostic)]
#[error(transparent)]
pub(crate) enum Error {
Io(#[from] std::io::Error),
Json(#[from] serde_json::Error),
Yaml(#[from] serde_yml::Error),
}
#[derive(Debug, Clone, clap::Args)]
#[remain::sorted]
pub(crate) struct Source {
#[arg(long = "source-path")]
pub(crate) path: camino::Utf8PathBuf,
}
impl<T> From<T> for Source
where
T: Into<camino::Utf8PathBuf>,
{
fn from(value: T) -> Self {
Self { path: value.into() }
}
}
impl From<Source> for std::path::PathBuf {
fn from(source: Source) -> Self {
source.path.into()
}
}
impl AsRef<camino::Utf8Path> for Source {
fn as_ref(&self) -> &camino::Utf8Path {
&self.path
}
}
impl AsRef<std::path::Path> for Source {
fn as_ref(&self) -> &std::path::Path {
self.path.as_ref()
}
}
impl TryFrom<&Source> for fs_err::File {
type Error = Error;
fn try_from(source: &Source) -> Result<Self, Self::Error> {
Ok(Self::open(source.clone())?)
}
}
impl TryFrom<&Source> for serde_yml::Value {
type Error = Error;
fn try_from(source: &Source) -> Result<Self, Self::Error> {
let mut value: Self = serde_yml::from_reader(fs_err::File::try_from(source)?)?;
value.apply_merge()?;
Ok(value)
}
}
impl TryFrom<&Source> for serde_json::Value {
type Error = Error;
fn try_from(source: &Source) -> Result<Self, Self::Error> {
Ok(serde_yml::from_value(serde_yml::Value::try_from(source)?)?)
}
}
impl Source {
pub(crate) fn read<T: serde::de::DeserializeOwned>(&self) -> Result<T, Error> {
Ok(serde_json::from_value(serde_json::Value::try_from(self)?)?)
}
}