Skip to main content

khive_types/
substrate.rs

1//! Substrate discriminant — the 3 data types in khive.
2//!
3//! Full substrate structs live in the sibling modules (`note`, `entity`,
4//! `event`). This module provides the discriminant for typed dispatch and
5//! persistence.
6
7use core::fmt;
8use core::str::FromStr;
9
10/// The 3 substrate types in khive OSS.
11///
12/// - **Note**: temporal-referential records (observations, insights, decisions)
13/// - **Entity**: graph nodes with properties and typed links
14/// - **Event**: universal system log — every verb execution produces one
15#[repr(u8)]
16#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
19pub enum SubstrateKind {
20    Note = 0,
21    Entity = 1,
22    Event = 2,
23}
24
25/// Total number of substrate kinds. Matches the length of [`SubstrateKind::ALL`].
26pub const SUBSTRATE_COUNT: usize = 3;
27
28impl SubstrateKind {
29    /// All substrate kinds in discriminant order.
30    pub const ALL: [SubstrateKind; SUBSTRATE_COUNT] = [
31        SubstrateKind::Note,
32        SubstrateKind::Entity,
33        SubstrateKind::Event,
34    ];
35
36    /// Return the canonical lowercase name for this substrate, as stored on the wire.
37    #[inline]
38    pub const fn name(self) -> &'static str {
39        match self {
40            Self::Note => "note",
41            Self::Entity => "entity",
42            Self::Event => "event",
43        }
44    }
45
46    /// Construct a `SubstrateKind` from its `u8` discriminant, or `None` if out of range.
47    #[inline]
48    pub const fn from_u8(v: u8) -> Option<Self> {
49        match v {
50            0 => Some(Self::Note),
51            1 => Some(Self::Entity),
52            2 => Some(Self::Event),
53            _ => None,
54        }
55    }
56}
57
58impl fmt::Display for SubstrateKind {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        f.write_str(self.name())
61    }
62}
63
64const SUBSTRATE_KIND_VALID: &[&str] = &["note", "entity", "event"];
65
66impl FromStr for SubstrateKind {
67    type Err = crate::error::UnknownVariant;
68
69    fn from_str(s: &str) -> Result<Self, Self::Err> {
70        match s {
71            "note" | "Note" => Ok(Self::Note),
72            "entity" | "Entity" => Ok(Self::Entity),
73            "event" | "Event" => Ok(Self::Event),
74            other => Err(crate::error::UnknownVariant::new(
75                "substrate_kind",
76                other,
77                SUBSTRATE_KIND_VALID,
78            )),
79        }
80    }
81}
82
83#[cfg(test)]
84#[path = "substrate_tests.rs"]
85mod tests;