Skip to main content

ssp2/
error.rs

1//! Decode errors carrying the SPEC-named error codes (SPEC.md §1.7, §10).
2
3use std::fmt;
4
5/// The closed set of error codes a conformant decoder may produce
6/// (SPEC.md §1.7: `sync.invalid_request` unless a code is named).
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum ErrorCode {
9    /// `sync.invalid_request` — envelope/framing/grammar/primitive violations.
10    InvalidRequest,
11    /// `sync.empty_commit` — `PUSH_COMMIT` with zero operations (§6.1).
12    EmptyCommit,
13}
14
15impl ErrorCode {
16    pub fn as_str(self) -> &'static str {
17        match self {
18            ErrorCode::InvalidRequest => "sync.invalid_request",
19            ErrorCode::EmptyCommit => "sync.empty_commit",
20        }
21    }
22}
23
24/// A decode failure: the SPEC-named code plus a human-oriented detail.
25#[derive(Debug, Clone)]
26pub struct DecodeError {
27    pub code: ErrorCode,
28    pub detail: String,
29}
30
31impl DecodeError {
32    pub fn invalid(detail: impl Into<String>) -> Self {
33        DecodeError {
34            code: ErrorCode::InvalidRequest,
35            detail: detail.into(),
36        }
37    }
38
39    pub fn empty_commit(detail: impl Into<String>) -> Self {
40        DecodeError {
41            code: ErrorCode::EmptyCommit,
42            detail: detail.into(),
43        }
44    }
45}
46
47impl fmt::Display for DecodeError {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(f, "{}: {}", self.code.as_str(), self.detail)
50    }
51}
52
53impl std::error::Error for DecodeError {}
54
55pub type Result<T> = std::result::Result<T, DecodeError>;