feat: node id

This commit is contained in:
sevki 2024-11-20 15:54:45 +00:00
parent 1c32f0bc65
commit 3c0d144b5f
4 changed files with 185 additions and 17 deletions

39
Cargo.lock generated
View file

@ -261,6 +261,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "colored"
version = "1.9.4"
@ -1068,12 +1074,31 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "mac_address"
version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8836fae9d0d4be2c8b4efcdd79e828a2faa058a90d005abf42f91cac5493a08e"
dependencies = [
"nix",
"winapi",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "memoffset"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg",
]
[[package]]
name = "mime"
version = "0.3.17"
@ -1118,6 +1143,19 @@ dependencies = [
"version_check",
]
[[package]]
name = "nix"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [
"bitflags",
"cfg-if",
"cfg_aliases",
"libc",
"memoffset",
]
[[package]]
name = "num-conv"
version = "0.1.0"
@ -1165,6 +1203,7 @@ dependencies = [
"hex",
"insta",
"jetstream_wireformat",
"mac_address",
"serde",
"serde_json",
"sha1",

View file

@ -15,6 +15,7 @@ enumflags2 = "0.7.10"
git2 = { version = "0.18.3", optional = true, default-features = false }
hex = { version = "0.4.3", features = ["serde"] }
jetstream_wireformat = "6.0.0"
mac_address = { version = "1.1.7", optional = true }
serde = { version = "1.0.210", features = ["derive"] }
serde_json = "1.0.128"
sha1 = { version = "0.10.6", optional = true }
@ -35,6 +36,7 @@ ulid = ["dep:ulid"]
openapi = ["dep:utoipa"]
git = ["dep:git2"]
graphql = ["dep:async-graphql"]
node = ["dep:mac_address"]
[dev-dependencies]
insta = { version = "1.40.0", features = ["yaml"] }

View file

@ -4,7 +4,7 @@
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![deny(missing_docs)]
use std::{fmt::Display, hash::Hash, path::PathBuf, str::FromStr};
use std::{fmt::Display, hash::Hash, str::FromStr};
use digest::OutputSizeUser;
@ -28,6 +28,9 @@ pub const SEPARATOR: char = 'ː';
pub mod blake3;
/// fingerprint module
pub mod fingerprint;
#[cfg(feature = "node")]
/// node module
pub mod node;
#[cfg(feature = "git")]
/// git module
pub mod oid;
@ -72,6 +75,8 @@ pub(crate) enum BinaryType {
Uuid = 1 << 5,
// Fingerprint
Fingerprint = 1 << 6,
#[cfg(feature = "node")]
Node = 1 << 7,
}
impl From<char> for BinaryType {
@ -90,6 +95,7 @@ impl From<char> for BinaryType {
#[cfg(feature = "uuid")]
'i' => Self::Uuid,
'f' => Self::Fingerprint,
'n' => Self::Node,
_ => Self::Unknown,
}
}
@ -99,19 +105,21 @@ impl BinaryType {
fn char_code(&self) -> char {
match self {
#[cfg(feature = "sha1")]
Self::Sha1 => '1',
BinaryType::Sha1 => '1',
#[cfg(feature = "sha2")]
Self::Sha256 => '2',
BinaryType::Sha256 => '2',
#[cfg(feature = "sha3")]
Self::Sha3_512 => '3',
BinaryType::Sha3_512 => '3',
#[cfg(feature = "blake3")]
Self::Blake3 => 'b',
BinaryType::Blake3 => 'b',
#[cfg(feature = "ulid")]
Self::Ulid => 'u',
BinaryType::Ulid => 'u',
#[cfg(feature = "uuid")]
Self::Uuid => 'i',
Self::Unknown => '0',
Self::Fingerprint => 'f',
BinaryType::Uuid => 'i',
BinaryType::Unknown => '0',
BinaryType::Fingerprint => 'f',
#[cfg(feature = "node")]
BinaryType::Node => 'n',
}
}
}
@ -120,19 +128,21 @@ impl Display for BinaryType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
#[cfg(feature = "sha1")]
Self::Sha1 => write!(f, "sha1"),
BinaryType::Sha1 => write!(f, "sha1"),
#[cfg(feature = "sha2")]
Self::Sha256 => write!(f, "sha256"),
BinaryType::Sha256 => write!(f, "sha256"),
#[cfg(feature = "sha3")]
Self::Sha3_512 => write!(f, "sha3-512"),
BinaryType::Sha3_512 => write!(f, "sha3-512"),
#[cfg(feature = "blake3")]
Self::Blake3 => write!(f, "blake3"),
BinaryType::Blake3 => write!(f, "blake3"),
#[cfg(feature = "ulid")]
Self::Ulid => write!(f, "ulid"),
BinaryType::Ulid => write!(f, "ulid"),
#[cfg(feature = "uuid")]
Self::Uuid => write!(f, "uuid"),
Self::Unknown => write!(f, "unknown"),
Self::Fingerprint => write!(f, "fingerprint"),
BinaryType::Uuid => write!(f, "uuid"),
BinaryType::Unknown => write!(f, "unknown"),
BinaryType::Fingerprint => write!(f, "fingerprint"),
#[cfg(feature = "node")]
BinaryType::Node => write!(f, "node"),
}
}
}
@ -193,6 +203,8 @@ impl PartialEq for OkId {
(Digest::Uuid(_), _) => false,
(Digest::Fingerprint(a), Digest::Fingerprint(b)) => a == b,
(Digest::Fingerprint(_), _) => false,
(Digest::Node(a), Digest::Node(b)) => a == b,
(Digest::Node(_), _) => false,
}
}
}
@ -219,6 +231,7 @@ impl Hash for OkId {
Digest::Ulid(d) => d.hash(state),
Digest::Uuid(d) => d.hash(state),
Digest::Fingerprint(d) => d.hash(state),
Digest::Node(d) => d.hash(state),
}
}
}
@ -322,6 +335,10 @@ fn parse_okid(s: &str) -> Result<OkId, Error> {
hash_type,
digest: Digest::Fingerprint(rest.parse()?),
}),
BinaryType::Node => Ok(OkId {
hash_type,
digest: Digest::Node(rest.parse()?),
}),
}
}
@ -341,6 +358,8 @@ enum Digest {
#[cfg(feature = "uuid")]
Uuid(crate::uuid::Uuid),
Fingerprint(crate::fingerprint::Fingerprint),
#[cfg(feature = "node")]
Node(crate::node::Node),
}
impl Display for OkId {
@ -361,6 +380,8 @@ impl Display for OkId {
#[cfg(feature = "uuid")]
Digest::Uuid(uuid) => uuid.fmt(f),
Digest::Fingerprint(fingerprint) => fingerprint.fmt(f),
#[cfg(feature = "node")]
Digest::Node(node) => node.fmt(f),
}
}
}
@ -384,6 +405,8 @@ impl std::fmt::Debug for OkId {
Digest::Uuid(uuid) => std::fmt::Display::fmt(uuid, f),
Digest::Fingerprint(fingerprint) => std::fmt::Display::fmt(fingerprint, f),
#[cfg(feature = "node")]
Digest::Node(node) => std::fmt::Display::fmt(node, f),
}
}
}
@ -428,6 +451,7 @@ impl jetstream_wireformat::WireFormat for OkId {
Digest::Ulid(_ulid) => 128 / 8,
Digest::Uuid(_uuid) => 128 / 8,
Digest::Fingerprint(_fingerprint) => 64 / 8,
Digest::Node(_node) => 6 ,
}
}
@ -453,6 +477,9 @@ impl jetstream_wireformat::WireFormat for OkId {
Digest::Fingerprint(fingerprint) => {
u64::encode(&fingerprint.0, writer)?;
}
Digest::Node(node) => {
Data::encode(&Data(node.0.into()), writer)?;
}
}
Ok(())
@ -536,6 +563,18 @@ impl jetstream_wireformat::WireFormat for OkId {
digest: Digest::Fingerprint(crate::fingerprint::Fingerprint(data)),
})
}
BinaryType::Node => {
let data = Data::decode(reader)?;
let data = data.get(0..6).unwrap();
let mut buf = [0; 6];
if data.len() == 6 {
buf.copy_from_slice(data);
}
Ok(OkId {
hash_type: BinaryType::Node,
digest: Digest::Node(crate::node::Node(buf)),
})
}
}
}
}
@ -806,4 +845,14 @@ mod okid_tests {
assert_eq!(file, new_file);
}
#[cfg(feature = "node")]
#[test]
fn test_node_display() {
use mac_address::MacAddressIterator;
let binary_id = OkId::from(
MacAddressIterator::new().unwrap_or_else(|_| panic!("No mac address found")),
);
assert_eq!(binary_id.to_string().len(), 15);
}
}

78
src/node.rs Normal file
View file

@ -0,0 +1,78 @@
use std::{fmt::Display, str::FromStr};
use mac_address::{MacAddress, MacAddressIterator};
use crate::OkId;
/// Node ID type.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub(super) struct Node(pub(crate) [u8; 6]);
impl From<MacAddress> for OkId {
fn from(mac: MacAddress) -> Self {
OkId {
hash_type: crate::BinaryType::Node,
digest: crate::Digest::Node(Node(mac.bytes())),
}
}
}
impl From<MacAddressIterator> for OkId {
fn from(iter: MacAddressIterator) -> Self {
let mut iter = iter.into_iter();
let mut bytes_now = iter.next().unwrap().bytes();
for bytes in iter {
bytes_now
.iter_mut()
.zip(bytes.bytes().iter())
.for_each(|(a, b)| *a ^= b);
}
OkId {
hash_type: crate::BinaryType::Node,
digest: crate::Digest::Node(Node(bytes_now)),
}
}
}
impl Display for Node {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
hex::encode(self.0).fmt(f)
}
}
impl FromStr for Node {
type Err = super::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Node(
MacAddress::from_str(s)
.map_err(|_| super::Error::InvalidFormat)?
.bytes(),
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_node_from_mac_address() {
let mac = MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
let node = OkId::from(mac);
assert_eq!(
node,
OkId {
hash_type: crate::BinaryType::Node,
digest: crate::Digest::Node(Node([0x00, 0x11, 0x22, 0x33, 0x44, 0x55])),
}
);
}
#[test]
fn test_node_from_mac_address_iterator() {
let iter = MacAddressIterator::new().unwrap();
let id = OkId::from(iter);
assert_eq!(id.hash_type, crate::BinaryType::Node);
}
}