Skip to main content

bitcoin_consensus_encoding/
serde_as_consensus.rs

1// SPDX-License-Identifier: CC0-1.0
2
3// Methods are an implementation of a standardized serde-specific signature.
4#![allow(missing_docs)]
5#![allow(clippy::missing_errors_doc)]
6
7//! `serde` serialize and deserialize types using consensus encoding.
8//!
9//! Use with `#[serde(with = "bitcoin_consensus_encoding::serde_as_consensus")]`.
10//!
11//! This module works with any type `T` that implements both [`Encode`] and [`Decode`].
12//! In human-readable formats (like JSON), the value is serialized as a hex string.
13//! In non-human-readable formats (like bincode), raw bytes are used.
14
15use core::fmt;
16use core::marker::PhantomData;
17
18use hex::DisplayHex as _;
19use serde::{de, Deserializer, Serializer};
20
21use crate::{Decode, Encode, Encoder as _};
22
23/// Serializes a type as a consensus-encoded hex string.
24///
25/// # Type Parameters
26///
27/// * `T` - The type to serialize, must implement [`Encode`] and [`Decode`]
28/// * `S` - The serializer type
29pub fn serialize<T, S>(value: &T, s: S) -> Result<S::Ok, S::Error>
30where
31    T: Encode + Decode,
32    S: Serializer,
33{
34    if s.is_human_readable() {
35        struct ConsensusHex<'a, T>(&'a T);
36
37        impl<T: Encode> fmt::Display for ConsensusHex<'_, T> {
38            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39                let mut encoder = self.0.encoder();
40                loop {
41                    fmt::Display::fmt(&encoder.current_chunk().as_hex(), f)?;
42                    if encoder.advance().has_finished() {
43                        return Ok(());
44                    }
45                }
46            }
47        }
48
49        s.collect_str(&ConsensusHex(value))
50    } else {
51        // For non-human-readable formats, serialize as bytes.
52        let bytes = crate::encode_to_vec(value);
53        s.serialize_bytes(&bytes)
54    }
55}
56
57/// Deserializes a type from a consensus-encoded hex string.
58///
59/// # Type Parameters
60///
61/// * `T` - The type to deserialize, must implement [`Encode`] and [`Decode`]
62/// * `D` - The deserializer type
63pub fn deserialize<'d, T, D>(d: D) -> Result<T, D::Error>
64where
65    T: Encode + Decode,
66    D: Deserializer<'d>,
67{
68    if d.is_human_readable() {
69        use alloc::string::String;
70
71        use serde::Deserialize;
72
73        let hex_str = String::deserialize(d)?;
74        crate::decode_from_hex(&hex_str)
75            .map_err(|_| de::Error::custom("failed to decode hex string"))
76    } else {
77        // For non-human-readable formats, deserialize from bytes
78        struct BytesVisitor<T>(PhantomData<T>);
79
80        impl<'de, T> serde::de::Visitor<'de> for BytesVisitor<T>
81        where
82            T: Encode + Decode,
83        {
84            type Value = T;
85
86            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
87                formatter.write_str("a byte array")
88            }
89
90            fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
91            where
92                E: serde::de::Error,
93            {
94                crate::decode_from_slice(v)
95                    .map_err(|_| serde::de::Error::custom("failed to decode from bytes"))
96            }
97
98            fn visit_byte_buf<E>(self, v: alloc::vec::Vec<u8>) -> Result<Self::Value, E>
99            where
100                E: serde::de::Error,
101            {
102                crate::decode_from_slice(&v)
103                    .map_err(|_| serde::de::Error::custom("failed to decode from bytes"))
104            }
105        }
106
107        d.deserialize_bytes(BytesVisitor(PhantomData))
108    }
109}
110
111pub mod opt {
112    //! `serde` serialize and deserialize `Option<T>`.
113    //!
114    //! Note: This module does not produce consensus-encoded options (i.e., with a length prefix
115    //! of 0 or 1), it defers to the data format's serialization.
116    //!
117    //! This module is designed for serializing and deserializing objects that implement
118    //! `Encode`/`Decode` when wrapped in an `Option`. Use with
119    //! `#[serde(with = "bitcoin_consensus_encoding::serde_as_consensus::opt")]`.
120    //!
121    //! # Examples
122    //!
123    //! ```
124    //! # use bitcoin_consensus_encoding::{Encode, Decode, ArrayEncoder, ArrayDecoder, Decoder, DecoderStatus};
125    //! # #[derive(Debug, PartialEq)]
126    //! # struct MyType([u8; 4]);
127    //! # impl Encode for MyType {
128    //! #     type Encoder<'e> = ArrayEncoder<4>;
129    //! #     fn encoder(&self) -> Self::Encoder<'_> { ArrayEncoder::without_length_prefix(self.0) }
130    //! # }
131    //! # struct MyTypeDecoder(ArrayDecoder<4>);
132    //! # impl Default for MyTypeDecoder {
133    //! #     fn default() -> Self { MyTypeDecoder(ArrayDecoder::new()) }
134    //! # }
135    //! # impl Decoder for MyTypeDecoder {
136    //! #     type Output = MyType;
137    //! #     type Error = bitcoin_consensus_encoding::UnexpectedEofError;
138    //! #     fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<DecoderStatus, Self::Error> { self.0.push_bytes(bytes) }
139    //! #     fn end(self) -> Result<Self::Output, Self::Error> { self.0.end().map(MyType) }
140    //! #     fn read_limit(&self) -> usize { self.0.read_limit() }
141    //! # }
142    //! # impl Decode for MyType {
143    //! #     type Decoder = MyTypeDecoder;
144    //! # }
145    //! use serde::{Deserialize, Serialize};
146    //!
147    //! #[derive(Serialize, Deserialize)]
148    //! struct MyStruct {
149    //!     #[serde(with = "bitcoin_consensus_encoding::serde_as_consensus::opt")]
150    //!     field: Option<MyType>,
151    //! }
152    //! ```
153
154    use core::fmt;
155    use core::marker::PhantomData;
156
157    use serde::{de, Deserializer, Serializer};
158
159    use crate::{Decode, Encode};
160
161    #[allow(clippy::ref_option)] // API forced by serde.
162    pub fn serialize<T, S>(t: &Option<T>, s: S) -> Result<S::Ok, S::Error>
163    where
164        T: Encode + Decode,
165        S: Serializer,
166    {
167        struct AsConsensus<'a, T>(&'a T);
168
169        impl<T: Encode + Decode> serde::Serialize for AsConsensus<'_, T> {
170            fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
171                super::serialize(self.0, s)
172            }
173        }
174
175        match *t {
176            Some(ref t) => s.serialize_some(&AsConsensus(t)),
177            None => s.serialize_none(),
178        }
179    }
180
181    pub fn deserialize<'d, T, D>(d: D) -> Result<Option<T>, D::Error>
182    where
183        T: Encode + Decode,
184        D: Deserializer<'d>,
185    {
186        struct OptVisitor<X>(PhantomData<X>);
187
188        impl<'de, X> de::Visitor<'de> for OptVisitor<X>
189        where
190            X: Encode + Decode,
191        {
192            type Value = Option<X>;
193
194            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
195                write!(formatter, "an Option<T> where T: encoding::Decode")
196            }
197
198            fn visit_none<E>(self) -> Result<Self::Value, E>
199            where
200                E: de::Error,
201            {
202                Ok(None)
203            }
204
205            fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
206            where
207                D: Deserializer<'de>,
208            {
209                Ok(Some(super::deserialize(d)?))
210            }
211        }
212        d.deserialize_option(OptVisitor::<T>(PhantomData))
213    }
214}
215
216pub mod vec {
217    //! `serde` serialize and deserialize `Vec<T>`.
218    //!
219    //! Note: This module does not produce consensus-encoded vectors (i.e., with a length prefix),
220    //! it defers to the data format's vector serialization.
221    //!
222    //! It is designed for serializing and deserializing objects that implement `Encode`/`Decode`
223    //! when wrapped in a `Vec`. Use with
224    //! `#[serde(with = "bitcoin_consensus_encoding::serde_as_consensus::vec")]`.
225    //!
226    //! # Examples
227    //!
228    //! ```
229    //! # use bitcoin_consensus_encoding::{Encode, Decode, ArrayEncoder, ArrayDecoder, Decoder, DecoderStatus};
230    //! # #[derive(Debug, PartialEq)]
231    //! # struct MyType([u8; 2]);
232    //! # impl Encode for MyType {
233    //! #     type Encoder<'e> = ArrayEncoder<2>;
234    //! #     fn encoder(&self) -> Self::Encoder<'_> { ArrayEncoder::without_length_prefix(self.0) }
235    //! # }
236    //! # struct MyTypeDecoder(ArrayDecoder<2>);
237    //! # impl Default for MyTypeDecoder {
238    //! #     fn default() -> Self { MyTypeDecoder(ArrayDecoder::new()) }
239    //! # }
240    //! # impl Decoder for MyTypeDecoder {
241    //! #     type Output = MyType;
242    //! #     type Error = bitcoin_consensus_encoding::UnexpectedEofError;
243    //! #     fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<DecoderStatus, Self::Error> { self.0.push_bytes(bytes) }
244    //! #     fn end(self) -> Result<Self::Output, Self::Error> { self.0.end().map(MyType) }
245    //! #     fn read_limit(&self) -> usize { self.0.read_limit() }
246    //! # }
247    //! # impl Decode for MyType {
248    //! #     type Decoder = MyTypeDecoder;
249    //! # }
250    //! use serde::{Deserialize, Serialize};
251    //!
252    //! #[derive(Serialize, Deserialize)]
253    //! struct MyStruct {
254    //!     #[serde(with = "bitcoin_consensus_encoding::serde_as_consensus::vec")]
255    //!     items: Vec<MyType>,
256    //! }
257    //! ```
258
259    use alloc::vec::Vec;
260    use core::fmt;
261    use core::marker::PhantomData;
262
263    use serde::{de, Deserializer, Serializer};
264
265    use crate::{Decode, Encode};
266
267    pub fn serialize<T, S>(v: &[T], s: S) -> Result<S::Ok, S::Error>
268    where
269        T: Encode + Decode,
270        S: Serializer,
271    {
272        struct AsConsensus<'a, T>(&'a T);
273
274        impl<T: Encode + Decode> serde::Serialize for AsConsensus<'_, T> {
275            fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
276                super::serialize(self.0, s)
277            }
278        }
279
280        s.collect_seq(v.iter().map(|item| AsConsensus(item)))
281    }
282
283    pub fn deserialize<'d, T, D>(d: D) -> Result<Vec<T>, D::Error>
284    where
285        T: Encode + Decode,
286        D: Deserializer<'d>,
287    {
288        struct VecVisitor<X>(PhantomData<X>);
289
290        impl<'de, X> de::Visitor<'de> for VecVisitor<X>
291        where
292            X: Encode + Decode,
293        {
294            type Value = Vec<X>;
295
296            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
297                write!(formatter, "a sequence of consensus-encodable items")
298            }
299
300            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
301            where
302                A: de::SeqAccess<'de>,
303            {
304                struct Wrap<X>(X);
305
306                impl<'de, X> de::Deserialize<'de> for Wrap<X>
307                where
308                    X: Encode + Decode,
309                {
310                    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
311                        super::deserialize::<X, D>(d).map(Wrap)
312                    }
313                }
314
315                let mut out = Vec::new();
316                while let Some(Wrap(item)) = seq.next_element::<Wrap<X>>()? {
317                    out.push(item);
318                }
319                Ok(out)
320            }
321        }
322
323        d.deserialize_seq(VecVisitor::<T>(PhantomData))
324    }
325}