gitscope
← rgit / 0.1.5 / src/methods/filters.rs
https://dev.kronoz.win/r/rgit.git
src/methods/filters.rs · Rust
Blame Raw
  1// sorry clippy, we don't have a choice. askama forces this on us
  2#![allow(clippy::unnecessary_wraps, clippy::trivially_copy_pass_by_ref)]
  3
  4use std::{
  5    borrow::Borrow,
  6    fmt::Display,
  7    sync::{Arc, LazyLock},
  8};
  9
 10use arc_swap::ArcSwap;
 11use rkyv::{
 12    rend::{i32_le, i64_le},
 13    tuple::ArchivedTuple2,
 14};
 15use time::{format_description::well_known::Rfc3339, OffsetDateTime, UtcOffset};
 16
 17// pub fn format_time(s: impl Borrow<time::OffsetDateTime>) -> Result<String, askama::Error> {
 18pub fn format_time(s: impl Into<Timestamp>) -> Result<String, askama::Error> {
 19    let s = s.into().0;
 20
 21    (*s.borrow())
 22        .format(&Rfc3339)
 23        .map_err(Box::from)
 24        .map_err(askama::Error::Custom)
 25}
 26
 27pub fn branch_query(branch: Option<&str>) -> String {
 28    if let Some(b) = branch {
 29        format!("?h={b}")
 30    } else {
 31        String::new()
 32    }
 33}
 34
 35pub fn timeago(s: impl Into<Timestamp>) -> Result<String, askama::Error> {
 36    Ok(timeago::Formatter::new()
 37        .convert((OffsetDateTime::now_utc() - s.into().0).try_into().unwrap()))
 38}
 39
 40pub fn file_perms(s: &u16) -> Result<String, askama::Error> {
 41    Ok(unix_mode::to_string(u32::from(*s)))
 42}
 43
 44pub struct DisplayHexBuffer<const N: usize>(pub const_hex::Buffer<N>);
 45
 46impl<const N: usize> Display for DisplayHexBuffer<N> {
 47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 48        f.write_str(self.0.as_str())
 49    }
 50}
 51
 52pub fn hex(s: &[u8; 20]) -> Result<DisplayHexBuffer<20>, askama::Error> {
 53    let mut buf = const_hex::Buffer::new();
 54    buf.format(s);
 55    Ok(DisplayHexBuffer(buf))
 56}
 57
 58pub fn gravatar(email: &str) -> Result<&'static str, askama::Error> {
 59    static CACHE: LazyLock<ArcSwap<hashbrown::HashMap<&'static str, &'static str>>> =
 60        LazyLock::new(|| ArcSwap::new(Arc::new(hashbrown::HashMap::new())));
 61
 62    if let Some(res) = CACHE.load().get(email).copied() {
 63        return Ok(res);
 64    }
 65
 66    let url = format!(
 67        "https://www.gravatar.com/avatar/{}",
 68        const_hex::encode(md5::compute(email).0)
 69    );
 70    let key = Box::leak(Box::from(email));
 71    let url = url.leak();
 72
 73    CACHE.rcu(|curr| {
 74        let mut r = (**curr).clone();
 75        r.insert(key, url);
 76        r
 77    });
 78
 79    Ok(url)
 80}
 81
 82pub struct Timestamp(OffsetDateTime);
 83
 84impl From<&ArchivedTuple2<i64_le, i32_le>> for Timestamp {
 85    fn from(value: &ArchivedTuple2<i64_le, i32_le>) -> Self {
 86        Self(
 87            OffsetDateTime::from_unix_timestamp(value.0.to_native())
 88                .unwrap()
 89                .to_offset(UtcOffset::from_whole_seconds(value.1.to_native()).unwrap()),
 90        )
 91    }
 92}
 93
 94impl From<(i64, i32)> for Timestamp {
 95    fn from(value: (i64, i32)) -> Self {
 96        Self(
 97            OffsetDateTime::from_unix_timestamp(value.0)
 98                .unwrap()
 99                .to_offset(UtcOffset::from_whole_seconds(value.1).unwrap()),
100        )
101    }
102}
103
104impl From<&(i64, i32)> for Timestamp {
105    fn from(value: &(i64, i32)) -> Self {
106        Self(
107            OffsetDateTime::from_unix_timestamp(value.0)
108                .unwrap()
109                .to_offset(UtcOffset::from_whole_seconds(value.1).unwrap()),
110        )
111    }
112}
113
114impl From<OffsetDateTime> for Timestamp {
115    fn from(value: OffsetDateTime) -> Self {
116        Self(value)
117    }
118}