use super::*;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NodeId([u8; 16]);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StableFaceId([u8; 16]);
pub const ROOT_NODE_ID: NodeId = NodeId::from_path("<root>", "root");
impl NodeId {
#[doc(hidden)]
pub const fn from_raw(bytes: [u8; 16]) -> Self {
Self(bytes)
}
pub const fn from_path(relative_path: &str, declared_name: &str) -> Self {
Self(sha256_path_prefix(
relative_path.as_bytes(),
declared_name.as_bytes(),
true,
))
}
pub const fn from_namespaced_path(
namespace: &str,
relative_path: &str,
declared_name: &str,
) -> Self {
let scoped = sha256_path_prefix(namespace.as_bytes(), relative_path.as_bytes(), true);
Self(sha256_prefix(&scoped, declared_name.as_bytes(), true))
}
pub const fn from_bytes(input: &[u8]) -> Self {
Self(sha256_prefix(input, &[], false))
}
pub const fn into_bytes(self) -> [u8; 16] {
self.0
}
pub const fn pruning_table(self) -> [u64; 4096] {
let bytes = self.0;
let mut state = u64::from_le_bytes([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
]);
let mut table = [0_u64; 4096];
let mut index = 0;
while index < table.len() {
state ^= state << 13;
state ^= state >> 7;
state ^= state << 17;
table[index] = state.wrapping_add(index as u64);
index += 1;
}
table
}
}
pub const fn root_node_id(namespace: &str) -> NodeId {
NodeId::from_namespaced_path(namespace, "<root>", "root")
}
impl StableFaceId {
pub const fn from_name(name: &str) -> Self {
Self(sha256_prefix(name.as_bytes(), &[], false))
}
pub const fn into_bytes(self) -> [u8; 16] {
self.0
}
}
impl fmt::Display for NodeId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in self.0 {
write!(formatter, "{byte:02x}")?;
}
Ok(())
}
}
impl fmt::Display for StableFaceId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in self.0 {
write!(formatter, "{byte:02x}")?;
}
Ok(())
}
}
impl fmt::Debug for StableFaceId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, formatter)
}
}
impl fmt::Debug for NodeId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, formatter)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ParseNodeIdError;
impl fmt::Display for ParseNodeIdError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("node identity must contain exactly 32 hexadecimal digits")
}
}
impl std::error::Error for ParseNodeIdError {}
impl FromStr for NodeId {
type Err = ParseNodeIdError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
if value.len() != 32 {
return Err(ParseNodeIdError);
}
let bytes = value.as_bytes();
let mut id = [0_u8; 16];
for index in 0..16 {
let high = hex_nibble(bytes[index * 2]).ok_or(ParseNodeIdError)?;
let low = hex_nibble(bytes[index * 2 + 1]).ok_or(ParseNodeIdError)?;
id[index] = (high << 4) | low;
}
Ok(Self(id))
}
}
pub(crate) const fn hex_nibble(byte: u8) -> Option<u8> {
match byte {
b'0'..=b'9' => Some(byte - b'0'),
b'a'..=b'f' => Some(byte - b'a' + 10),
b'A'..=b'F' => Some(byte - b'A' + 10),
_ => None,
}
}
pub fn hex_decode(value: &str) -> Option<Vec<u8>> {
if !value.len().is_multiple_of(2) {
return None;
}
let bytes = value.as_bytes();
let mut decoded = Vec::with_capacity(bytes.len() / 2);
let chunk = bytes.as_chunks::<2>().0;
for pair in chunk {
let high = hex_nibble(pair[0])?;
let low = hex_nibble(pair[1])?;
decoded.push((high << 4) | low);
}
Some(decoded)
}