ulid and uuid
This commit is contained in:
parent
0722e3dac0
commit
30aef157ad
12 changed files with 418 additions and 109 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# okid
|
||||
|
||||
<img src="https://assets.ok.software/okid.png" align="right" width="200">
|
||||
|
||||
# okid
|
||||
|
||||
IDs represented as self identifying strings.
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
280
src/lib.rs
280
src/lib.rs
|
@ -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
|
||||
"###);
|
||||
|
|
59
src/sha1.rs
59
src/sha1.rs
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
35
src/sha2.rs
35
src/sha2.rs
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
31
src/sha3.rs
31
src/sha3.rs
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
source: src/lib.rs
|
||||
expression: binary_id.to_string()
|
||||
---
|
||||
1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
source: src/lib.rs
|
||||
expression: binary_id.to_string()
|
||||
---
|
||||
1ː002aae6c35c94fcfb415dbe95f408b9ce91ee846ed
|
33
src/ulid.rs
Normal file
33
src/ulid.rs
Normal 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
32
src/uuid.rs
Normal 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)))
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue