Skip to main content

qubit_value/value_wire/
value_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
9//! Errors produced while constructing a V1 wire DTO.
10
11#[cfg(feature = "json")]
12use qubit_budget::BudgetError;
13#[cfg(feature = "json")]
14use qubit_budget::MeasuredBudgetError;
15#[cfg(feature = "json")]
16use qubit_budget::QuantityConversionError;
17#[cfg(feature = "json")]
18use qubit_budget::json::JsonResource;
19use qubit_datatype::DataType;
20#[cfg(feature = "json")]
21use qubit_json::decode::JsonSyntaxError;
22#[cfg(feature = "json")]
23use qubit_json::encode::JsonEncodeError;
24#[cfg(feature = "json")]
25use qubit_json::encode::JsonEncodeErrorSource;
26#[cfg(feature = "json")]
27use qubit_json::encode::JsonSerializationError;
28use thiserror::Error;
29
30/// A runtime value cannot be represented by the JSON V1 wire contract.
31///
32/// # Examples
33///
34/// ```
35/// use qubit_value::{Value, ValueWireEncodeError, ValueWireV1};
36///
37/// let error = ValueWireV1::try_from(Value::Float64(f64::NAN)).unwrap_err();
38/// assert!(matches!(error, ValueWireEncodeError::NonFiniteFloat { .. }));
39/// ```
40#[non_exhaustive]
41#[must_use]
42#[derive(Debug, Error)]
43pub enum ValueWireEncodeError {
44    /// A JSON V1 float must be finite.
45    #[error("V1 JSON wire cannot represent a non-finite {data_type} value")]
46    NonFiniteFloat {
47        /// Runtime data type of the rejected value.
48        data_type: DataType,
49    },
50    /// A V1 decimal exponent must stay within the bounded wire range.
51    #[error("V1 JSON wire cannot represent decimal scale {scale}; maximum absolute scale is {maximum_absolute_scale}")]
52    BigDecimalScaleTooLarge {
53        /// Rejected decimal exponent.
54        scale: i64,
55        /// Inclusive exponent magnitude limit for V1.
56        maximum_absolute_scale: i64,
57    },
58    /// The JSON output exceeded one configured resource budget.
59    #[cfg(feature = "json")]
60    #[error("V1 JSON wire resource budget exceeded: {0}")]
61    Budget(
62        /// Budget violation reported by the bounded JSON encoder.
63        #[source]
64        BudgetError<JsonResource, usize>,
65    ),
66    /// A native JSON measurement could not be represented by the budget
67    /// quantity type.
68    #[cfg(feature = "json")]
69    #[error("V1 JSON wire resource quantity conversion failed for {resource:?}: {source}")]
70    Quantity {
71        /// Resource whose measurement failed.
72        resource: JsonResource,
73        /// Native measurement conversion failure.
74        #[source]
75        source: QuantityConversionError,
76    },
77    /// The encoded value contains invalid JSON syntax.
78    #[cfg(feature = "json")]
79    #[error("invalid V1 JSON wire syntax: {0}")]
80    Syntax(
81        /// Syntax error found in an embedded raw JSON payload.
82        #[source]
83        JsonSyntaxError,
84    ),
85    /// Strict JSON serialization rejected the value during bounded encoding.
86    #[cfg(feature = "json")]
87    #[error("failed to encode V1 JSON wire value: {0}")]
88    Json(
89        /// Stable, privacy-safe JSON serialization failure.
90        #[source]
91        JsonSerializationError,
92    ),
93    /// The destination writer rejected bounded JSON output.
94    #[cfg(feature = "json")]
95    #[error("failed to write V1 JSON wire value: {0}")]
96    Io(
97        /// Destination-writer failure.
98        #[source]
99        std::io::Error,
100    ),
101}
102
103#[cfg(feature = "json")]
104impl From<JsonEncodeError<JsonResource, usize>> for ValueWireEncodeError {
105    #[inline]
106    fn from(error: JsonEncodeError<JsonResource>) -> Self {
107        match error.into_source() {
108            JsonEncodeErrorSource::Budget(source) => match source {
109                MeasuredBudgetError::Budget(error) => Self::Budget(error),
110                MeasuredBudgetError::Quantity { resource, source } => Self::Quantity { resource, source },
111            },
112            JsonEncodeErrorSource::InvalidRawJson(source) => Self::Syntax(source),
113            JsonEncodeErrorSource::Serialize(source) => Self::Json(source),
114            JsonEncodeErrorSource::Write(source) => Self::Io(source),
115        }
116    }
117}
118
119#[cfg(feature = "json")]
120impl From<MeasuredBudgetError<JsonResource, usize>> for ValueWireEncodeError {
121    #[inline]
122    fn from(error: MeasuredBudgetError<JsonResource, usize>) -> Self {
123        match error {
124            MeasuredBudgetError::Budget(error) => Self::Budget(error),
125            MeasuredBudgetError::Quantity { resource, source } => Self::Quantity { resource, source },
126        }
127    }
128}