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}