icechip 0.1.1

A mostly true to spec Twitter Snowflake implementation, with multiple modes.
Documentation
use tinyrand::{Rand, StdRand};

use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Clone, Debug)]
pub enum Version {
    ENHANCED,
    EXTENDED,
}

#[derive(Clone, Debug)]
pub struct Icechip<T> {
    version: Version,
    timestamp: T,
    machine_id: T,
    sequence: T,
    epoch: Option<u128>,
}

impl Into<u64> for Icechip<u64> {
    fn into(self) -> u64 {
        let mut ret: u64 = self.timestamp.wrapping_shl(23);
        ret = ret + self.machine_id.wrapping_shl(12);
        ret = ret + self.sequence;
        return ret;
    }
}

impl From<u64> for Icechip<u64> {
    fn from(value: u64) -> Icechip<u64> {
        return Icechip {
            version: Version::ENHANCED,
            timestamp: value.wrapping_shr(23),
            machine_id: value.wrapping_shl(41).wrapping_shr(53),
            sequence: value.wrapping_shl(52).wrapping_shr(52),
            epoch: None,
        };
    }
}

impl Into<u128> for Icechip<u128> {
    fn into(self) -> u128 {
        let mut ret: u128 = self.timestamp.wrapping_shl(64);
        ret = ret + self.machine_id.wrapping_shl(32);
        ret = ret + self.sequence;
        return ret;
    }
}

impl From<u128> for Icechip<u128> {
    fn from(value: u128) -> Icechip<u128> {
        return Icechip {
            version: Version::EXTENDED,
            timestamp: value.wrapping_shr(64),
            machine_id: value.wrapping_shr(32).wrapping_shl(64).wrapping_shr(64),
            sequence: value.wrapping_shl(96).wrapping_shr(96),
            epoch: None,
        };
    }
}

impl<T: Clone> Icechip<T> {
    pub fn set_epoch(mut self, epoch: u128) {
        self.epoch = Some(epoch);
    }

    pub fn timestamp(&self) -> T {
        return self.timestamp.clone();
    }

    pub fn machine_id(&self) -> T {
        return self.machine_id.clone();
    }

    pub fn sequence(&self) -> T {
        return self.sequence.clone();
    }

    pub fn version(&self) -> Version {
        return self.version.clone();
    }
}

impl Icechip<u64> {
    pub fn new(epoch: Option<u128>) -> Icechip<u64> {
        let mut rand = StdRand::default();
        return Icechip {
            version: Version::ENHANCED,
            timestamp: 0,
            machine_id: rand.next_u64().wrapping_shl(41).wrapping_shr(53),
            sequence: 0,
            epoch,
        }
        .tick();
    }

    pub fn tick(&self) -> Icechip<u64> {
        match SystemTime::now().duration_since(UNIX_EPOCH) {
            Ok(o) => {
                let o = o.as_millis();
                let curr_ts = match self.epoch {
                    Some(s) => (o - s).wrapping_shl(23).wrapping_shr(23) as u64,
                    None => o.wrapping_shl(23).wrapping_shr(23) as u64,
                };
                if self.timestamp == curr_ts {
                    if (self.sequence + 1) > 1023 {
                        std::thread::sleep(std::time::Duration::from_millis(1));
                        return self.tick();
                    } else {
                        return Icechip {
                            version: self.version.clone(),
                            timestamp: self.timestamp.clone(),
                            machine_id: self.machine_id.clone(),
                            sequence: self.sequence.clone() + 1,
                            epoch: self.epoch.clone(),
                        };
                    }
                } else {
                    return Icechip {
                        version: self.version.clone(),
                        timestamp: curr_ts.clone(),
                        machine_id: self.machine_id.clone(),
                        sequence: 0,
                        epoch: self.epoch.clone(),
                    };
                }
            }
            Err(_) => {
                std::thread::sleep(std::time::Duration::from_millis(1));
                return self.tick();
            }
        }
    }

    pub fn with_id(machine_id: u64, epoch: Option<u128>) -> Icechip<u64> {
        return Icechip {
            version: Version::ENHANCED,
            timestamp: 0,
            machine_id,
            sequence: 0,
            epoch,
        }
        .tick();
    }

    pub fn to_u64(self) -> u64 {
        return Into::<u64>::into(self);
    }
}

impl Icechip<u128> {
    pub fn new(epoch: Option<u128>) -> Icechip<u128> {
        let mut rand = StdRand::default();
        return Icechip {
            version: Version::EXTENDED,
            timestamp: 0,
            machine_id: rand.next_u128(),
            sequence: 0,
            epoch,
        }
        .tick();
    }

    pub fn tick(&self) -> Icechip<u128> {
        match SystemTime::now().duration_since(UNIX_EPOCH) {
            Ok(o) => {
                let o = o.as_millis();
                let curr_ts = match self.epoch {
                    Some(s) => o - s as u128,
                    None => o,
                };
                if self.timestamp == curr_ts {
                    if (self.sequence + 1) > u32::MAX as u128 {
                        std::thread::sleep(std::time::Duration::from_millis(1));
                        return self.tick();
                    } else {
                        return Icechip {
                            version: self.version.clone(),
                            timestamp: self.timestamp.clone(),
                            machine_id: self.machine_id.clone(),
                            sequence: self.sequence.clone() + 1,
                            epoch: self.epoch.clone(),
                        };
                    }
                } else {
                    return Icechip {
                        version: self.version.clone(),
                        timestamp: o.clone(),
                        machine_id: self.machine_id.clone(),
                        sequence: 0,
                        epoch: self.epoch.clone(),
                    };
                }
            }
            Err(_) => {
                std::thread::sleep(std::time::Duration::from_millis(1));
                return self.tick();
            }
        }
    }

    pub fn with_id(machine_id: u128, epoch: Option<u128>) -> Icechip<u128> {
        return Icechip {
            version: Version::EXTENDED,
            timestamp: 0,
            machine_id,
            sequence: 0,
            epoch,
        }
        .tick();
    }

    pub fn to_u128(self) -> u128 {
        return Into::<u128>::into(self);
    }
}

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

    #[test]
    fn from_into_u128() {
        let test_chip = Icechip::from(1234567890u128);
        assert_eq!(1234567890u128, test_chip.into());
    }

    #[test]
    fn from_into_u64() {
        let test_chip = Icechip::from(1234567890u64);
        assert_eq!(1234567890u64, test_chip.into());
    }

    #[test]
    fn custom_machine_id_u128() {
        let test_chip = Icechip::<u128>::with_id(1u128, None);
        test_chip.tick();
        assert_eq!(test_chip.machine_id(), 1u128);
    }

    #[test]
    fn custom_machine_id_u64() {
        let test_chip = Icechip::<u64>::with_id(1u64, None);
        test_chip.tick();
        assert_eq!(test_chip.machine_id(), 1u64);
    }

    #[test]
    fn tick_u128() {
        let test_chip = Icechip::<u128>::new(None);
        println!("test: {:#b}", test_chip.clone().to_u128());
        let ticked_chip = test_chip.tick();
        println!("tick: {:#b}", ticked_chip.clone().to_u128());
        assert!(test_chip.clone().to_u128() < ticked_chip.to_u128());
    }

    #[test]
    fn tick_u64() {
        let test_chip = Icechip::<u64>::new(None);
        println!("test: {:#b}", test_chip.clone().to_u64());
        let ticked_chip = test_chip.tick();
        println!("tick: {:#b}", ticked_chip.clone().to_u64());
        assert!(test_chip.clone().to_u64() < ticked_chip.to_u64());
    }
}