use super::{BodyReader, ContentAddress, DomainTag, IdentityProfile, IdentityProfileVersion};
use crate::identity::HARNESS_IDENTITY_PROFILE;
macro_rules! content_address_reference {
(
$(#[$reference_meta:meta])*
$visibility:vis struct $reference:ident;
) => {
$(#[$reference_meta])*
$visibility struct $reference($crate::identity::ContentAddress);
};
(
$(#[$reader_meta:meta])*
value $reference:ident;
) => {
impl $reference {
$(#[$reader_meta])*
#[must_use]
pub const fn address(self) -> $crate::identity::ContentAddress {
self.0
}
}
};
(
$(#[$reader_meta:meta])*
borrowed $reference:ident;
) => {
impl $reference {
$(#[$reader_meta])*
#[must_use]
pub const fn address(&self) -> &$crate::identity::ContentAddress {
&self.0
}
}
};
}
pub(crate) use content_address_reference;
impl IdentityProfileVersion {
#[must_use]
pub const fn declared(position: u32) -> Self {
Self(position)
}
#[must_use]
pub const fn position(self) -> u32 {
self.0
}
}
impl DomainTag {
#[must_use]
pub const fn declared(spelling: &'static str, version: IdentityProfileVersion) -> Self {
let mut remaining = spelling.as_bytes();
while let [byte, tail @ ..] = remaining {
assert!(
matches!(*byte, b'a'..=b'z' | b'0'..=b'9' | b'-'),
"a domain tag contains a byte outside its declared character grammar"
);
remaining = tail;
}
Self { spelling, version }
}
#[must_use]
pub const fn spelling(self) -> &'static str {
self.spelling
}
#[must_use]
pub const fn version(self) -> IdentityProfileVersion {
self.version
}
}
impl IdentityProfile {
#[must_use]
pub const fn declared(stem: &'static str) -> Self {
Self { stem }
}
#[must_use]
pub const fn stem(self) -> &'static str {
self.stem
}
#[must_use]
pub fn context_for(self, tag: DomainTag) -> String {
let stem = self.stem;
let family = tag.spelling();
let version = tag.version().position();
format!("{stem}/{family}/v{version}")
}
}
impl ContentAddress {
pub(crate) const WIDTH: usize = size_of::<[u8; 32]>();
#[must_use]
pub fn derived(tag: DomainTag, preimage: &[u8]) -> Self {
Self(blake3::derive_key(
&HARNESS_IDENTITY_PROFILE.context_for(tag),
preimage,
))
}
#[must_use]
pub const fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
}
impl<'body, Refusal: Copy> BodyReader<'body, Refusal> {
pub(crate) const fn over(
body: &'body [u8],
truncated: Refusal,
length_outside_platform: fn(u64) -> Refusal,
) -> Self {
Self {
body,
at: 0,
truncated,
length_outside_platform,
}
}
pub(crate) fn u32(&mut self) -> Result<u32, Refusal> {
self.fixed::<4>().map(u32::from_be_bytes)
}
pub(crate) fn u64(&mut self) -> Result<u64, Refusal> {
self.fixed::<8>().map(u64::from_be_bytes)
}
pub(crate) fn count(&mut self) -> Result<usize, Refusal> {
let declared = self.u64()?;
usize::try_from(declared)
.map_err(|_beyond_platform| (self.length_outside_platform)(declared))
}
pub(crate) fn bytes(&mut self) -> Result<&'body [u8], Refusal> {
let length = self.count()?;
self.take(length)
}
pub(crate) const fn remaining(&self) -> usize {
self.body.len().saturating_sub(self.at)
}
fn fixed<const WIDTH: usize>(&mut self) -> Result<[u8; WIDTH], Refusal> {
let bytes = self.take(WIDTH)?;
<[u8; WIDTH]>::try_from(bytes).map_err(|_unexpected_width| self.truncated)
}
fn take(&mut self, width: usize) -> Result<&'body [u8], Refusal> {
let Some(end) = self.at.checked_add(width) else {
return Err(self.truncated);
};
let Some(bytes) = self.body.get(self.at..end) else {
return Err(self.truncated);
};
self.at = end;
Ok(bytes)
}
}