use super::{Output, RENDERED_BYTE_LIMIT, RenderError, RenderedProjection, RenderedUnit};
use crate::bounded::{NonEmpty, NonEmptyError};
use crate::identity::{self, Identity, OwnerIdentity, Profile, Transcript};
use crate::kind::{Destination, Kind, Role};
use crate::origin::OriginTrail;
use crate::plan::{DigestContract, MEMBERSHIP_LIMIT, Plan, PlannedMember, PlannedOutput};
use crate::token::GeneratedTree;
impl<R: Role> RenderedUnit<R> {
pub fn materialized(
planned: &PlannedMember<R>,
tree: GeneratedTree,
) -> Result<Self, RenderError> {
let material = tree.canonical_bytes();
if material.len() > RENDERED_BYTE_LIMIT {
return Err(RenderError::BytesUnbounded {
role: planned.role.name(),
bound: RENDERED_BYTE_LIMIT,
observed: material.len(),
});
}
let output = &planned.output;
let position = u32::from(planned.role.slot());
let digest = Identity::derived(Transcript::under_projection(
identity::Role::OutputBytes,
&output.semantic_key,
&material,
position,
));
let derived = Identity::derived(Transcript::under_projection(
identity::Role::RenderedUnit,
&output.semantic_key,
&material,
position,
));
Ok(Self {
role: planned.role,
identity: derived,
semantic_key: output.semantic_key,
profile: output.expected_profile,
origin: output.origin.clone(),
address: output.address,
tree,
digest,
})
}
#[must_use]
pub const fn role(&self) -> R {
self.role
}
#[must_use]
pub const fn identity(&self) -> Identity<identity::RenderedUnit> {
self.identity
}
#[must_use]
pub const fn semantic_key(&self) -> Identity<identity::GeneratedUnit> {
self.semantic_key
}
#[must_use]
pub fn destination(&self) -> Destination {
self.role.destination()
}
#[must_use]
pub const fn profile(&self) -> Profile {
self.profile
}
#[must_use]
pub const fn origin(&self) -> &OriginTrail {
&self.origin
}
pub const fn address(&self) -> Option<OwnerIdentity> {
self.address
}
#[must_use]
pub const fn tree(&self) -> &GeneratedTree {
&self.tree
}
#[must_use]
pub const fn digest(&self) -> Identity<identity::OutputBytes> {
self.digest
}
#[must_use]
pub fn bytes(&self) -> Vec<u8> {
self.tree.canonical_bytes()
}
#[must_use]
pub fn reconstructed(&self) -> PlannedMember<R> {
PlannedMember {
role: self.role,
output: PlannedOutput {
semantic_key: self.semantic_key,
origin: self.origin.clone(),
expected_profile: self.profile,
address: self.address,
digest_contract: DigestContract {
anchored_to: self.semantic_key,
},
},
}
}
#[must_use]
pub fn digest_under(&self, contract: DigestContract) -> Identity<identity::OutputBytes> {
let material = self.tree.canonical_bytes();
Identity::derived(Transcript::under_projection(
identity::Role::OutputBytes,
&contract.anchored_to,
&material,
u32::from(self.role.slot()),
))
}
}
impl<R: Role> RenderedProjection<R> {
#[must_use]
pub fn of_one(unit: RenderedUnit<R>) -> Self {
Self {
units: NonEmpty::one(unit),
}
}
pub fn materialized(units: Vec<RenderedUnit<R>>) -> Result<Self, RenderError> {
NonEmpty::new(units)
.map(|admitted| Self { units: admitted })
.map_err(|refusal| match refusal {
NonEmptyError::Empty(_) => RenderError::NothingRendered,
NonEmptyError::Overflow(overflow) => RenderError::UnitsUnbounded {
bound: overflow.capacity,
observed: overflow.offered,
},
})
}
#[must_use]
pub fn first(&self) -> &RenderedUnit<R> {
self.units.first()
}
#[must_use]
pub fn units(&self) -> &NonEmpty<RenderedUnit<R>, MEMBERSHIP_LIMIT> {
&self.units
}
pub fn under(&self, role: R) -> Option<&RenderedUnit<R>> {
self.units().iter().find(|unit| unit.role() == role)
}
pub fn units_under(&self, role: R) -> impl Iterator<Item = &RenderedUnit<R>> {
self.units().iter().filter(move |unit| unit.role() == role)
}
#[must_use]
pub fn count_under(&self, role: R) -> usize {
self.units_under(role).count()
}
pub fn units_to(&self, destination: Destination) -> impl Iterator<Item = &RenderedUnit<R>> {
R::ALL
.iter()
.copied()
.filter(move |role| role.destination() == destination)
.flat_map(move |role| self.units_under(role))
}
#[must_use]
pub fn count_to(&self, destination: Destination) -> usize {
self.units_to(destination).count()
}
#[must_use]
pub fn count(&self) -> usize {
self.units.count()
}
}
impl<'plan, K: Kind> Output<'plan, K> {
#[must_use]
pub const fn over(plan: &'plan Plan<K>) -> Self {
Self {
plan,
units: Vec::new(),
}
}
pub fn unit(&mut self, role: K::Role, tree: GeneratedTree) -> Result<(), RenderError> {
let plan = self.plan;
let planned = plan
.membership()
.under(role)
.ok_or_else(|| RenderError::SeatUnplanned { role: role.name() })?;
let rendered = RenderedUnit::materialized(planned, tree)?;
self.units.push(rendered);
Ok(())
}
pub fn rendered(self) -> Result<RenderedProjection<K::Role>, RenderError> {
RenderedProjection::materialized(self.units)
}
}