datom 0.1.1-pre4

datom-rs: an open-source database inspired by Datomic
Documentation
// SPDX-FileCopyrightText: 2021 Lutris Engineering, Inc
// SPDX-License-Identifier: BlueOak-1.0.0 OR BSD-2-Clause-Patent
// SPDX-FileContributor: Piper McCorkle <piper@lutris.engineering>

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

use uuid::Uuid;

/**

An entity ID

These IDs are better known as Squuids - a [UUID](Uuid) v4 with the most
significant 32 bits overwritten with seconds since epoch. Squuids
allow for more efficient indexing of the IDs, since they will end up
approximately monotonically increasing on a large scale.

Since attributes are entities themselves, these are also attribute
IDs.
*/
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ID(Uuid);

impl ID {
    /// Generate a new [ID] from the current time.
    pub fn new() -> Self {
        let now = SystemTime::now();
        let since_epoch = now
            .duration_since(UNIX_EPOCH)
            .expect("Must be run after 1970 (large ask, I know)")
            .as_secs() as u32;
        let since_epoch_be = since_epoch.to_be_bytes();
        let mut uuid_bytes = Uuid::new_v4().as_bytes().to_owned();
        uuid_bytes[..since_epoch_be.len()].clone_from_slice(&since_epoch_be[..]);
        Self(Uuid::from_bytes(uuid_bytes))
    }

    /// Get the null [UUID](Uuid), which is all zeroes.
    pub const fn null() -> Self {
        Self(Uuid::nil())
    }

    /// A const equivalent to [From<u128>::from]
    ///
    /// ```
    /// use datom::ID;
    /// assert_eq!(ID::from_u128(0), ID::null());
    /// ```
    pub const fn from_u128(x: u128) -> Self {
        Self(Uuid::from_u128(x))
    }
}

impl Default for ID {
    /// ```
    /// datom::ID::default();
    /// ```
    fn default() -> Self {
        Self::new()
    }
}

impl FromStr for ID {
    type Err = Box<dyn std::error::Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Self(Uuid::from_str(s)?))
    }
}

impl ToString for ID {
    fn to_string(&self) -> String {
        self.0.to_string()
    }
}

impl From<u128> for ID {
    /// ```
    /// use datom::ID;
    /// assert_eq!(ID::from_u128(0), ID::null());
    /// ```
    fn from(n: u128) -> Self {
        Self(Uuid::from_u128(n))
    }
}

impl From<ID> for u128 {
    /// ```
    /// use datom::ID;
    /// assert_eq!(0u128, ID::null().into());
    /// ```
    fn from(val: ID) -> Self {
        val.0.as_u128()
    }
}

impl From<[u8; 16]> for ID {
    fn from(bytes: [u8; 16]) -> Self {
        Self(Uuid::from_bytes(bytes))
    }
}

impl From<&ID> for [u8; 16] {
    fn from(id: &ID) -> Self {
        id.0.as_bytes().to_owned()
    }
}

impl From<ID> for [u8; 16] {
    fn from(id: ID) -> Self {
        <[u8; 16]>::from(&id)
    }
}