#![allow(missing_docs)]
use serde::{Deserialize, Serialize};
use crate::crossing::CrossingRecord;
use crate::quad::{Quad, Tree};
use crate::types::{CrossingType, Layer, UnitId};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Envelope {
pub cycle_index: u64,
pub source_unit: UnitId,
pub crossing_type: CrossingType,
pub quad: Quad,
pub crossing_record: Option<CrossingRecord>,
#[serde(default)]
pub target_layer: Option<Layer>,
}
impl Envelope {
pub fn new(cycle_index: u64, source_unit: UnitId, quad: Quad) -> Self {
Self {
cycle_index,
source_unit,
crossing_type: CrossingType::Vertical,
quad,
crossing_record: None,
target_layer: None,
}
}
pub fn with_crossing_type(
cycle_index: u64,
source_unit: UnitId,
crossing_type: CrossingType,
quad: Quad,
) -> Self {
Self {
cycle_index,
source_unit,
crossing_type,
quad,
crossing_record: None,
target_layer: None,
}
}
pub fn with_target_layer(
cycle_index: u64,
source_unit: UnitId,
quad: Quad,
target_layer: Layer,
) -> Self {
Self {
cycle_index,
source_unit,
crossing_type: CrossingType::Vertical,
quad,
crossing_record: None,
target_layer: Some(target_layer),
}
}
pub fn genesis(seed: &[u8; 32]) -> Self {
let seed_hash = blake3::hash(seed);
let quad = Quad::new(
*seed_hash.as_bytes(),
*seed_hash.as_bytes(),
Tree::new(),
);
Self {
cycle_index: 0,
source_unit: UnitId::FU,
crossing_type: CrossingType::Vertical,
quad,
crossing_record: None,
target_layer: None,
}
}
pub fn has_crossing_record(&self) -> bool {
self.crossing_record.is_some()
}
pub fn destination(&self) -> UnitId {
match self.crossing_type {
CrossingType::Vertical => self.source_unit.successor(),
CrossingType::Horizontal => self.source_unit,
}
}
pub fn quad_hash(&self) -> [u8; 32] {
self.quad.content_hash()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_envelope_has_no_crossing_record() {
let env = Envelope::new(1, UnitId::FU, Quad::empty());
assert!(!env.has_crossing_record());
}
#[test]
fn destination_follows_ring_topology_for_vertical() {
let env = Envelope::new(1, UnitId::FU, Quad::empty());
assert_eq!(env.destination(), UnitId::MU);
let env = Envelope::new(1, UnitId::HU, Quad::empty());
assert_eq!(env.destination(), UnitId::FU);
}
#[test]
fn destination_is_self_for_horizontal() {
let env =
Envelope::with_crossing_type(1, UnitId::FU, CrossingType::Horizontal, Quad::empty());
assert_eq!(env.destination(), UnitId::FU);
}
#[test]
fn genesis_envelope_derives_from_seed() {
let seed = [42u8; 32];
let env = Envelope::genesis(&seed);
assert_eq!(env.cycle_index, 0);
assert_eq!(env.source_unit, UnitId::FU);
assert_ne!(env.quad.root, [0u8; 32]);
assert_eq!(env.quad.root, env.quad.pointer);
}
}