Skip to main content

qubit_codec/value/
json_string_value_codec.rs

1// =============================================================================
2//    Copyright (c) 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Bidirectional Serde JSON string codec for one owned value.
9
10use core::marker::PhantomData;
11
12use serde::Serialize;
13use serde::de::DeserializeOwned;
14
15use super::JsonStringValueDecoder;
16use super::JsonStringValueEncoder;
17use super::ValueDecoder;
18use super::ValueEncoder;
19
20/// Encodes and decodes one serializable value through UTF-8 JSON strings.
21///
22/// This type combines [`JsonStringValueEncoder`] and [`JsonStringValueDecoder`]
23/// for registry-backed or bidirectional call sites. It holds no state between
24/// calls, so it is `Copy` and `Default`, and encoding and decoding can share
25/// one value through [`ValueEncoder`] and [`ValueDecoder`].
26///
27/// # Type Parameters
28///
29/// - `T`: Value type serialized to a JSON string and recovered from it.
30///
31/// # Examples
32///
33/// ```
34/// use qubit_codec::JsonStringValueCodec;
35/// use qubit_codec::ValueDecoder;
36/// use qubit_codec::ValueEncoder;
37///
38/// let mut codec = JsonStringValueCodec::<String>::new();
39/// assert_eq!(codec.encode(&"hello".to_string()).unwrap(), r#""hello""#.to_string());
40/// assert_eq!(codec.decode(r#""hello""#).unwrap(), "hello");
41/// ```
42#[must_use]
43#[derive(Debug, Clone, Copy, Default)]
44pub struct JsonStringValueCodec<T> {
45    /// Associates the codec with `T` without retaining a value.
46    _marker: PhantomData<T>,
47}
48
49impl<T> JsonStringValueCodec<T> {
50    /// Creates a bidirectional JSON string codec for values of type `T`.
51    ///
52    /// # Returns
53    ///
54    /// Returns a stateless codec bound to values of type `T`.
55    #[inline]
56    pub const fn new() -> Self {
57        Self { _marker: PhantomData }
58    }
59}
60
61impl<T> ValueEncoder<T> for JsonStringValueCodec<T>
62where
63    T: Serialize,
64{
65    /// Serialization failure reported by Serde JSON.
66    type Error = serde_json::Error;
67    /// Newly allocated UTF-8 JSON string owned by the caller.
68    type Output = String;
69
70    /// Serializes `input` into a JSON string.
71    ///
72    /// The codec holds no state, so this delegates to a freshly created
73    /// [`JsonStringValueEncoder`] and `self` stays usable for further calls.
74    ///
75    /// # Parameters
76    ///
77    /// - `input`: Value to serialize as JSON.
78    ///
79    /// # Returns
80    ///
81    /// Returns the serialized JSON text as an owned UTF-8 string.
82    ///
83    /// # Errors
84    ///
85    /// Returns [`serde_json::Error`] when `input` cannot be serialized to
86    /// JSON, including when a custom `Serialize` implementation fails or when
87    /// the value contains a map key that is not a string.
88    #[inline]
89    fn encode(&mut self, input: &T) -> Result<Self::Output, Self::Error> {
90        JsonStringValueEncoder::<T>::new().encode(input)
91    }
92}
93
94impl<T> ValueDecoder<str> for JsonStringValueCodec<T>
95where
96    T: DeserializeOwned,
97{
98    /// JSON syntax or target-value deserialization failure.
99    type Error = serde_json::Error;
100    /// Owned value deserialized independently of the input string lifetime.
101    type Output = T;
102
103    /// Deserializes `input` from a JSON string.
104    ///
105    /// The codec holds no state, so this delegates to a freshly created
106    /// [`JsonStringValueDecoder`] and `self` stays usable for further calls.
107    ///
108    /// # Parameters
109    ///
110    /// - `input`: Complete JSON value to deserialize.
111    ///
112    /// # Returns
113    ///
114    /// Returns an owned `T` deserialized independently of `input`'s lifetime.
115    ///
116    /// # Errors
117    ///
118    /// Returns [`serde_json::Error`] when `input` is not valid JSON or when a
119    /// valid JSON document does not match the shape required by `T`.
120    #[inline]
121    fn decode(&mut self, input: &str) -> Result<Self::Output, Self::Error> {
122        JsonStringValueDecoder::<T>::new().decode(input)
123    }
124}