use core::fmt;
#[cfg(feature = "serde")]
use etwin_serde_tools::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::str::FromStr;
pub use etwin_core::core::Instant;
pub use etwin_core::core::{LocaleId, PeriodLower};
use once_cell::sync::Lazy;
use regex::Regex;
#[cfg(feature = "serde")]
use serde::{Deserializer, Serializer};
use thiserror::Error;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct BoundedVec<T, const MIN: u32, const MAX: u32>(Vec<T>);
impl<T, const MIN: u32, const MAX: u32> BoundedVec<T, MIN, MAX> {
pub fn new(inner: Vec<T>) -> Option<Self> {
let len = u32::try_from(inner.len()).ok()?;
if MIN <= len && len <= MAX {
Some(Self(inner))
} else {
None
}
}
}
impl<T, const MIN: u32, const MAX: u32> AsRef<Vec<T>> for BoundedVec<T, MIN, MAX> {
fn as_ref(&self) -> &Vec<T> {
&self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SimpleSemVer {
pub major: u32,
pub minor: u32,
pub patch: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Error)]
#[error("invalid SimpleSemVerParseError format")]
pub struct SimpleSemVerParseError(());
impl FromStr for SimpleSemVer {
type Err = SimpleSemVerParseError;
fn from_str(input: &str) -> Result<Self, Self::Err> {
static PATTERN: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"^(0|[1-9]\d{0,10})\.(0|[1-9]\d{0,10})\.(0|[1-9]\d{0,10})$")
.expect("the SimpleSemVer pattern is well-formed")
});
let captures = PATTERN.captures(input).ok_or(SimpleSemVerParseError(()))?;
let major = captures.get(1).expect("capture group 1 exists").as_str();
let minor = captures.get(2).expect("capture group 2 exists").as_str();
let patch = captures.get(3).expect("capture group 3 exists").as_str();
Ok(Self {
major: major.parse().map_err(|_| SimpleSemVerParseError(()))?,
minor: minor.parse().map_err(|_| SimpleSemVerParseError(()))?,
patch: patch.parse().map_err(|_| SimpleSemVerParseError(()))?,
})
}
}
impl fmt::Display for SimpleSemVer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
#[cfg(feature = "serde")]
impl Serialize for SimpleSemVer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.to_string().as_str())
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for SimpleSemVer {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
let raw = std::borrow::Cow::<str>::deserialize(deserializer)?;
Self::from_str(raw.as_ref()).map_err(D::Error::custom)
}
}
pub trait Request {
type Response;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Mutable<T> {
pub current: Span<T>,
pub latest: Span<T>,
}
impl<T> Mutable<T> {
pub fn fresh(time: Instant, value: T) -> Self
where
T: Clone,
{
Self {
current: Span {
value: value.clone(),
period: PeriodLower::unbounded(time),
},
latest: Span {
value,
period: PeriodLower::unbounded(time),
},
}
}
pub fn map<F, R>(self, mut f: F) -> Mutable<R>
where
F: FnMut(T) -> R,
{
Mutable {
current: self.current.map(&mut f),
latest: self.latest.map(f),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Span<T> {
pub value: T,
#[cfg_attr(feature = "serde", serde(flatten))]
pub period: PeriodLower,
}
impl<T> Span<T> {
pub fn map<F, R>(self, mut f: F) -> Span<R>
where
F: FnMut(T) -> R,
{
Span {
value: f(self.value),
period: self.period,
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Listing<T> {
pub offset: u32,
pub limit: u32,
pub count: u32,
pub is_count_exact: bool,
pub items: Vec<T>,
}
impl<T> Listing<T> {
pub fn map<F, R>(self, f: F) -> Listing<R>
where
F: FnMut(T) -> R,
{
Listing {
offset: self.offset,
limit: self.limit,
count: self.count,
is_count_exact: self.is_count_exact,
items: self.items.into_iter().map(f).collect(),
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Localized<T> {
pub value: T,
pub main_locale: LocaleId,
pub i18n: BTreeMap<LocaleId, T>,
}
impl<T> Localized<T> {
pub fn one(main_locale: LocaleId, value: T) -> Self {
Self {
value,
main_locale,
i18n: BTreeMap::new(),
}
}
pub fn map<F, R>(self, mut f: F) -> Localized<R>
where
F: FnMut(T) -> R,
{
Localized {
value: f(self.value),
main_locale: self.main_locale,
i18n: self.i18n.into_iter().map(|(k, v)| (k, f(v))).collect(),
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Patch<T> {
Skip,
Set(T),
}