metrale_grammar/schema/
error.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//
3// Error type for the JSON-schema -> EBNF converter — port of the
4// internal `SchemaError` / `SchemaErrorType` from
5// `cpp/json_schema_converter.cc`.
6//
7// The C++ converter aborts the process (`XGRAMMAR_LOG(FATAL)`) on a
8// malformed schema; here we return `Err(SchemaError)` — no panics.
9
10use std::fmt;
11
12/// Classification of a schema-conversion failure, mirroring the C++
13/// `SchemaErrorType` enum.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum SchemaErrorKind {
16    /// The schema document is structurally invalid (wrong JSON type
17    /// for a keyword, non-string `type`, unparsable JSON, ...).
18    InvalidSchema,
19    /// The schema is well-formed but cannot accept any value (e.g.
20    /// `false`, `minItems > maxItems`).
21    UnsatisfiableSchema,
22    /// A `$ref` could not be resolved or a regex/sub-conversion
23    /// failed. (`InvalidSchema` is reused in C++; we keep a dedicated
24    /// variant to make ref failures easy to spot.)
25    RefResolution,
26}
27
28/// An error raised while converting a JSON Schema document into an
29/// EBNF grammar string.
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct SchemaError {
32    /// The category of the failure.
33    pub kind: SchemaErrorKind,
34    /// Human-readable description.
35    pub message: String,
36}
37
38impl SchemaError {
39    /// Construct an `InvalidSchema` error.
40    pub fn invalid(message: impl Into<String>) -> Self {
41        SchemaError {
42            kind: SchemaErrorKind::InvalidSchema,
43            message: message.into(),
44        }
45    }
46
47    /// Construct an `UnsatisfiableSchema` error.
48    pub fn unsatisfiable(message: impl Into<String>) -> Self {
49        SchemaError {
50            kind: SchemaErrorKind::UnsatisfiableSchema,
51            message: message.into(),
52        }
53    }
54
55    /// Construct a `RefResolution` error.
56    pub fn ref_error(message: impl Into<String>) -> Self {
57        SchemaError {
58            kind: SchemaErrorKind::RefResolution,
59            message: message.into(),
60        }
61    }
62}
63
64impl fmt::Display for SchemaError {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        let tag = match self.kind {
67            SchemaErrorKind::InvalidSchema => "invalid schema",
68            SchemaErrorKind::UnsatisfiableSchema => "unsatisfiable schema",
69            SchemaErrorKind::RefResolution => "ref resolution",
70        };
71        write!(f, "{tag}: {}", self.message)
72    }
73}
74
75impl std::error::Error for SchemaError {}
76
77/// Convenience alias for converter results.
78pub type SchemaResult<T> = Result<T, SchemaError>;