Skip to main content

harmos_domain/
refusal.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12/* === Re-Exports === */
13
14/* === Imports === */
15
16// Standard Library Imports
17use std::fmt;
18// Third Party Imports
19use serde::{Deserialize, Serialize};
20
21// Local Imports
22use crate::failure::{Failure, Origin};
23use crate::operations;
24
25/* === Constants === */
26
27pub const RESERVED: &str = "harmos.";
28
29pub const FAILED: i64 = -32_000;
30
31pub const UNKNOWN: i64 = -32_601;
32
33pub const UNREADABLE: i64 = -32_602;
34
35/* === Macros === */
36
37/* === Type Aliases === */
38
39/* === Structs === */
40
41// A host or carrier refusal: the JSON-RPC code beside the failure it carries.
42#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
43#[serde(deny_unknown_fields)]
44pub struct Refusal {
45    code: i64,
46    failure: Failure,
47}
48
49/* === Enums === */
50
51/* === Traits === */
52
53/* === Implementations === */
54
55impl Refusal {
56    pub fn new(code: i64, message: impl fmt::Display) -> Self {
57        let failure = Failure::new(operations::FailureKind::Permanent, message.to_string());
58        Self::failed(code, failure)
59    }
60
61    pub fn of(cause: impl fmt::Display) -> Self {
62        Self::new(FAILED, cause)
63    }
64
65    pub fn failed(code: i64, failure: Failure) -> Self {
66        Self { code, failure }
67    }
68
69    // Refuses with the failure an error chain carries, or writes its cause.
70    pub fn originate(
71        code: i64, classification: operations::FailureKind, error: &(dyn std::error::Error + 'static), origin: Origin,
72    ) -> Self {
73        Self::failed(code, Failure::originate(classification, error, origin))
74    }
75
76    pub fn code(&self) -> i64 {
77        self.code
78    }
79
80    pub fn message(&self) -> &str {
81        self.failure.cause()
82    }
83
84    pub fn failure(&self) -> &Failure {
85        &self.failure
86    }
87
88    pub fn into_failure(self) -> Failure {
89        self.failure
90    }
91}
92
93impl fmt::Display for Refusal {
94    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
95        // A Refusal Is A Leaf: It Names The Operation Frame Beside Its Cause
96        match self.failure.context().operation() {
97            Some(operation) => write!(formatter, "operation `{operation}` failed: {} ({})", self.failure.cause(), self.code),
98            None => write!(formatter, "{} ({})", self.failure.cause(), self.code),
99        }
100    }
101}
102
103impl std::error::Error for Refusal {}
104
105/* === Public Functions === */
106
107pub const fn reserved(method: &str) -> bool {
108    let bytes = method.as_bytes();
109    bytes.len() >= 7
110        && bytes[0] == b'h'
111        && bytes[1] == b'a'
112        && bytes[2] == b'r'
113        && bytes[3] == b'm'
114        && bytes[4] == b'o'
115        && bytes[5] == b's'
116        && (bytes[6] == b'.' || bytes[6] == b'_')
117}
118
119/* === Private Functions === */
120
121/* === Tests === */