hibana 0.5.3

Const-projected Affine Multiparty Session Types for choreography-first Rust protocols
Documentation
//! Control-plane type-level invariants.
//!
//! This module defines marker traits and newtypes that encode invariants at the type level:
//! - No cross-lane aliasing
//! - At-most-once commit
//! - Strictly increasing generation
//! - Single-use shot discipline

/// Marker trait: guarantees no cross-lane aliasing.
///
/// Types implementing this trait ensure that multiple lanes cannot alias the same resource.
pub(crate) trait NoCrossLaneAliasing {}

/// Marker trait: guarantees at-most-once commit.
///
/// Types implementing this trait ensure that a transaction can be committed at most once.
pub(crate) trait AtMostOnceCommit {}

/// Type marker for strictly increasing generation.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct IncreasingGen;

/// One-shot type marker.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct One;

/// Multi-shot type marker.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Many;

/// Lane identifier.
///
/// Lanes are wire-visible `u8` values. Construction rejects values outside the
/// wire domain so capability and topology handles cannot silently alias lanes by
/// truncation.
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Lane(u8);

impl Lane {
    /// Create a new lane identifier.
    pub const fn new(id: u32) -> Self {
        assert!(id <= u8::MAX as u32, "lane id must be <= 255");
        Self(id as u8)
    }

    /// Fallible constructor for descriptor and wire decode paths.
    pub const fn try_new(id: u32) -> Option<Self> {
        if id <= u8::MAX as u32 {
            Some(Self(id as u8))
        } else {
            None
        }
    }

    /// Get the raw lane identifier.
    pub const fn raw(self) -> u32 {
        self.0 as u32
    }

    /// Convert to wire format.
    pub const fn as_wire(self) -> u8 {
        self.0
    }
}

/// Generation number (newtype for type safety).
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Generation(pub u16);

impl Generation {
    /// Initial generation.
    pub const ZERO: Self = Self(0);

    /// Create a new generation.
    pub const fn new(value: u16) -> Self {
        Self(value)
    }

    /// Get the raw generation number.
    pub const fn raw(self) -> u16 {
        self.0
    }

    /// Convert to wire format (u16).
    ///
    /// # Note
    /// Generation is already u16, so this is an identity operation.
    /// Provided for consistency with Lane::as_wire().
    pub const fn as_wire(self) -> u16 {
        self.0
    }

    /// Increment generation (saturating).
    pub fn bump(self) -> Self {
        Self(self.0.saturating_add(1))
    }
}

/// Session identifier (newtype for type safety).
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct SessionId(pub u32);

impl SessionId {
    /// Create a new session identifier.
    pub const fn new(id: u32) -> Self {
        Self(id)
    }

    /// Get the raw session identifier.
    pub const fn raw(self) -> u32 {
        self.0
    }
}

/// Rendezvous identifier (newtype for type safety).
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct RendezvousId(pub u16);

impl RendezvousId {
    /// Create a new rendezvous identifier.
    pub const fn new(id: u16) -> Self {
        Self(id)
    }

    /// Get the raw rendezvous identifier.
    pub const fn raw(self) -> u16 {
        self.0
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_gen_bump() {
        let generation = Generation::ZERO;
        assert_eq!(generation.bump(), Generation::new(1));
        assert_eq!(generation.bump().bump(), Generation::new(2));

        // Saturating behavior
        let max_gen = Generation::new(u16::MAX);
        assert_eq!(max_gen.bump(), max_gen);
    }
}