Skip to main content

concinnity_core/
result.rs

1//! The engine's flat result code, shared by every crate that reports a
2//! recoverable failure across an API or FFI seam.
3
4use thiserror::Error;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
7#[non_exhaustive]
8/// The engine's flat result code, returned across the API and FFI seams.
9pub enum CnResult {
10    #[error("Success")]
11    /// The call succeeded.
12    Success = 0,
13
14    #[error("Invalid asset type")]
15    /// The asset type name is not in the registry.
16    AssetInvalidType,
17
18    /// Generic
19    #[error("Invalid state")]
20    InvalidState,
21    #[error("Invalid argument")]
22    /// An argument was outside its accepted range.
23    InvalidArgument,
24
25    #[error("File I/O error")]
26    /// A file could not be read or written.
27    FileIo,
28
29    #[error("No state directory installed")]
30    /// Project state was read before any host anchored the state tree. See
31    /// `concinnity_host::store::paths::set_state_dir`.
32    NoStateRoot,
33}
34
35// Baking a component into its blob record serializes it with postcard.
36impl From<postcard::Error> for CnResult {
37    fn from(e: postcard::Error) -> Self {
38        tracing::error!("postcard error: {}", e);
39        CnResult::InvalidArgument
40    }
41}
42
43// Reading one back reads a length-delimited frame; a failure means the record
44// and the component schema disagree (a stale blob survives the version check
45// instead of reaching here).
46impl From<crate::blob::FrameError> for CnResult {
47    fn from(e: crate::blob::FrameError) -> Self {
48        tracing::error!("baked record did not decode: {}", e);
49        CnResult::InvalidArgument
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56    use alloc::string::{String, ToString};
57
58    #[test]
59    fn display_messages_are_stable() {
60        assert_eq!(CnResult::Success.to_string(), "Success");
61        assert_eq!(CnResult::AssetInvalidType.to_string(), "Invalid asset type");
62        assert_eq!(CnResult::InvalidState.to_string(), "Invalid state");
63        assert_eq!(CnResult::InvalidArgument.to_string(), "Invalid argument");
64        assert_eq!(CnResult::FileIo.to_string(), "File I/O error");
65        assert_eq!(
66            CnResult::NoStateRoot.to_string(),
67            "No state directory installed"
68        );
69    }
70
71    #[test]
72    fn frame_errors_map_to_invalid_argument() {
73        let bad = crate::blob::decode_exact::<String>(&[0xff]).unwrap_err();
74        assert_eq!(CnResult::from(bad), CnResult::InvalidArgument);
75
76        let trailing = crate::blob::decode_exact::<u8>(&[1, 2]).unwrap_err();
77        assert_eq!(CnResult::from(trailing), CnResult::InvalidArgument);
78    }
79}