eternalfest_core 0.18.0

Core crate for Eternalfest
Documentation
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
  }
}

/// Simplified semver, with only major, minor and patch components.
#[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> {
  /// Creates a new `Mutable` for a fresh value (current == latest)
  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),
    }
  }
}

/// A value in a given period of time
#[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,
  /// Count with the current permissions
  pub count: u32,
  /// If `false`, `count` is a lower bound on the real number of entries in the DB (may or may not be exact).
  /// If `true`, the count is exactly what's in the DB (guaranteed exact).
  ///
  /// To get the exact count, you need the permission to view the full list.
  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),
}