webtoon 0.9.0

Client for interacting with various webtoon websites.
Documentation
use serde_with::{DeserializeFromStr, SerializeDisplay};
use std::{fmt::Display, num::ParseIntError, ops::Add, str::FromStr};

#[derive(
    Debug, PartialEq, Eq, PartialOrd, Ord, DeserializeFromStr, SerializeDisplay, Clone, Copy, Hash,
)]
pub struct Base36(u32);

impl Base36 {
    #[cfg(test)]
    pub fn new(n: u32) -> Self {
        Self(n)
    }
}

impl Add for Base36 {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        let mut this = self;
        this.0 += rhs.0;
        this
    }
}

impl Add<u32> for Base36 {
    type Output = Self;
    fn add(self, rhs: u32) -> Self::Output {
        let mut this = self;
        this.0 += rhs;
        this
    }
}

impl FromStr for Base36 {
    type Err = ParseIntError;

    fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> {
        let num = u32::from_str_radix(s, 36)?;

        Ok(Self(num))
    }
}

impl Display for Base36 {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut x = self.0;
        let mut result = ['\0'; 128];

        let mut used = 0;

        loop {
            let m = x % 36;
            x /= 36;

            result[used] = std::char::from_digit(m, 36).unwrap();
            used += 1;

            if x == 0 {
                break;
            }
        }

        for c in result[..used].iter().rev() {
            write!(f, "{c}")?;
        }

        Ok(())
    }
}

impl PartialEq<u32> for Base36 {
    fn eq(&self, other: &u32) -> bool {
        self.0 == *other
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn should_format_u32_to_base_36() {
        {
            let num = Base36(0);
            pretty_assertions::assert_str_eq!("0", num.to_string());
        }
        {
            let num = Base36(9);
            pretty_assertions::assert_str_eq!("9", num.to_string());
        }
        {
            let num = Base36(10);
            pretty_assertions::assert_str_eq!("a", num.to_string());
        }
        {
            let num = Base36(35);
            pretty_assertions::assert_str_eq!("z", num.to_string());
        }
        {
            let num = Base36(23812);
            pretty_assertions::assert_str_eq!("idg", num.to_string());
        }
        {
            let num = Base36(u32::MAX);
            pretty_assertions::assert_str_eq!("1z141z3", num.to_string());
        }
    }

    #[test]
    fn should_parse_base_36_from_str() {
        {
            let num: Base36 = "0".parse().unwrap();

            pretty_assertions::assert_eq!(num, 0);
        }
        {
            let num: Base36 = "9".parse().unwrap();

            pretty_assertions::assert_eq!(num, 9);
        }
        {
            let num: Base36 = "a".parse().unwrap();

            pretty_assertions::assert_eq!(num, 10);
        }
        {
            let num: Base36 = "z".parse().unwrap();

            pretty_assertions::assert_eq!(num, 35);
        }
        {
            let num: Base36 = "idg".parse().unwrap();

            pretty_assertions::assert_eq!(num, 23812);
        }
        {
            let num: Base36 = "1d".parse().unwrap();

            pretty_assertions::assert_eq!(num, 49);
        }
    }
}