Skip to main content

khive_types/
error.rs

1//! Unified error types for khive-types.
2//!
3//! All parse/validation errors from closed taxonomies (EntityKind, NoteKind,
4//! EdgeRelation, SubstrateKind) and ID parsing converge here.
5
6extern crate alloc;
7use alloc::string::String;
8use core::fmt;
9
10/// A variant string was not recognized in a closed taxonomy.
11///
12/// Carries the rejected input, the domain name, and the list of valid values
13/// so callers get actionable error messages without re-matching.
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct UnknownVariant {
16    pub domain: &'static str,
17    pub value: String,
18    pub valid: &'static [&'static str],
19}
20
21impl UnknownVariant {
22    pub fn new(
23        domain: &'static str,
24        value: impl Into<String>,
25        valid: &'static [&'static str],
26    ) -> Self {
27        Self {
28            domain,
29            value: value.into(),
30            valid,
31        }
32    }
33}
34
35impl fmt::Display for UnknownVariant {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        write!(
38            f,
39            "unknown {}: {:?}. Valid: {}",
40            self.domain,
41            self.value,
42            ValidList(self.valid),
43        )
44    }
45}
46
47#[cfg(feature = "std")]
48impl std::error::Error for UnknownVariant {}
49
50struct ValidList(&'static [&'static str]);
51
52impl fmt::Display for ValidList {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        for (i, v) in self.0.iter().enumerate() {
55            if i > 0 {
56                f.write_str(" | ")?;
57            }
58            f.write_str(v)?;
59        }
60        Ok(())
61    }
62}
63
64/// Unified error for all type-level validation in khive-types.
65#[derive(Clone, Debug, PartialEq, Eq)]
66pub enum TypeError {
67    Id(crate::id::ParseIdError),
68    Variant(UnknownVariant),
69}
70
71impl fmt::Display for TypeError {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        match self {
74            Self::Id(e) => write!(f, "id error: {e}"),
75            Self::Variant(e) => fmt::Display::fmt(e, f),
76        }
77    }
78}
79
80#[cfg(feature = "std")]
81impl std::error::Error for TypeError {
82    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
83        match self {
84            Self::Id(e) => Some(e),
85            Self::Variant(e) => Some(e),
86        }
87    }
88}
89
90impl From<crate::id::ParseIdError> for TypeError {
91    fn from(e: crate::id::ParseIdError) -> Self {
92        Self::Id(e)
93    }
94}
95
96impl From<UnknownVariant> for TypeError {
97    fn from(e: UnknownVariant) -> Self {
98        Self::Variant(e)
99    }
100}