use kitsune_p2p_dht_arc::DhtLocation;
pub trait KitsuneBinType:
'static
+ Send
+ Sync
+ std::fmt::Debug
+ Clone
+ std::hash::Hash
+ PartialEq
+ Eq
+ PartialOrd
+ Ord
+ std::convert::Into<Vec<u8>>
{
fn new(bytes: Vec<u8>) -> Self;
fn get_bytes(&self) -> &[u8];
fn get_loc(&self) -> DhtLocation;
}
fn bytes_to_loc(bytes: &[u8]) -> u32 {
(bytes[0] as u32)
+ ((bytes[1] as u32) << 8)
+ ((bytes[2] as u32) << 16)
+ ((bytes[3] as u32) << 24)
}
macro_rules! make_kitsune_bin_type {
($($doc:expr, $name:ident),*,) => {
$(
#[doc = $doc]
#[derive(
Clone,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
shrinkwraprs::Shrinkwrap,
derive_more::Into,
serde::Serialize,
serde::Deserialize,
)]
#[shrinkwrap(mutable)]
pub struct $name(#[serde(with = "serde_bytes")] pub Vec<u8>);
impl KitsuneBinType for $name {
fn new(mut bytes: Vec<u8>) -> Self {
if bytes.len() != 36 {
debug_assert_eq!(bytes.len(), 32);
bytes.append(&mut [0; 4].to_vec());
}
debug_assert_eq!(bytes.len(), 36);
Self(bytes)
}
fn get_bytes(&self) -> &[u8] {
&self.0[..self.0.len() - 4]
}
fn get_loc(&self) -> DhtLocation {
DhtLocation::new(bytes_to_loc(&self.0[self.0.len() - 4..]))
}
}
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}(0x{})", stringify!($name), &bytes_to_hex(&self.0)))
}
}
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
base64::encode_config(&self.0, base64::URL_SAFE_NO_PAD).fmt(f)
}
}
impl AsRef<[u8]> for $name {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
#[cfg(feature = "arbitrary")]
impl<'a> arbitrary::Arbitrary<'a> for $name {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let mut buf = [0; 36];
buf[..]
.copy_from_slice(u.bytes(36)?);
Ok(Self::new(buf.to_vec()))
}
}
)*
};
}
make_kitsune_bin_type! {
"Distinguish multiple categories of communication within the same network module.",
KitsuneSpace,
"Distinguish multiple agents within the same network module.",
KitsuneAgent,
"The basis hash/coordinate when identifying a neighborhood.",
KitsuneBasis,
r#"Top-level "KitsuneDataHash" items are buckets of related meta-data.
These metadata "Operations" each also have unique OpHashes."#,
KitsuneOpHash,
}
#[derive(PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(transparent)]
#[serde(transparent)]
pub struct KitsuneOpData(
#[serde(with = "serde_bytes")]
pub Vec<u8>,
);
impl KitsuneOpData {
pub fn new(op: Vec<u8>) -> KOp {
KOp::new(Self(op))
}
pub fn size(&self) -> usize {
self.0.len()
}
}
impl From<Vec<u8>> for KitsuneOpData {
fn from(d: Vec<u8>) -> Self {
Self(d)
}
}
pub fn bytes_to_hex(bytes: &[u8]) -> String {
use std::fmt::Write;
let mut s = String::with_capacity(bytes.len());
for b in bytes {
write!(&mut s, "{:02x}", b).ok();
}
s
}
pub fn many_bytes_string(bytes: &[u8]) -> String {
if bytes.len() <= 32 {
format!("0x{}", bytes_to_hex(bytes))
} else {
let l = bytes.len();
format!(
"[0x{}..{}; len={}]",
bytes_to_hex(&bytes[0..8]),
bytes_to_hex(&bytes[l - 8..l]),
l
)
}
}
impl std::fmt::Debug for KitsuneOpData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"KitsuneOpData({})",
&many_bytes_string(self.0.as_slice())
))
}
}
pub type KOp = std::sync::Arc<KitsuneOpData>;
#[derive(
Clone,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
shrinkwraprs::Shrinkwrap,
derive_more::From,
derive_more::Into,
serde::Deserialize,
serde::Serialize,
)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[shrinkwrap(mutable)]
pub struct KitsuneSignature(#[serde(with = "serde_bytes")] pub Vec<u8>);
impl std::fmt::Debug for KitsuneSignature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("Signature(0x"))?;
for byte in &self.0 {
f.write_fmt(format_args!("{:02x}", byte))?;
}
f.write_fmt(format_args!(")"))?;
Ok(())
}
}