Skip to main content

iroh_http_core/
error.rs

1//! Structured error types shared across the crate and the FFI boundary.
2//!
3//! [`CoreError`] pairs a machine-readable [`ErrorCode`] with human-readable
4//! detail. Platform adapters match on the code directly — no string parsing.
5
6/// Machine-readable error codes for the FFI boundary.
7///
8/// Platform adapters match on this directly — no string parsing needed.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10#[non_exhaustive]
11pub enum ErrorCode {
12    InvalidInput,
13    ConnectionFailed,
14    Timeout,
15    BodyTooLarge,
16    HeaderTooLarge,
17    PeerRejected,
18    Cancelled,
19    Internal,
20}
21
22/// Structured error returned by core functions.
23///
24/// `code` is machine-readable. `message` carries human-readable detail.
25#[derive(Debug, Clone, thiserror::Error)]
26#[error("{code:?}: {message}")]
27pub struct CoreError {
28    pub code: ErrorCode,
29    pub message: String,
30}
31
32impl CoreError {
33    pub fn invalid_input(detail: impl std::fmt::Display) -> Self {
34        CoreError {
35            code: ErrorCode::InvalidInput,
36            message: detail.to_string(),
37        }
38    }
39    pub fn connection_failed(detail: impl std::fmt::Display) -> Self {
40        CoreError {
41            code: ErrorCode::ConnectionFailed,
42            message: detail.to_string(),
43        }
44    }
45    pub fn timeout(detail: impl std::fmt::Display) -> Self {
46        CoreError {
47            code: ErrorCode::Timeout,
48            message: detail.to_string(),
49        }
50    }
51    pub fn body_too_large(detail: impl std::fmt::Display) -> Self {
52        CoreError {
53            code: ErrorCode::BodyTooLarge,
54            message: detail.to_string(),
55        }
56    }
57    pub fn header_too_large(detail: impl std::fmt::Display) -> Self {
58        CoreError {
59            code: ErrorCode::HeaderTooLarge,
60            message: detail.to_string(),
61        }
62    }
63    pub fn peer_rejected(detail: impl std::fmt::Display) -> Self {
64        CoreError {
65            code: ErrorCode::PeerRejected,
66            message: detail.to_string(),
67        }
68    }
69    pub fn internal(detail: impl std::fmt::Display) -> Self {
70        CoreError {
71            code: ErrorCode::Internal,
72            message: detail.to_string(),
73        }
74    }
75    pub fn invalid_handle(handle: u64) -> Self {
76        CoreError {
77            code: ErrorCode::InvalidInput,
78            message: format!("unknown handle: {handle}"),
79        }
80    }
81    pub fn cancelled() -> Self {
82        CoreError {
83            code: ErrorCode::Cancelled,
84            message: "aborted".to_string(),
85        }
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92
93    #[test]
94    fn core_error_display() {
95        let e = CoreError::timeout("30s elapsed");
96        assert!(e.to_string().contains("Timeout"));
97        assert!(e.to_string().contains("30s elapsed"));
98    }
99}