-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy patherror_coercion.rs
More file actions
75 lines (60 loc) · 2 KB
/
Copy patherror_coercion.rs
File metadata and controls
75 lines (60 loc) · 2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//! Automatic error type conversions with `?`.
//!
//! The `?` operator automatically converts between error types:
//! - `C` → `Report<C>`
//! - `C` → `Report<Dynamic>`
//! - `Report<C>` → `Report<Dynamic>`
//!
//! This lets you freely mix error types without manual conversions.
use std::fs;
use rootcause::prelude::*;
#[derive(Debug, Clone)]
enum ParseError {
InvalidFormat,
MissingField(String),
}
impl core::fmt::Display for ParseError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::InvalidFormat => write!(f, "Invalid format"),
Self::MissingField(field) => write!(f, "Missing required field: {field}"),
}
}
}
impl core::error::Error for ParseError {}
// Report<ParseError> accepts both ParseError and Report<ParseError>
fn parse_value(input: &str) -> Result<u32, Report<ParseError>> {
if input.is_empty() {
// Raw ParseError → ? converts to Report<ParseError>
Err(ParseError::InvalidFormat)?;
}
if !input.chars().all(|c| c.is_ascii_digit()) {
// Report<ParseError> → ? passes through
Err(report!(ParseError::InvalidFormat).attach(format!("Input: {input}")))?;
}
let value: u32 = input
.parse()
.context(ParseError::MissingField("value".to_string()))?;
Ok(value)
}
// Report (dynamic) accepts any error type
fn process_file(path: &str) -> Result<u32, Report> {
// io::Error → Report
let contents = fs::read_to_string(path).attach(format!("Path: {path}"))?;
// Report<ParseError> → Report
let value = parse_value(&contents)?;
Ok(value)
}
fn main() {
println!("Typed errors - Report<ParseError>:\n");
if let Err(report) = parse_value("") {
eprintln!("{report}\n");
}
if let Err(report) = parse_value("abc") {
eprintln!("{report}\n");
}
println!("Dynamic errors - mixing types:\n");
if let Err(report) = process_file("/nonexistent/config.txt") {
eprintln!("{report}");
}
}