octane 0.1.2

A web server built from the ground up.
Documentation
use crate::constants::{
    DAYS_IN_MONTH, DAYS_PER_100Y, DAYS_PER_400Y, DAYS_PER_4Y, LEAPOCH, MONTHS, SP, WEEKS,
};
use std::convert::TryInto;
use std::time::{SystemTime, UNIX_EPOCH};

pub struct Time {
    min: i64,
    sec: i64,
    hour: i64,
    week: i64,
    year: i64,
    month: i64,
    day: i64,
}

trait Padding {
    fn pad_zero(self) -> String;
}

impl Padding for i64 {
    fn pad_zero(self) -> String {
        let day_string = format!("{}{}", 0, self);
        (&day_string[day_string.len() - 2..]).to_owned()
    }
}

impl Time {
    pub fn now() -> Option<Self> {
        let stamp = match SystemTime::now().duration_since(UNIX_EPOCH) {
            Ok(n) => {
                if let Ok(x) = n.as_secs().try_into() {
                    x
                } else {
                    return None;
                }
            }
            Err(m) => panic!("Got time error: {}", m),
        };
        Self::time(stamp)
    }
    pub fn format(&self) -> String {
        if let Some(month_day) = self.month_day() {
            if let Some(week_day) = self.week_day() {
                let date = format!(
                    "{}{}{}{}{}",
                    self.day.pad_zero(),
                    SP,
                    month_day,
                    SP,
                    self.year
                );
                let time = format!(
                    "{}:{}:{}",
                    self.hour.pad_zero(),
                    self.min.pad_zero(),
                    self.sec.pad_zero()
                );
                format!("{},{}{}{}{}{}GMT", week_day, SP, date, SP, time, SP)
            } else {
                String::new()
            }
        } else {
            String::new()
        }
    }
    pub fn with_stamp(self, stamp: i64) -> Option<Self> {
        Self::time(stamp)
    }
    fn week_day(&self) -> Option<String> {
        if let Some(week) = WEEKS.iter().enumerate().find(|(i, _)| {
            if let Ok(week_day) = self.week.try_into() {
                *i == week_day
            } else {
                false
            }
        }) {
            Some(week.1.to_string())
        } else {
            None
        }
    }
    fn month_day(&self) -> Option<String> {
        if let Some(month) = MONTHS.iter().enumerate().find(|(i, _)| {
            if let Ok(month_day) = self.month.try_into() {
                *i == month_day
            } else {
                false
            }
        }) {
            Some(month.1.to_string())
        } else {
            None
        }
    }

    fn time(stamp: i64) -> Option<Self> {
        let secs = (stamp) - LEAPOCH;
        let mut days = secs / 86400;
        let mut remsecs = secs % 86400;
        if remsecs < 0 {
            remsecs += 86400;
            days -= 1;
        }
        let mut wday = (days + 3) % 7;
        if wday < 0 {
            wday += 7;
        }
        let mut qc_cycles = days / (DAYS_PER_400Y);
        let mut remdays = days % (DAYS_PER_400Y);
        if remdays < 0 {
            remdays += DAYS_PER_400Y;
            qc_cycles -= 1;
        }
        let mut c_cycles = remdays / DAYS_PER_100Y;
        if c_cycles == 4 {
            c_cycles -= 1;
        }
        remdays -= c_cycles * DAYS_PER_100Y;
        let mut q_cycles = remdays / DAYS_PER_4Y;
        if q_cycles == 25 {
            q_cycles -= 1;
        }
        remdays -= q_cycles * DAYS_PER_4Y;
        let mut remyears = remdays / 365;
        if remyears == 4 {
            remyears -= 1;
        }
        remdays -= remyears * 365;
        let years = remyears + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
        let mut month: usize = 0;
        while DAYS_IN_MONTH[month] <= remdays {
            remdays -= DAYS_IN_MONTH[month];
            month += 1;
        }
        let mut final_year = years + 100;
        let mut final_mon = (month as i64) + 2;
        if final_mon >= 12 {
            final_mon -= 12;
            final_year += 1;
        }
        Some(Time {
            min: (remsecs / 60) % 60,
            sec: remsecs % 60,
            hour: remsecs / 3600,
            week: wday,
            day: remdays + 1,
            year: 1900 + final_year,
            month: final_mon,
        })
    }
}