Skip to content

Commit e2d03fe

Browse files
committed
units: Manually implement serde traits
For types that have private inner fields we would like to manually implement `serde` traits instead of deriving them. This hardens the crate against making future mistakes if we want to change the inner fields. Do so for: - `Weight` - `BlockTime` - `NumberOfBlocks` - `NumberOf512seconds`
1 parent fc373f3 commit e2d03fe

File tree

3 files changed

+93
-11
lines changed

3 files changed

+93
-11
lines changed

units/src/locktime/relative.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@ use core::fmt;
88
#[cfg(feature = "arbitrary")]
99
use arbitrary::{Arbitrary, Unstructured};
1010
#[cfg(feature = "serde")]
11-
use serde::{Deserialize, Serialize};
11+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
1212

1313
#[deprecated(since = "TBD", note = "use `NumberOfBlocks` instead")]
1414
#[doc(hidden)]
1515
pub type Height = NumberOfBlocks;
1616

1717
/// A relative lock time lock-by-blockheight value.
1818
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
19-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2019
pub struct NumberOfBlocks(u16);
2120

2221
impl NumberOfBlocks {
@@ -92,6 +91,28 @@ impl fmt::Display for NumberOfBlocks {
9291
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
9392
}
9493

94+
#[cfg(feature = "serde")]
95+
impl Serialize for NumberOfBlocks {
96+
#[inline]
97+
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
98+
where
99+
S: Serializer,
100+
{
101+
u16::serialize(&self.to_height(), s)
102+
}
103+
}
104+
105+
#[cfg(feature = "serde")]
106+
impl<'de> Deserialize<'de> for NumberOfBlocks {
107+
#[inline]
108+
fn deserialize<D>(d: D) -> Result<Self, D::Error>
109+
where
110+
D: Deserializer<'de>,
111+
{
112+
Ok(Self::from_height(u16::deserialize(d)?))
113+
}
114+
}
115+
95116
#[deprecated(since = "TBD", note = "use `NumberOf512Seconds` instead")]
96117
#[doc(hidden)]
97118
pub type Time = NumberOf512Seconds;
@@ -100,7 +121,6 @@ pub type Time = NumberOf512Seconds;
100121
///
101122
/// For BIP 68 relative lock-by-blocktime locks, time is measured in 512 second intervals.
102123
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
103-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
104124
pub struct NumberOf512Seconds(u16);
105125

106126
impl NumberOf512Seconds {
@@ -213,6 +233,28 @@ impl fmt::Display for NumberOf512Seconds {
213233
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
214234
}
215235

236+
#[cfg(feature = "serde")]
237+
impl Serialize for NumberOf512Seconds {
238+
#[inline]
239+
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
240+
where
241+
S: Serializer,
242+
{
243+
u16::serialize(&self.to_512_second_intervals(), s)
244+
}
245+
}
246+
247+
#[cfg(feature = "serde")]
248+
impl<'de> Deserialize<'de> for NumberOf512Seconds {
249+
#[inline]
250+
fn deserialize<D>(d: D) -> Result<Self, D::Error>
251+
where
252+
D: Deserializer<'de>,
253+
{
254+
Ok(Self::from_512_second_intervals(u16::deserialize(d)?))
255+
}
256+
}
257+
216258
/// Error returned when the input time in seconds was too large to be encoded to a 16 bit 512 second interval.
217259
#[derive(Debug, Clone, PartialEq, Eq)]
218260
pub struct TimeOverflowError {

units/src/time.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@
99
1010
#[cfg(feature = "arbitrary")]
1111
use arbitrary::{Arbitrary, Unstructured};
12+
#[cfg(feature = "serde")]
13+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
1214

1315
mod encapsulate {
14-
#[cfg(feature = "serde")]
15-
use serde::{Deserialize, Serialize};
16-
1716
/// A Bitcoin block timestamp.
1817
///
1918
/// > Each block contains a Unix time timestamp. In addition to serving as a source of variation for
@@ -27,7 +26,6 @@ mod encapsulate {
2726
///
2827
/// ref: <https://en.bitcoin.it/wiki/Block_timestamp>
2928
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
30-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3129
pub struct BlockTime(u32);
3230

3331
impl BlockTime {
@@ -53,6 +51,28 @@ impl From<BlockTime> for u32 {
5351
fn from(t: BlockTime) -> Self { t.to_u32() }
5452
}
5553

54+
#[cfg(feature = "serde")]
55+
impl Serialize for BlockTime {
56+
#[inline]
57+
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
58+
where
59+
S: Serializer,
60+
{
61+
u32::serialize(&self.to_u32(), s)
62+
}
63+
}
64+
65+
#[cfg(feature = "serde")]
66+
impl<'de> Deserialize<'de> for BlockTime {
67+
#[inline]
68+
fn deserialize<D>(d: D) -> Result<Self, D::Error>
69+
where
70+
D: Deserializer<'de>,
71+
{
72+
Ok(Self::from_u32(u32::deserialize(d)?))
73+
}
74+
}
75+
5676
#[cfg(feature = "arbitrary")]
5777
impl<'a> Arbitrary<'a> for BlockTime {
5878
#[inline]

units/src/weight.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,19 @@ use core::{fmt, ops};
77

88
#[cfg(feature = "arbitrary")]
99
use arbitrary::{Arbitrary, Unstructured};
10+
#[cfg(feature = "serde")]
11+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
1012

1113
/// The factor that non-witness serialization data is multiplied by during weight calculation.
1214
pub const WITNESS_SCALE_FACTOR: usize = 4;
1315

1416
mod encapsulate {
15-
#[cfg(feature = "serde")]
16-
use serde::{Deserialize, Serialize};
1717

1818
/// The weight of a transaction or block.
1919
///
2020
/// This is an integer newtype representing [`Weight`] in `wu`. It provides protection
2121
/// against mixing up types as well as basic formatting features.
2222
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
23-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
24-
#[cfg_attr(feature = "serde", serde(transparent))]
2523
pub struct Weight(u64);
2624

2725
impl Weight {
@@ -263,6 +261,28 @@ impl<'a> core::iter::Sum<&'a Weight> for Weight {
263261

264262
crate::impl_parse_str_from_int_infallible!(Weight, u64, from_wu);
265263

264+
#[cfg(feature = "serde")]
265+
impl Serialize for Weight {
266+
#[inline]
267+
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
268+
where
269+
S: Serializer,
270+
{
271+
u64::serialize(&self.to_wu(), s)
272+
}
273+
}
274+
275+
#[cfg(feature = "serde")]
276+
impl<'de> Deserialize<'de> for Weight {
277+
#[inline]
278+
fn deserialize<D>(d: D) -> Result<Self, D::Error>
279+
where
280+
D: Deserializer<'de>,
281+
{
282+
Ok(Self::from_wu(u64::deserialize(d)?))
283+
}
284+
}
285+
266286
#[cfg(feature = "arbitrary")]
267287
impl<'a> Arbitrary<'a> for Weight {
268288
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {

0 commit comments

Comments
 (0)