Skip to main content

qubit_metadata/
metadata_wire_encode_error.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Errors from bounded JSON metadata wire encoding.
9
10use std::fmt;
11
12use qubit_budget::BudgetError;
13use qubit_budget::MeasuredBudgetError;
14use qubit_budget::QuantityConversionError;
15use qubit_budget::json::JsonResource;
16use qubit_json::decode::JsonSyntaxError;
17use qubit_json::encode::JsonEncodeError;
18use qubit_json::encode::JsonEncodeErrorSource;
19use qubit_json::encode::JsonSerializationError;
20
21/// Failure returned by bounded metadata JSON encoding APIs.
22///
23/// # Examples
24///
25/// ```
26/// use qubit_metadata::MetadataWireEncodeError;
27///
28/// let error = MetadataWireEncodeError::Io(std::io::Error::other("closed"));
29/// assert!(error.to_string().contains("closed"));
30/// ```
31#[derive(Debug)]
32#[non_exhaustive]
33#[must_use]
34pub enum MetadataWireEncodeError {
35    /// The JSON document exceeded one configured resource budget.
36    Budget(BudgetError<JsonResource, usize>),
37    /// A native JSON measurement could not be represented by the budget
38    /// quantity type.
39    Quantity {
40        /// Resource whose measurement failed to convert.
41        resource: JsonResource,
42        /// Native measurement conversion failure.
43        source: QuantityConversionError,
44    },
45    /// The encoded value contains invalid JSON syntax.
46    Syntax(JsonSyntaxError),
47    /// Strict JSON serialization rejected the value during bounded encoding.
48    Json(JsonSerializationError),
49    /// The destination writer rejected bounded JSON output.
50    Io(std::io::Error),
51}
52
53impl fmt::Display for MetadataWireEncodeError {
54    /// Formats the encoding failure with its underlying error context.
55    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
56        match self {
57            Self::Budget(error) => {
58                write!(formatter, "JSON resource budget exceeded: {error}")
59            }
60            Self::Quantity { resource, source } => write!(
61                formatter,
62                "JSON resource quantity conversion failed for {resource:?}: {source}",
63            ),
64            Self::Syntax(error) => {
65                write!(formatter, "invalid JSON wire syntax: {error}")
66            }
67            Self::Json(error) => {
68                write!(formatter, "failed to encode JSON wire value: {error}")
69            }
70            Self::Io(error) => {
71                write!(formatter, "failed to write JSON wire value: {error}")
72            }
73        }
74    }
75}
76
77impl std::error::Error for MetadataWireEncodeError {
78    /// Returns the underlying budget, syntax, JSON, or I/O error.
79    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
80        match self {
81            Self::Budget(error) => Some(error),
82            Self::Quantity { source, .. } => Some(source),
83            Self::Syntax(error) => Some(error),
84            Self::Json(error) => Some(error),
85            Self::Io(error) => Some(error),
86        }
87    }
88}
89
90impl From<JsonEncodeError<JsonResource>> for MetadataWireEncodeError {
91    /// Converts a shared budget adapter error into the metadata encoding
92    /// error.
93    fn from(error: JsonEncodeError<JsonResource>) -> Self {
94        match error.into_source() {
95            JsonEncodeErrorSource::Budget(source) => match source {
96                MeasuredBudgetError::Budget(error) => Self::Budget(error),
97                MeasuredBudgetError::Quantity { resource, source } => Self::Quantity { resource, source },
98            },
99            JsonEncodeErrorSource::InvalidRawJson(source) => Self::Syntax(source),
100            JsonEncodeErrorSource::Serialize(source) => Self::Json(source),
101            JsonEncodeErrorSource::Write(source) => Self::Io(source),
102        }
103    }
104}
105
106impl From<MeasuredBudgetError<JsonResource, usize>> for MetadataWireEncodeError {
107    fn from(error: MeasuredBudgetError<JsonResource, usize>) -> Self {
108        match error {
109            MeasuredBudgetError::Budget(error) => Self::Budget(error),
110            MeasuredBudgetError::Quantity { resource, source } => Self::Quantity { resource, source },
111        }
112    }
113}