ulid and uuid

This commit is contained in:
sevki 2024-09-21 13:02:57 +01:00
parent 0722e3dac0
commit 30aef157ad
12 changed files with 418 additions and 109 deletions

7
Cargo.lock generated
View file

@ -225,7 +225,7 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "okid"
version = "0.1.1"
version = "0.1.3"
dependencies = [
"blake3",
"digest",
@ -402,6 +402,7 @@ checksum = "04f903f293d11f31c0c29e4148f6dc0d033a7f80cebc0282bea147611667d289"
dependencies = [
"getrandom",
"rand",
"uuid",
"web-time",
]
@ -416,6 +417,10 @@ name = "uuid"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
dependencies = [
"getrandom",
"wasm-bindgen",
]
[[package]]
name = "version_check"

View file

@ -1,6 +1,6 @@
[package]
name = "okid"
version = "0.1.1"
version = "0.1.3"
edition = "2021"
publish = ["oksoftware"]
@ -14,11 +14,11 @@ serde_bytes = "0.11.15"
sha1 = { version = "0.10.6", optional = true }
sha2 = { version = "0.10.8", optional = true }
sha3 = { version = "0.10.8", optional = true }
ulid = { version = "1.1.3", optional = true }
uuid = { version = "1.10.0", optional = true }
ulid = { version = "1.1.3", optional = true, features = ["uuid"] }
uuid = { version = "1.10.0", optional = true, features = ["js", "v4"] }
[features]
default = ["sha1", "sha2", "sha3", "blake3"]
default = ["sha1", "sha2", "sha3", "blake3", "uuid", "ulid"]
sha1 = ["dep:sha1"]
sha2 = ["dep:sha2"]
sha3 = ["dep:sha3"]

View file

@ -1,5 +1,5 @@
# okid
<img src="https://assets.ok.software/okid.png" align="right" width="200">
# okid
IDs represented as self identifying strings.

View file

@ -1,11 +1,10 @@
use std::fmt::Display;
use crate::{BinaryId, BinaryType, Digest};
use crate::{BinaryType, Digest, OkId};
#[derive(Copy, Clone, Debug, PartialEq)]
pub(super) struct Blake3([u8; 32]);
impl From<blake3::Hasher> for BinaryId {
impl From<blake3::Hasher> for OkId {
fn from(value: blake3::Hasher) -> Self {
let data = value.finalize();
let data = data.as_bytes();
@ -16,20 +15,27 @@ impl From<blake3::Hasher> for BinaryId {
Self {
hash_type: BinaryType::Blake3,
digest: Digest {
blake3: Blake3(buf),
},
digest: Digest::Blake3(Blake3(buf)),
}
}
}
impl Display for Blake3 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let buf = self.0;
// Write the hex digest
for byte in buf {
write!(f, "{:02x}", byte)?;
}
let data = self.0;
let buf = hex::encode(data);
f.write_str(&buf)?;
Ok(())
}
}
impl std::str::FromStr for Blake3 {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let buf = hex::decode(s)?;
let mut hash: [u8; 32] = [0; 32];
hash.copy_from_slice(&buf);
Ok(Blake3(hash))
}
}

View file

@ -1,17 +1,45 @@
//! okid is a library for generating cannocial self-describing binary identifiers for
//! git commits, sha1, sha256, sha512 hashes, ULIDs, UUIDs, datatime, extended,
//! and random identifiers, etc.
//! okid binary identifier
//! # Examples
//! ## sha1
//! ```rust
//! use sha1::Digest as sha1digest;
//! let hasher = sha1::Sha1::new();
//! let binary_id = okid::OkId::from(hasher);
//! insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709"###);
//! ```
//! ## sha256
//! ```rust
//! use sha2::Digest;
//! let mut hasher = sha2::Sha256::new();
//! hasher.update(b"hello world");
//! let binary_id = okid::OkId::from(hasher);
//! insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
//! 2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
//! "###);
//! ```
//!
//! The resulting strings look like this:
//! 2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
//! first character of the string is the type of the binary data
//! in this case 2 means sha256
//! the rest of the string is the hexadecimal representation of the binary data
//!
#![doc(html_logo_url = "https://assets.ok.software/okid.png")]
#![doc(html_favicon_url = "https://assets.ok.software/okid.png")]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![deny(missing_docs)]
use std::fmt::Display;
use std::{fmt::Display, str::FromStr};
use enumflags2::{bitflags, BitFlags};
use serde::{Deserialize, Serialize};
const SEPARATOR: char = 'ː';
#[cfg(feature = "blake3")]
/// blake3 module
pub mod blake3;
@ -24,6 +52,12 @@ pub mod sha2;
#[cfg(feature = "sha3")]
/// sha3 module
pub mod sha3;
#[cfg(feature = "ulid")]
/// ulid module
pub mod ulid;
#[cfg(feature = "uuid")]
/// uuid module
pub mod uuid;
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Hash)]
@ -40,6 +74,12 @@ pub(crate) enum BinaryType {
#[cfg(feature = "blake3")]
// Next bit means the size of the digest is of blake3 type
Blake3 = 1 << 3,
#[cfg(feature = "ulid")]
// ULID
Ulid = 1 << 4,
#[cfg(feature = "uuid")]
// UUID
Uuid = 1 << 5,
}
impl From<char> for BinaryType {
@ -53,6 +93,10 @@ impl From<char> for BinaryType {
'3' => Self::Sha3_512,
#[cfg(feature = "blake3")]
'b' => Self::Blake3,
#[cfg(feature = "ulid")]
'u' => Self::Ulid,
#[cfg(feature = "uuid")]
'i' => Self::Uuid,
_ => panic!("Invalid binary type"),
}
}
@ -69,6 +113,10 @@ impl BinaryType {
Self::Sha3_512 => '3',
#[cfg(feature = "blake3")]
Self::Blake3 => 'b',
#[cfg(feature = "ulid")]
Self::Ulid => 'u',
#[cfg(feature = "uuid")]
Self::Uuid => 'i',
}
}
}
@ -84,17 +132,116 @@ impl Display for BinaryType {
Self::Sha3_512 => write!(f, "sha3-512"),
#[cfg(feature = "blake3")]
Self::Blake3 => write!(f, "blake3"),
#[cfg(feature = "ulid")]
Self::Ulid => write!(f, "ulid"),
#[cfg(feature = "uuid")]
Self::Uuid => write!(f, "uuid"),
}
}
}
/// Bird is a binary identifier representable as data
pub struct BinaryId {
/// The digest of the binary identifier
pub struct OkId {
hash_type: BinaryType,
/// The digest of the binary identifier
digest: Digest,
}
impl Serialize for OkId {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for OkId {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
s.parse().map_err(serde::de::Error::custom)
}
}
#[derive(Debug, Clone)]
/// Errors that can occur when parsing an OkId
pub enum Error {
/// The length of the OkId is invalid
InvalidLength,
/// The hash type is invalid
InvalidHashType,
/// Error parsing hex
Hex(hex::FromHexError),
/// Invalid format
InvalidFormat,
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::InvalidLength => write!(f, "Invalid length"),
Error::InvalidHashType => write!(f, "Invalid hash type"),
Error::Hex(e) => write!(f, "Hex error: {}", e),
Error::InvalidFormat => write!(f, "Invalid format"),
}
}
}
impl From<hex::FromHexError> for Error {
fn from(e: hex::FromHexError) -> Self {
Error::Hex(e)
}
}
impl FromStr for OkId {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
parse_okid(s)
}
}
// parse the OkId from a string
// the string should be in the format of <hash_type><digest>
fn parse_okid(s: &str) -> Result<OkId, Error> {
let mut chars = s.chars();
let hash_type: BinaryType = chars.next().unwrap().into();
// eat the separator
if chars.next() != Some(SEPARATOR) {
return Err(Error::InvalidFormat);
}
let rest = chars.collect::<String>();
match hash_type {
#[cfg(feature = "sha1")]
BinaryType::Sha1 => Ok(OkId {
hash_type,
digest: Digest::Sha1(rest.parse()?),
}),
#[cfg(feature = "sha2")]
BinaryType::Sha256 => Ok(OkId {
hash_type,
digest: Digest::Sha256(rest.parse()?),
}),
#[cfg(feature = "sha3")]
BinaryType::Sha3_512 => Ok(OkId {
hash_type,
digest: Digest::Sha512(rest.parse()?),
}),
#[cfg(feature = "blake3")]
BinaryType::Blake3 => Ok(OkId {
hash_type,
digest: Digest::Blake3(rest.parse()?),
}),
#[cfg(feature = "ulid")]
BinaryType::Ulid => Ok(OkId {
hash_type,
digest: Digest::Ulid(rest.parse()?),
}),
#[cfg(feature = "uuid")]
BinaryType::Uuid => Ok(OkId {
hash_type,
digest: Digest::Uuid(rest.parse()?),
}),
}
}
#[bitflags]
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Hash)]
@ -139,46 +286,41 @@ impl Display for CommonSettings {
write!(f, "{}", buf + settings.as_str())
}
}
/// Digest of the binary identifier
union Digest {
/// u64 bit fp like hashes, probably not secure
u64: u64,
#[derive(Debug, Clone)]
enum Digest {
#[cfg(feature = "sha1")]
/// SHA-1 digest
sha1: crate::sha1::Sha1,
Sha1(crate::sha1::Sha1),
#[cfg(feature = "sha2")]
/// SHA-256 digest
sha256: crate::sha2::Sha256,
Sha256(crate::sha2::Sha256),
#[cfg(feature = "sha3")]
/// SHA-512 digest
sha512: crate::sha3::Sha512,
Sha512(crate::sha3::Sha512),
#[cfg(feature = "blake3")]
blake3: crate::blake3::Blake3,
Blake3(crate::blake3::Blake3),
#[cfg(feature = "ulid")]
Ulid(crate::ulid::Ulid),
#[cfg(feature = "uuid")]
Uuid(crate::uuid::Uuid),
}
impl From<u64> for Digest {
fn from(value: u64) -> Self {
Self { u64: value }
}
}
impl Display for BinaryId {
impl Display for OkId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Write the binary type code
write!(f, "{}ː", self.hash_type.char_code())?;
write!(f, "{}{}", self.hash_type.char_code(), SEPARATOR)?;
unsafe {
match self.hash_type {
#[cfg(feature = "sha1")]
BinaryType::Sha1 => self.digest.sha1.fmt(f),
#[cfg(feature = "sha2")]
BinaryType::Sha256 => self.digest.sha256.fmt(f),
#[cfg(feature = "sha3")]
BinaryType::Sha3_512 => self.digest.sha512.fmt(f),
#[cfg(feature = "blake3")]
BinaryType::Blake3 => self.digest.blake3.fmt(f),
}
match &self.digest {
#[cfg(feature = "sha1")]
Digest::Sha1(sha1) => sha1.fmt(f),
#[cfg(feature = "sha2")]
Digest::Sha256(sha256) => sha256.fmt(f),
#[cfg(feature = "sha3")]
Digest::Sha512(sha512) => sha512.fmt(f),
#[cfg(feature = "blake3")]
Digest::Blake3(blake3) => blake3.fmt(f),
#[cfg(feature = "ulid")]
Digest::Ulid(ulid) => ulid.fmt(f),
#[cfg(feature = "uuid")]
Digest::Uuid(uuid) => uuid.fmt(f),
}
}
}
@ -189,12 +331,12 @@ mod binary_id_tests {
#[cfg(feature = "sha1")]
use sha1::Digest as sha1digest;
use crate::BinaryId;
use crate::OkId;
#[cfg(feature = "sha1")]
#[test]
fn test_display() {
let hasher = sha1::Sha1::new();
let binary_id = BinaryId::from(hasher);
let binary_id = OkId::from(hasher);
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709
"###);
@ -204,7 +346,7 @@ mod binary_id_tests {
fn test_display_hello_world() {
let mut hasher = sha1::Sha1::new();
hasher.update(b"hello world");
let binary_id = BinaryId::from(hasher);
let binary_id = OkId::from(hasher);
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
1ː002aae6c35c94fcfb415dbe95f408b9ce91ee846ed
"###);
@ -214,7 +356,7 @@ mod binary_id_tests {
fn test_display_hello_world_sha256() {
let mut hasher = sha2::Sha256::new();
hasher.update(b"hello world");
let binary_id = BinaryId::from(hasher);
let binary_id = OkId::from(hasher);
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
"###);
@ -225,7 +367,7 @@ mod binary_id_tests {
fn test_display_hello_world_sha3() {
let mut hasher = sha3::Sha3_512::new();
hasher.update(b"hello world");
let binary_id = BinaryId::from(hasher);
let binary_id = OkId::from(hasher);
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
3ː840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a
"###);
@ -236,7 +378,67 @@ mod binary_id_tests {
fn test_display_hello_world_blake3() {
let mut hasher = blake3::Hasher::new();
hasher.update(b"hello world");
let binary_id = BinaryId::from(hasher);
let binary_id = OkId::from(hasher);
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
bːd74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24
"###);
}
#[cfg(feature = "ulid")]
#[test]
fn test_display_hello_world_ulid() {
let ulid = ulid::Ulid::from_parts(0x0192146907d25d66, 0x35da136af2f988ca);
let binary_id = OkId::from(ulid);
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
uː146907d25d66000035da136af2f988ca
"###);
}
#[cfg(feature = "uuid")]
#[test]
fn test_display_hello_world_uuid() {
let uuid = uuid::Uuid::from_u128(0x73da51ba29654c53909fc283d33e39ba);
let binary_id = OkId::from(uuid);
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
iː73da51ba29654c53909fc283d33e39ba
"###);
}
#[cfg(feature = "sha1")]
#[test]
fn test_parse_hello_world_sha1() {
let hash = "1ː002aae6c35c94fcfb415dbe95f408b9ce91ee846ed";
let binary_id = hash.parse::<OkId>().unwrap();
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
1ː002aae6c35c94fcfb415dbe95f408b9ce91ee846ed
"###);
}
#[cfg(feature = "sha2")]
#[test]
fn test_parse_hello_world_sha256() {
let hash = "2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
let binary_id = hash.parse::<OkId>().unwrap();
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
"###);
}
#[cfg(feature = "sha3")]
#[test]
fn test_parse_hello_world_sha3() {
let hash = "3ː840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a";
let binary_id = hash.parse::<OkId>().unwrap();
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
3ː840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a
"###);
}
#[cfg(feature = "blake3")]
#[test]
fn test_parse_hello_world_blake3() {
let hash = "bːd74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24";
let binary_id = hash.parse::<OkId>().unwrap();
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
bːd74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24
"###);

View file

@ -1,18 +1,15 @@
use std::fmt::Display;
use std::{fmt::Display, str::FromStr};
use digest::core_api::CoreWrapper;
use enumflags2::BitFlags;
use super::{BinaryId, BinaryType, CommonSettings, Digest};
use super::{BinaryType, CommonSettings, Digest, OkId};
#[derive(Copy, Clone, Debug, PartialEq)]
pub(super) struct Sha1(BitFlags<CommonSettings>, [u8; 20]);
#[cfg(feature = "sha1")]
use sha1::Digest as sha1Digest;
#[cfg(feature = "sha1")]
impl From<sha1::Sha1> for BinaryId {
impl From<sha1::Sha1> for OkId {
fn from(value: sha1::Sha1) -> Self {
let data = value.finalize();
let data = data.get(0..20).unwrap();
@ -23,13 +20,11 @@ impl From<sha1::Sha1> for BinaryId {
let empty: BitFlags<CommonSettings> = BitFlags::empty();
Self {
hash_type: BinaryType::Sha1,
digest: Digest {
sha1: Sha1(empty, buf),
},
digest: Digest::Sha1(Sha1(empty, buf)),
}
}
}
impl From<sha1::Sha1Core> for BinaryId {
impl From<sha1::Sha1Core> for OkId {
fn from(value: sha1::Sha1Core) -> Self {
CoreWrapper::from_core(value).into()
}
@ -38,12 +33,44 @@ impl From<sha1::Sha1Core> for BinaryId {
impl Display for Sha1 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let settings = self.0;
let buf = self.1;
write!(f, "{:02x}", settings.bits())?;
// Write the hex digest
for byte in buf {
write!(f, "{:02x}", byte)?;
}
let data = self.1;
let buf = hex::encode([settings.bits()]) + &hex::encode(data);
f.write_str(&buf)?;
Ok(())
}
}
impl FromStr for Sha1 {
type Err = super::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut settings = BitFlags::empty();
let buf = hex::decode(s)?;
let _ = buf.first().map(|&first| {
settings = BitFlags::from_bits_truncate(first);
});
let mut hash: [u8; 20] = [0; 20];
hash.copy_from_slice(&buf[1..]);
Ok(Sha1(settings, hash))
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn sha1_to_string() {
let hasher = sha1::Sha1::new();
let binary_id = OkId::from(hasher);
insta::assert_yaml_snapshot!(binary_id.to_string(), @r###"
1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709
"###);
}
#[test]
fn sha1_from_str() {
let hash = "1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709";
let _binary_id: OkId = hash.parse().unwrap();
}
}

View file

@ -1,15 +1,14 @@
use enumflags2::BitFlags;
use sha2::Digest;
use std::fmt::Display;
use std::{fmt::Display, str::FromStr};
use crate::BinaryId;
use crate::OkId;
use super::CommonSettings;
#[derive(Copy, Clone, Debug, PartialEq)]
pub(super) struct Sha256(BitFlags<CommonSettings>, [u8; 32]);
impl From<sha2::Sha256> for BinaryId {
impl From<sha2::Sha256> for OkId {
fn from(value: sha2::Sha256) -> Self {
let data = value.finalize();
let data = data.get(0..32).unwrap();
@ -20,9 +19,7 @@ impl From<sha2::Sha256> for BinaryId {
let empty: BitFlags<CommonSettings> = BitFlags::empty();
Self {
hash_type: super::BinaryType::Sha256,
digest: super::Digest {
sha256: Sha256(empty, buf),
},
digest: super::Digest::Sha256(Sha256(empty, buf)),
}
}
}
@ -30,12 +27,24 @@ impl From<sha2::Sha256> for BinaryId {
impl Display for Sha256 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let settings = self.0;
let buf = self.1;
write!(f, "{:02x}", settings.bits())?;
// Write the hex digest
for byte in buf {
write!(f, "{:02x}", byte)?;
}
let data = self.1;
let buf = hex::encode([settings.bits()]) + &hex::encode(data);
f.write_str(&buf)?;
Ok(())
}
}
impl FromStr for Sha256 {
type Err = super::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut settings = BitFlags::empty();
let buf = hex::decode(s)?;
let _ = buf.first().map(|&first| {
settings = BitFlags::from_bits_truncate(first);
});
let mut hash: [u8; 32] = [0; 32];
hash.copy_from_slice(&buf[1..]);
Ok(Sha256(settings, hash))
}
}

View file

@ -1,14 +1,13 @@
use std::fmt::Display;
use std::{fmt::Display, str::FromStr};
use digest::core_api::CoreWrapper;
use sha3::Digest;
use super::BinaryId;
use super::OkId;
#[derive(Copy, Clone, Debug, PartialEq)]
pub(super) struct Sha512([u8; 64]);
impl From<sha3::Sha3_512> for BinaryId {
impl From<sha3::Sha3_512> for OkId {
fn from(value: sha3::Sha3_512) -> Self {
let data = value.finalize();
let data = data.get(0..64).unwrap();
@ -19,14 +18,12 @@ impl From<sha3::Sha3_512> for BinaryId {
Self {
hash_type: super::BinaryType::Sha3_512,
digest: super::Digest {
sha512: Sha512(buf),
},
digest: super::Digest::Sha512(Sha512(buf)),
}
}
}
impl From<sha3::Sha3_512Core> for BinaryId {
impl From<sha3::Sha3_512Core> for OkId {
fn from(value: sha3::Sha3_512Core) -> Self {
CoreWrapper::from_core(value).into()
}
@ -34,11 +31,19 @@ impl From<sha3::Sha3_512Core> for BinaryId {
impl Display for Sha512 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let buf = self.0;
// Write the hex digest
for byte in buf {
write!(f, "{:02x}", byte)?;
}
let buf = hex::encode(self.0);
f.write_str(&buf)?;
Ok(())
}
}
impl FromStr for Sha512 {
type Err = super::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let buf = hex::decode(s)?;
let mut hash: [u8; 64] = [0; 64];
hash.copy_from_slice(&buf);
Ok(Sha512(hash))
}
}

View file

@ -1,5 +0,0 @@
---
source: src/lib.rs
expression: binary_id.to_string()
---
1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709

View file

@ -1,5 +0,0 @@
---
source: src/lib.rs
expression: binary_id.to_string()
---
1ː002aae6c35c94fcfb415dbe95f408b9ce91ee846ed

33
src/ulid.rs Normal file
View file

@ -0,0 +1,33 @@
use std::fmt::Display;
use crate::OkId;
#[derive(Copy, Clone, Debug, PartialEq)]
pub(super) struct Ulid(u128);
impl From<ulid::Ulid> for OkId {
fn from(value: ulid::Ulid) -> Self {
Self {
hash_type: super::BinaryType::Ulid,
digest: super::Digest::Ulid(Ulid(value.into())),
}
}
}
impl Display for Ulid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let buf = hex::encode(self.0.to_be_bytes());
write!(f, "{}", buf)
}
}
impl std::str::FromStr for Ulid {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let buf = hex::decode(s)?;
let mut hash: [u8; 16] = [0; 16];
hash.copy_from_slice(&buf);
Ok(Ulid(u128::from_be_bytes(hash)))
}
}

32
src/uuid.rs Normal file
View file

@ -0,0 +1,32 @@
use std::fmt::Display;
use crate::OkId;
#[derive(Copy, Clone, Debug, PartialEq)]
pub(super) struct Uuid(u128);
impl From<uuid::Uuid> for OkId {
fn from(value: uuid::Uuid) -> Self {
Self {
hash_type: super::BinaryType::Uuid,
digest: super::Digest::Uuid(Uuid(value.as_u128())),
}
}
}
impl Display for Uuid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let buf = hex::encode(self.0.to_be_bytes());
write!(f, "{}", buf)
}
}
impl std::str::FromStr for Uuid {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let buf = hex::decode(s)?;
let mut hash: [u8; 16] = [0; 16];
hash.copy_from_slice(&buf);
Ok(Uuid(u128::from_be_bytes(hash)))
}
}