Skip to main content

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 {}