Skip to main content

weavatrix_clone/
error.rs

1use std::{error::Error, fmt};
2
3pub type Result<T> = std::result::Result<T, CloneError>;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum CloneError {
7    InvalidConfig {
8        field: &'static str,
9        reason: &'static str,
10    },
11    InvalidFragment {
12        id: String,
13        reason: &'static str,
14    },
15    DuplicateFragment(String),
16    CapacityExceeded {
17        resource: &'static str,
18        limit: usize,
19    },
20    InvalidOutput(String),
21    AccuracyGate {
22        metric: &'static str,
23        actual: u16,
24        required: u16,
25    },
26    Repository(String),
27}
28
29impl fmt::Display for CloneError {
30    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
31        match self {
32            Self::InvalidConfig { field, reason } => {
33                write!(formatter, "invalid clone config {field}: {reason}")
34            }
35            Self::InvalidFragment { id, reason } => {
36                write!(formatter, "invalid fragment {id}: {reason}")
37            }
38            Self::DuplicateFragment(id) => write!(formatter, "duplicate fragment id: {id}"),
39            Self::CapacityExceeded { resource, limit } => {
40                write!(formatter, "{resource} exceeds configured limit {limit}")
41            }
42            Self::InvalidOutput(message) => write!(formatter, "invalid output: {message}"),
43            Self::AccuracyGate {
44                metric,
45                actual,
46                required,
47            } => write!(
48                formatter,
49                "accuracy gate failed for {metric}: {actual} permille is below {required}"
50            ),
51            Self::Repository(message) => write!(formatter, "repository scan failed: {message}"),
52        }
53    }
54}
55
56impl Error for CloneError {}
57
58#[cfg(test)]
59mod tests {
60    use super::CloneError;
61
62    #[test]
63    fn formats_every_error_variant() {
64        let errors = [
65            CloneError::InvalidConfig {
66                field: "limit",
67                reason: "zero",
68            },
69            CloneError::InvalidFragment {
70                id: "fragment".to_owned(),
71                reason: "empty",
72            },
73            CloneError::DuplicateFragment("fragment".to_owned()),
74            CloneError::CapacityExceeded {
75                resource: "tokens",
76                limit: 1,
77            },
78            CloneError::InvalidOutput("path".to_owned()),
79            CloneError::AccuracyGate {
80                metric: "recall",
81                actual: 800,
82                required: 900,
83            },
84            CloneError::Repository("incomplete".to_owned()),
85        ];
86        for error in errors {
87            assert!(!error.to_string().is_empty());
88            let as_error: &dyn std::error::Error = &error;
89            assert!(as_error.source().is_none());
90        }
91    }
92}