use data_encoding::BASE64URL_NOPAD;
use liter::Value;
use rand::Rng;
use serde::{Serialize, Deserialize};
#[derive(
Copy,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
Value
)]
pub struct NodeID {
id: [u8; 6]
}
impl NodeID {
pub fn get(self) -> [u8; 6] { self.id }
pub fn random() -> Self {
let mut id: [u8; 6] = rand::rng().random();
id[0] |= 0b1;
Self {id}
}
pub fn inner(&self) -> &[u8; 6] {&self.id}
pub fn from_u64(packed: u64) -> Self {
let [_, _, a, b, c, d, e, f] = packed.to_le_bytes();
Self { id: [a, b, c, d, e, f] }
}
pub fn to_u64(self) -> u64 {
let Self { id: [a, b, c, d, e, f]} = self;
u64::from_le_bytes([0, 0, a, b, c, d, e, f])
}
}
impl std::ops::Deref for NodeID {
type Target = [u8];
fn deref(&self) -> &[u8] {&self.id}
}
impl std::convert::AsRef<[u8; 6]> for NodeID {
fn as_ref(&self) -> &[u8; 6] {&self.id}
}
impl std::convert::AsMut<[u8; 6]> for NodeID {
fn as_mut(&mut self) -> &mut [u8; 6] {&mut self.id}
}
impl std::convert::From<[u8; 6]> for NodeID {
fn from(id: [u8; 6]) -> Self {Self{id}}
}
impl std::convert::From<NodeID> for [u8; 6] {
fn from(node_id: NodeID) -> [u8; 6] {node_id.id}
}
impl std::str::FromStr for NodeID {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match BASE64URL_NOPAD.decode(s.as_bytes()) {
Ok(id_vec) if id_vec.len() == 6 => {
Ok(Self {id: id_vec.try_into().unwrap()})
},
Ok(_) => Err("ID is not exactly 6 bytes long!".to_owned()),
Err(e) => Err(
format!("failed to decode URL-safe base64 ID: {e}")
)
}
}
}
impl std::fmt::Display for NodeID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
BASE64URL_NOPAD.encode(&self.id).fmt(f)
}
}
impl std::fmt::Debug for NodeID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
}
}