fluidattacks-blends-domain 0.36.0

Blends functional core: pure AST graph to syntax graph (no_std)
Documentation
use core::num::NonZeroU32;

macro_rules! stack_variable {
    ($(#[$doc:meta])* $name:ident) => {
        $(#[$doc])*
        #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
        #[non_exhaustive]
        pub struct $name(NonZeroU32);

        impl $name {
            /// The first variable of a path.
            pub const INITIAL: Self = Self(NonZeroU32::MIN);

            /// The variable numbered `id`; `None` for 0, which numbers no variable.
            #[must_use]
            pub fn new(id: u32) -> Option<Self> {
                NonZeroU32::new(id).map(Self)
            }

            /// This variable's number.
            #[must_use]
            pub const fn get(self) -> u32 {
                self.0.get()
            }

            /// This variable renumbered `offset` places up; `None` past the last number.
            #[must_use]
            pub fn with_offset(self, offset: u32) -> Option<Self> {
                self.0.checked_add(offset).map(Self)
            }
        }
    };
}

stack_variable!(
    /// Stands for the unknown rest of a partial symbol stack.
    SymbolStackVariable
);

stack_variable!(
    /// Stands for the unknown rest of a partial scope stack.
    ScopeStackVariable
);

#[cfg(test)]
mod tests {
    use super::{ScopeStackVariable, SymbolStackVariable};

    #[test]
    fn zero_numbers_no_variable() {
        assert_eq!(SymbolStackVariable::new(0), None);
        assert_eq!(ScopeStackVariable::new(0), None);
    }

    #[test]
    fn the_initial_variable_is_number_one() {
        assert_eq!(SymbolStackVariable::INITIAL.get(), 1);
        assert_eq!(ScopeStackVariable::INITIAL.get(), 1);
    }

    #[test]
    fn an_offset_renumbers_a_variable_up() {
        assert_eq!(
            SymbolStackVariable::INITIAL.with_offset(2),
            SymbolStackVariable::new(3)
        );
    }

    #[test]
    fn an_offset_past_the_last_number_gives_no_variable() {
        let last = ScopeStackVariable::new(u32::MAX).unwrap();

        assert_eq!(last.with_offset(1), None);
        assert_eq!(last.with_offset(0), Some(last));
    }
}