Skip to main content

aion_package/
error.rs

1//! Error taxonomy for malformed `.aion` packages.
2
3/// Errors produced while validating or loading a `.aion` package.
4#[derive(thiserror::Error, Debug)]
5pub enum PackageError {
6    /// The archive could not be read as a ZIP container.
7    #[error("failed to read .aion ZIP archive: {0}")]
8    ArchiveRead(#[from] zip::result::ZipError),
9
10    /// The archive does not contain the required root manifest.
11    #[error("missing required manifest.json entry")]
12    MissingManifest,
13
14    /// A module uses a namespace owned by the engine's native NIF layer.
15    #[error(
16        "module `{module}` uses an engine-reserved namespace and must not ship as package bytecode"
17    )]
18    ReservedModuleName {
19        /// The offending logical module name.
20        module: String,
21    },
22
23    /// The archive could not be written as a ZIP container.
24    #[error("failed to write .aion ZIP archive: {0}")]
25    ArchiveWrite(zip::result::ZipError),
26
27    /// The archive target could not be written to the filesystem or memory buffer.
28    #[error("failed to write .aion archive bytes: {source}")]
29    ArchiveWriteIo {
30        /// I/O failure reported by the write target.
31        source: std::io::Error,
32    },
33
34    /// The manifest entry is present but is not valid manifest JSON.
35    #[error("failed to parse manifest.json: {source}")]
36    ManifestParse {
37        /// JSON parsing failure reported by `serde_json`.
38        source: serde_json::Error,
39    },
40
41    /// The manifest could not be serialised for writing into the archive.
42    #[error("failed to serialise manifest.json: {source}")]
43    ManifestSerialise {
44        /// JSON serialisation failure reported by `serde_json`.
45        source: serde_json::Error,
46    },
47
48    /// The manifest declares a format version this crate does not support.
49    #[error("unknown .aion format_version {found}")]
50    UnknownFormatVersion {
51        /// Unsupported format version found in the manifest.
52        found: u32,
53    },
54
55    /// The manifest entry module is not present in the beam set.
56    #[error("missing entry module `{module}` in beam set")]
57    MissingEntryModule {
58        /// Logical entry module named by the manifest.
59        module: String,
60    },
61
62    /// The manifest version does not match the hash recomputed from beams.
63    #[error("package integrity mismatch: expected version `{expected}`, computed `{computed}`")]
64    IntegrityMismatch {
65        /// Version claimed by the manifest.
66        expected: String,
67        /// Version recomputed from package beams.
68        computed: String,
69    },
70
71    /// A beam archive entry is malformed or ambiguous.
72    #[error("malformed beam entry `{entry}`")]
73    MalformedBeamEntry {
74        /// Archive entry or logical module name that failed validation.
75        entry: String,
76    },
77
78    /// The archive's entries inflate past the caller's extraction budget.
79    #[error(
80        "archive contents inflate past the extraction limit of {limit} bytes; refusing to extract further"
81    )]
82    InflatedSizeExceeded {
83        /// The caller-configured inflate ceiling in bytes.
84        limit: u64,
85    },
86}
87
88#[cfg(test)]
89mod tests {
90    use super::PackageError;
91
92    fn assert_send_sync<T: Send + Sync>() {}
93
94    #[test]
95    fn package_error_is_send_and_sync() {
96        assert_send_sync::<PackageError>();
97    }
98
99    #[test]
100    fn display_messages_name_the_failed_condition() {
101        assert_eq!(
102            PackageError::MissingManifest.to_string(),
103            "missing required manifest.json entry"
104        );
105        assert_eq!(
106            PackageError::ArchiveWriteIo {
107                source: std::io::Error::other("disk full"),
108            }
109            .to_string(),
110            "failed to write .aion archive bytes: disk full"
111        );
112        assert_eq!(
113            PackageError::UnknownFormatVersion { found: 99 }.to_string(),
114            "unknown .aion format_version 99"
115        );
116        assert_eq!(
117            PackageError::MissingEntryModule {
118                module: "workflow/main".to_owned(),
119            }
120            .to_string(),
121            "missing entry module `workflow/main` in beam set"
122        );
123        assert_eq!(
124            PackageError::IntegrityMismatch {
125                expected: "expected".to_owned(),
126                computed: "computed".to_owned(),
127            }
128            .to_string(),
129            "package integrity mismatch: expected version `expected`, computed `computed`"
130        );
131        assert_eq!(
132            PackageError::MalformedBeamEntry {
133                entry: "beam/workflow.beam".to_owned(),
134            }
135            .to_string(),
136            "malformed beam entry `beam/workflow.beam`"
137        );
138        assert_eq!(
139            PackageError::InflatedSizeExceeded { limit: 1024 }.to_string(),
140            "archive contents inflate past the extraction limit of 1024 bytes; refusing to extract further"
141        );
142    }
143}