use bincode_next::{Decode, Encode};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)]
pub struct NodeHash(pub(crate) u64);
impl NodeHash {
pub const ZERO: Self = Self(0);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)]
pub struct NodeFlags {
bits: u8,
}
impl NodeFlags {
pub const EMPTY: Self = Self { bits: 0 };
const COMMUTATIVE: u8 = 0b0000_0001;
const ASSOCIATIVE: u8 = 0b0000_0010;
const CANONICAL: u8 = 0b0000_0100;
#[must_use]
pub const fn commutative() -> Self {
Self {
bits: Self::COMMUTATIVE,
}
}
#[must_use]
pub const fn commutative_associative() -> Self {
Self {
bits: Self::COMMUTATIVE | Self::ASSOCIATIVE,
}
}
#[must_use]
pub const fn is_commutative(self) -> bool {
self.bits & Self::COMMUTATIVE != 0
}
#[must_use]
pub const fn is_associative(self) -> bool {
self.bits & Self::ASSOCIATIVE != 0
}
#[must_use]
pub const fn is_canonical(self) -> bool {
self.bits & Self::CANONICAL != 0
}
#[must_use]
pub const fn with_canonical(self) -> Self {
Self {
bits: self.bits | Self::CANONICAL,
}
}
#[must_use]
pub const fn without_canonical(self) -> Self {
Self {
bits: self.bits & !Self::CANONICAL,
}
}
#[must_use]
pub const fn bits(self) -> u8 {
self.bits
}
#[must_use]
pub const fn from_bits(bits: u8) -> Self {
Self { bits }
}
}
#[derive(Debug, Clone, PartialEq, Encode, Decode)]
pub struct NodeMetadata {
pub hash: NodeHash,
pub coefficient: f64,
pub flags: NodeFlags,
}
impl NodeMetadata {
#[must_use]
pub const fn leaf(hash: NodeHash) -> Self {
Self {
hash,
coefficient: 1.0,
flags: NodeFlags::EMPTY,
}
}
#[must_use]
pub const fn operator(hash: NodeHash, flags: NodeFlags) -> Self {
Self {
hash,
coefficient: 1.0,
flags,
}
}
#[must_use]
pub const fn with_coefficient(mut self, coeff: f64) -> Self {
self.coefficient = coeff;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn flags_round_trip() {
let f = NodeFlags::commutative_associative();
assert!(f.is_commutative());
assert!(f.is_associative());
assert!(!f.is_canonical());
let f2 = f.with_canonical();
assert!(f2.is_canonical());
assert!(f2.is_commutative());
}
#[test]
fn leaf_metadata() {
let m = NodeMetadata::leaf(NodeHash(42));
assert_eq!(m.coefficient, 1.0);
assert_eq!(m.hash, NodeHash(42));
}
#[test]
fn coefficient_override() {
let m = NodeMetadata::leaf(NodeHash(1)).with_coefficient(3.5);
assert_eq!(m.coefficient, 3.5);
}
}