skytool 0.1.0-pre.2

an experimental API client for BlueSky / ATProto
Documentation
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)?)?)
  }
}