use std::{
fs::OpenOptions,
io::{Read, Write},
};
use camino::Utf8Path;
use facet::Facet;
use facet_json::JsonSerializeError;
#[derive(thiserror::Error, Debug)]
pub enum Errors {
#[error(transparent)]
StdIo(#[from] std::io::Error),
#[error("{0}")]
Custom(String),
}
impl From<String> for Errors {
fn from(value: String) -> Self {
Self::Custom(value)
}
}
impl From<&str> for Errors {
fn from(value: &str) -> Self {
Self::from(value.to_string())
}
}
impl From<facet_json::DeserializeError> for Errors {
fn from(value: facet_json::DeserializeError) -> Self {
todo!()
}
}
impl From<facet_format::SerializeError<JsonSerializeError>> for Errors {
fn from(value: facet_format::SerializeError<JsonSerializeError>) -> Self {
todo!()
}
}
pub type Res<T> = Result<T, Errors>;
#[derive(Facet, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Annotation<T, A> {
inner: T,
key: &'static str,
value: A,
}
impl<T, A> Annotation<T, A> {
pub fn store_xattr(&self, path: &Utf8Path) -> Res<()> {
todo!()
}
pub fn load_xattr(path: &Utf8Path) -> Res<Self> {
todo!()
}
}
impl<T, A> Annotation<T, A> {
pub fn store_sidecar_file(&self, path: &Utf8Path, kind: SidecarKind) -> Res<()> {
todo!()
}
pub fn load_sidecar_file(path: &Utf8Path, kind: SidecarKind) -> Res<Self> {
todo!()
}
}
#[derive(facet::Facet, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
#[repr(C)]
pub enum SidecarKind {
#[default]
Json,
JsonLines,
}
impl SidecarKind {
pub fn guess_kind(path: &Utf8Path) -> Option<Self> {
if let Some(ext) = path.extension() {
match ext {
"json" => Some(Self::Json),
"ndjson" => Some(Self::JsonLines),
_ => None,
}
} else {
None
}
}
pub fn load<T, A>(&self, path: &Utf8Path) -> Res<Annotation<T, A>> {
let file = OpenOptions::new()
.create_new(true)
.create(true)
.truncate(false)
.read(true)
.open(path)?;
todo!()
}
pub fn store<T, A>(&self, annot: Annotation<T, A>, path: &Utf8Path) -> Res<()> {
let data: facet_value::Value = if path.canonicalize_utf8()?.exists() {
let mut f = OpenOptions::new().read(true).open(path)?;
let mut buf = vec![];
f.read_to_end(&mut buf)?;
facet_json::from_slice(&buf)?
} else {
facet_json::from_str(&format!("{{\"{}\": null}}", annot.key))?
};
let mut file = OpenOptions::new()
.create_new(true)
.create(true)
.truncate(true)
.write(true)
.open(path)?;
let s = facet_json::to_string_pretty(&data)?;
writeln!(&mut file, "{s}")?;
Ok(())
}
}