use std::{borrow::Cow, ops::Deref, str::FromStr};
use jiff::{
Timestamp, Zoned,
civil::Time,
fmt::temporal::{DateTimePrinter, Pieces},
tz::TimeZone,
};
use serde::{Deserialize, Deserializer, Serialize, de, de::DeserializeOwned};
use serde_with::{DeserializeAs, SerializeAs};
pub(crate) mod configfile;
pub(crate) mod indexfile;
pub(crate) mod keyfile;
pub(crate) mod packfile;
pub(crate) mod snapshotfile;
pub trait RepoFile: Serialize + DeserializeOwned + Sized + Send + Sync + 'static {
const TYPE: FileType;
const ENCRYPTED: bool = true;
type Id: RepoId;
}
pub trait RepoId: Deref<Target = Id> + From<Id> + Sized + Copy + Send + Sync + 'static {
const TYPE: FileType;
}
#[macro_export]
macro_rules! impl_repoid {
($a:ident, $b: expr) => {
$crate::define_new_id_struct!($a, concat!("repository file of type", stringify!($b)));
impl $crate::repofile::RepoId for $a {
const TYPE: FileType = $b;
}
};
}
#[macro_export]
macro_rules! impl_repofile {
($a:ident, $b: expr, $c: ty) => {
$crate::impl_repoid!($a, $b);
impl RepoFile for $c {
const TYPE: FileType = $b;
type Id = $a;
}
};
}
#[derive(Debug, Clone, Copy)]
pub struct RusticTime;
impl RusticTime {
pub fn parse(
s: &str,
default_time: Time,
default_zone: TimeZone,
) -> Result<Zoned, jiff::Error> {
if let Ok(zoned) = Zoned::from_str(s) {
return Ok(zoned);
}
let pieces = Pieces::parse(&s)?;
let time = pieces.time().unwrap_or(default_time);
let dt = pieces.date().to_datetime(time);
let zone = pieces.to_time_zone()?.unwrap_or_else(|| {
pieces
.to_numeric_offset()
.map_or_else(|| default_zone, TimeZone::fixed)
});
dt.to_zoned(zone)
}
pub fn parse_system(s: &str) -> Result<Zoned, jiff::Error> {
Self::parse(s, Time::MIN, TimeZone::system())
}
pub fn parse_utc(s: &str) -> Result<Zoned, jiff::Error> {
Self::parse(s, Time::MIN, TimeZone::UTC)
}
#[must_use]
pub fn to_string(source: &Zoned) -> String {
DateTimePrinter::new().timestamp_with_offset_to_string(&source.timestamp(), source.offset())
}
}
impl SerializeAs<Zoned> for RusticTime {
fn serialize_as<S>(source: &Zoned, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.collect_str(&Self::to_string(source))
}
}
impl<'de> DeserializeAs<'de, Zoned> for RusticTime {
fn deserialize_as<D>(deserializer: D) -> Result<Zoned, D::Error>
where
D: Deserializer<'de>,
{
let s = <Cow<'de, str>>::deserialize(deserializer)?;
Self::parse_utc(&s).map_err(de::Error::custom)
}
}
impl SerializeAs<Timestamp> for RusticTime {
fn serialize_as<S>(source: &Timestamp, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let offset = TimeZone::system().to_offset(*source);
serializer.collect_str(&source.display_with_offset(offset).to_string())
}
}
impl<'de> DeserializeAs<'de, Timestamp> for RusticTime {
fn deserialize_as<D>(deserializer: D) -> Result<Timestamp, D::Error>
where
D: Deserializer<'de>,
{
Timestamp::deserialize(deserializer)
}
}
use crate::Id;
pub use {
crate::{
backend::{
ALL_FILE_TYPES, FileType,
node::{Metadata, Node, NodeType},
},
blob::{ALL_BLOB_TYPES, BlobType, tree::Tree},
},
configfile::{Chunker, ConfigFile},
indexfile::{IndexBlob, IndexFile, IndexId, IndexPack},
keyfile::{KeyFile, KeyId, MasterKey},
packfile::{HeaderEntry, PackHeader, PackHeaderLength, PackHeaderRef, PackId},
snapshotfile::{
DeleteOption, PathList, SnapshotFile, SnapshotId, SnapshotModification, SnapshotSummary,
StringList,
},
};