1use coven_crypto::CryptoError;
4use coven_database::DbError;
5use coven_merge::MergeError;
6use std::{error::Error, fmt, sync::Arc};
7
8#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
11pub enum Refusal {
12 Decryption {
14 #[serde(skip)]
16 cause: Option<Arc<CryptoError>>,
17 },
18 Signature {
20 #[serde(skip)]
22 cause: Option<Arc<CryptoError>>,
23 },
24 Parse {
26 #[serde(skip)]
28 cause: Option<Arc<dyn Error + Send + Sync>>,
29 },
30 InvalidWrite {
32 #[serde(skip)]
34 cause: Option<Arc<DbError>>,
35 },
36 NotAuthorized,
38 InvalidCausality {
40 #[serde(skip)]
42 cause: Option<Arc<MergeError>>,
43 },
44 WrongIdentity {
46 #[serde(skip)]
48 cause: Option<Arc<dyn Error + Send + Sync>>,
49 },
50 ContentHash,
52}
53
54impl PartialEq for Refusal {
55 fn eq(&self, other: &Self) -> bool {
56 std::mem::discriminant(self) == std::mem::discriminant(other)
57 }
58}
59impl Eq for Refusal {}
60
61impl Error for Refusal {
62 fn source(&self) -> Option<&(dyn Error + 'static)> {
63 match self {
64 Self::Decryption { cause } | Self::Signature { cause } => {
65 cause.as_deref().map(|e| e as &dyn Error)
66 }
67 Self::Parse { cause } | Self::WrongIdentity { cause } => {
68 cause.as_deref().map(|e| e as &dyn Error)
69 }
70 Self::InvalidWrite { cause } => cause.as_deref().map(|e| e as &dyn Error),
71 Self::InvalidCausality { cause } => cause.as_deref().map(|e| e as &dyn Error),
72 Self::NotAuthorized | Self::ContentHash => None,
73 }
74 }
75}
76
77impl fmt::Display for Refusal {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 f.write_str(match self {
80 Self::Decryption { .. } => "decryption failed",
81 Self::Signature { .. } => "signature failed",
82 Self::Parse { .. } => "parse failed",
83 Self::InvalidWrite { .. } => "invalid write",
84 Self::NotAuthorized => "object is not authorized",
85 Self::InvalidCausality { .. } => "invalid causality",
86 Self::WrongIdentity { .. } => "wrong object identity",
87 Self::ContentHash => "file content hash differs",
88 })?;
89 if let Some(cause) = self.source() {
90 write!(f, ": {cause}")?;
91 }
92 Ok(())
93 }
94}
95
96impl From<coven_format::Error> for Refusal {
97 fn from(error: coven_format::Error) -> Self {
98 match error {
99 coven_format::Error::Merge(
100 error @ (MergeError::CausalTimestamp(_)
101 | MergeError::CausalClosure(_)
102 | MergeError::DuplicateTimestamp(_, _)),
103 ) => Self::InvalidCausality { cause: Some(Arc::new(error)) },
104 coven_format::Error::Merge(error @ MergeError::TimestampDevice(_)) => {
105 Self::WrongIdentity { cause: Some(Arc::new(error)) }
106 }
107 error @ coven_format::Error::Invalid {
108 rule: coven_format::error::Rule::TimestampDevice,
109 ..
110 } => Self::WrongIdentity { cause: Some(Arc::new(error)) },
111 error => Self::Parse { cause: Some(Arc::new(error)) },
112 }
113 }
114}
115
116#[cfg(test)]
117#[path = "refusal_tests.rs"]
118mod tests;