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}