squint 0.1.4

Encode sequential integer ids as random looking strings
Documentation
use core::{
    fmt::{self, Write},
    str::FromStr,
};

use aes::Aes128;

use crate::{
    encoding::{parse, stringify},
    encryption::{decrypt, encrypt},
    error::Error,
};

#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Id<const TAG: u64>(u128);

impl<const TAG: u64> Id<TAG> {
    pub fn new(id: i64, cipher: &Aes128) -> Self {
        Self(encrypt(TAG, id, cipher))
    }

    pub fn to_raw(self, cipher: &Aes128) -> crate::Result<i64> {
        match decrypt(self.0, cipher) {
            (tag, id) if tag == TAG => Ok(id),
            _ => Err(Error::TagMismatch),
        }
    }
}

impl<const TAG: u64> fmt::Display for Id<TAG> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        stringify(self.0).try_for_each(|c| f.write_char(c))
    }
}

impl<const TAG: u64> fmt::Debug for Id<TAG> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("Id").field(&format_args!("{self}")).finish()
    }
}

impl<const TAG: u64> FromStr for Id<TAG> {
    type Err = crate::Error;

    fn from_str(s: &str) -> crate::Result<Self> {
        parse(s).map(Self).ok_or(Error::InvalidFormat)
    }
}