msg_store_uuid 0.1.0

The UUID format and types used for the msg store
Documentation
use std::cmp::Ordering;
use std::fmt::Display;
use std::sync::Arc;
use std::time::{
    SystemTime,
    UNIX_EPOCH
};

#[derive(Debug)]
pub enum UuidErrorTy {
    InvalidPriority,
    InvalidTimestamp,
    InvalidSequence,
    InvalidNodeId,
    InvalidFormat
}
impl Display for UuidErrorTy {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::InvalidPriority |
            Self::InvalidTimestamp |
            Self::InvalidSequence |
            Self::InvalidNodeId |
            Self::InvalidFormat => write!(f, "{:#?}", self)
        }
    }
}

#[derive(Debug)]
pub struct UuidError {
    pub err_ty: UuidErrorTy,
    pub file: &'static str,
    pub line: u32,
    pub msg: Option<String>
}
impl Display for UuidError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
       if let Some(msg) = &self.msg {
            write!(f, "UUID_ERROR: {}. file: {}, line: {}, msg: {}", self.err_ty, self.file, self.line, msg)
        } else {
            write!(f, "UUID_ERROR: {}. file: {}, line: {}.", self.err_ty, self.file, self.line)
        }
    }   
}

macro_rules! uuid_error {
    ($err_ty:expr) => {
        UuidError {
            err_ty: $err_ty,
            file: file!(),
            line: line!(),
            msg: None
        }
    };
    ($err_ty:expr, $msg:expr) => {
        UuidError {
            err_ty: $err_ty,
            file: file!(),
            line: line!(),
            msg: Some($msg.to_string())
        }
    };
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Uuid {
    pub priority: u16,
    pub timestamp: u64,
    pub sequence: u32,
    pub node_id: u16
}
impl Uuid {
    pub fn to_string(&self) -> String {
        format!("{}-{}-{}-{}", self.priority, self.timestamp, self.sequence, self.node_id)
    }
    pub fn from_string(id: &str) -> Result<Arc<Uuid>, UuidError> {
        let split_str = id.split("-").collect::<Vec<&str>>();
        if split_str.len() != 4 {
            return Err(uuid_error!(UuidErrorTy::InvalidFormat));
        }
        let priority: u16 = match split_str[0].parse() {
            Ok(priority) => priority,
            Err(error) => {
                return Err(uuid_error!(UuidErrorTy::InvalidPriority, error))
            }
        };
        let timestamp: u64 = match split_str[1].parse() {
            Ok(timestamp) => timestamp,
            Err(error) => {
                return Err(uuid_error!(UuidErrorTy::InvalidTimestamp, error))
            }
        };
        let sequence: u32 = match split_str[2].parse() {
            Ok(sequence) => sequence,
            Err(error) => {
                return Err(uuid_error!(UuidErrorTy::InvalidSequence, error))
            }
        };
        let node_id: u16 = match split_str[3].parse() {
            Ok(sequence) => sequence,
            Err(error) => {
                return Err(uuid_error!(UuidErrorTy::InvalidNodeId, error))
            }
        };
        Ok(Arc::new(Uuid {
            priority,
            timestamp,
            sequence,
            node_id
        }))
    }
}

impl PartialOrd for Uuid {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.priority > other.priority {
            Some(Ordering::Greater)
        } else if self.priority < other.priority {
            Some(Ordering::Less)
        } else {
            if self.timestamp < other.timestamp {
                Some(Ordering::Greater)
            } else if self.timestamp > other.timestamp {
                Some(Ordering::Less)
            } else {
                if self.sequence < other.sequence {
                    Some(Ordering::Greater)
                } else if self.sequence > other.sequence {
                    Some(Ordering::Less)
                } else {
                    Some(Ordering::Equal)
                }
            }
        }
    }
}

impl Ord for Uuid {
    fn cmp(&self, other: &Self) -> Ordering {
        if self.priority > other.priority {
            Ordering::Greater
        } else if self.priority < other.priority {
            Ordering::Less
        } else {
            if self.timestamp < other.timestamp {
                Ordering::Greater
            } else if self.timestamp > other.timestamp {
                Ordering::Less
            } else {
                if self.sequence < other.sequence {
                    Ordering::Greater
                } else if self.sequence > other.sequence {
                    Ordering::Less
                } else {
                    Ordering::Equal
                }
            }
        }
    }
}

#[derive(Debug)]
pub enum UuidManagerErrorTy {
    SystemTimeError
}
impl Display for UuidManagerErrorTy {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::SystemTimeError => write!(f, "{:#?}", self)
        }
    }
}

#[derive(Debug)]
pub struct UuidManagerError {
    pub err_ty: UuidManagerErrorTy,
    pub file: &'static str,
    pub line: u32,
    pub msg: Option<String>
}
impl Display for UuidManagerError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if let Some(msg) = &self.msg {
            write!(f, "UUID_MANAGER_ERROR: {}. file: {}, line: {}, msg: {}", self.err_ty, self.file, self.line, msg)
        } else {
            write!(f, "UUID_MANAGER_ERROR: {}. file: {}, line: {}.", self.err_ty, self.file, self.line)
        }
    }   
}

macro_rules! uuid_manager_error {
    ($err_ty:expr) => {
        UuidManagerError {
            err_ty: $err_ty,
            file: file!(),
            line: line!(),
            msg: None
        }
    };
    ($err_ty:expr, $msg:expr) => {
        UuidManagerError {
            err_ty: $err_ty,
            file: file!(),
            line: line!(),
            msg: Some($msg.to_string())
        }
    };
}

#[derive(Debug)]
pub struct UuidManager {
    pub timestamp: u64,
    pub sequence: u32,
    pub node_id: u16
}
impl UuidManager {
    pub fn default() -> Result<UuidManager, UuidManagerError> {
        let timestamp = match SystemTime::now().duration_since(UNIX_EPOCH) {
            Ok(duration) => Ok(duration.as_secs()),
            Err(error) => Err(uuid_manager_error!(UuidManagerErrorTy::SystemTimeError, error))
        }?;
        Ok(UuidManager {
            timestamp,
            sequence: 1,
            node_id: 0
        })
    }
    pub fn new(node_id: Option<u16>) -> Result<UuidManager, UuidManagerError> {
        let node_id = match node_id {
            Some(node_id) => node_id,
            None => 0
        };
        let mut manager = UuidManager::default()?;
        manager.node_id = node_id;
        Ok(manager)
    }
    pub fn next(&mut self, priority: u16) -> Result<Arc<Uuid>, UuidManagerError> {
        let current_timestamp = match SystemTime::now().duration_since(UNIX_EPOCH) {
            Ok(duration) => Ok(duration.as_secs()),
            Err(error) => Err(uuid_manager_error!(UuidManagerErrorTy::SystemTimeError, error))
        }?;
        if current_timestamp != self.timestamp {
            self.timestamp = current_timestamp;
            self.sequence = 1;
        } else {
            self.sequence += 1;
        }
        Ok(Arc::new(Uuid {
            priority,
            timestamp: self.timestamp,
            sequence: self.sequence,
            node_id: self.node_id           
        }))
    }
}