appcore_contracts/error.rs
1//! Errors returned while constructing or decoding contracts.
2
3use std::fmt::{Display, Formatter};
4
5/// Result type used by AppCore contracts.
6pub type ContractResult<T> = Result<T, ContractError>;
7
8/// Validation error for a versioned contract.
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum ContractError {
11 /// A required value was empty.
12 Empty {
13 /// Name of the invalid field.
14 field: &'static str,
15 },
16 /// A value exceeded its documented maximum length.
17 TooLong {
18 /// Name of the invalid field.
19 field: &'static str,
20 /// Maximum accepted UTF-8 byte length.
21 max_bytes: usize,
22 },
23 /// An identifier contains unsupported characters or delimiters.
24 InvalidIdentifier {
25 /// Name of the invalid identifier field.
26 field: &'static str,
27 },
28 /// A field combination is not valid.
29 InvalidValue {
30 /// Name of the invalid field.
31 field: &'static str,
32 /// Stable, non-sensitive validation reason.
33 reason: &'static str,
34 },
35 /// A collection contains the same logical key more than once.
36 Duplicate {
37 /// Name of the collection field.
38 field: &'static str,
39 /// Repeated non-sensitive identifier.
40 value: String,
41 },
42 /// A manifest attempted to store a secret instead of a secret reference.
43 SecretValue {
44 /// Field that must be replaced by a secret reference.
45 field: String,
46 },
47 /// An application manifest attempted to store an installation-local path.
48 LocalPath {
49 /// Application-owned field that attempted to carry a path.
50 field: String,
51 },
52}
53
54impl Display for ContractError {
55 fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
56 match self {
57 Self::Empty { field } => write!(formatter, "{field} must not be empty"),
58 Self::TooLong { field, max_bytes } => {
59 write!(formatter, "{field} must not exceed {max_bytes} bytes")
60 }
61 Self::InvalidIdentifier { field } => {
62 write!(formatter, "{field} is not a valid distributed identifier")
63 }
64 Self::InvalidValue { field, reason } => write!(formatter, "{field}: {reason}"),
65 Self::Duplicate { field, value } => write!(formatter, "duplicate {field}: {value}"),
66 Self::SecretValue { field } => {
67 write!(formatter, "{field} must use a secret reference")
68 }
69 Self::LocalPath { field } => {
70 write!(formatter, "{field} must be declared by the deployment")
71 }
72 }
73 }
74}
75
76impl std::error::Error for ContractError {}