1#[cfg(feature = "encoding")]
11use core::convert::Infallible;
12use core::fmt;
13
14#[cfg(feature = "arbitrary")]
15use arbitrary::{Arbitrary, Unstructured};
16#[cfg(feature = "encoding")]
17use internals::write_err;
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Deserializer, Serialize, Serializer};
20
21mod encapsulate {
22 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
35 pub struct BlockTime(u32);
36
37 impl BlockTime {
38 #[inline]
40 pub const fn from_u32(t: u32) -> Self { Self(t) }
41
42 #[inline]
44 pub const fn to_u32(self) -> u32 { self.0 }
45 }
46}
47#[doc(inline)]
48pub use encapsulate::BlockTime;
49
50crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockTime, to_u32);
51
52impl fmt::Display for BlockTime {
53 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.to_u32(), f) }
54}
55
56impl From<u32> for BlockTime {
57 #[inline]
58 fn from(t: u32) -> Self { Self::from_u32(t) }
59}
60
61impl From<BlockTime> for u32 {
62 #[inline]
63 fn from(t: BlockTime) -> Self { t.to_u32() }
64}
65
66#[cfg(feature = "serde")]
67impl Serialize for BlockTime {
68 #[inline]
69 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
70 where
71 S: Serializer,
72 {
73 u32::serialize(&self.to_u32(), s)
74 }
75}
76
77#[cfg(feature = "serde")]
78impl<'de> Deserialize<'de> for BlockTime {
79 #[inline]
80 fn deserialize<D>(d: D) -> Result<Self, D::Error>
81 where
82 D: Deserializer<'de>,
83 {
84 Ok(Self::from_u32(u32::deserialize(d)?))
85 }
86}
87
88#[cfg(feature = "encoding")]
89encoding::encoder_newtype_exact! {
90 pub struct BlockTimeEncoder<'e>(encoding::ArrayEncoder<4>);
92}
93
94#[cfg(feature = "encoding")]
95impl encoding::Encodable for BlockTime {
96 type Encoder<'e> = BlockTimeEncoder<'e>;
97 fn encoder(&self) -> Self::Encoder<'_> {
98 BlockTimeEncoder::new(encoding::ArrayEncoder::without_length_prefix(
99 self.to_u32().to_le_bytes(),
100 ))
101 }
102}
103
104#[cfg(feature = "encoding")]
106pub struct BlockTimeDecoder(encoding::ArrayDecoder<4>);
107
108#[cfg(feature = "encoding")]
109impl Default for BlockTimeDecoder {
110 fn default() -> Self { Self::new() }
111}
112
113#[cfg(feature = "encoding")]
114impl BlockTimeDecoder {
115 pub const fn new() -> Self { Self(encoding::ArrayDecoder::new()) }
117}
118
119#[cfg(feature = "encoding")]
120impl encoding::Decoder for BlockTimeDecoder {
121 type Output = BlockTime;
122 type Error = BlockTimeDecoderError;
123
124 #[inline]
125 fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
126 self.0.push_bytes(bytes).map_err(BlockTimeDecoderError)
127 }
128
129 #[inline]
130 fn end(self) -> Result<Self::Output, Self::Error> {
131 let t = u32::from_le_bytes(self.0.end().map_err(BlockTimeDecoderError)?);
132 Ok(BlockTime::from_u32(t))
133 }
134
135 #[inline]
136 fn read_limit(&self) -> usize { self.0.read_limit() }
137}
138
139#[cfg(feature = "encoding")]
140impl encoding::Decodable for BlockTime {
141 type Decoder = BlockTimeDecoder;
142 fn decoder() -> Self::Decoder { BlockTimeDecoder(encoding::ArrayDecoder::<4>::new()) }
143}
144
145#[cfg(feature = "encoding")]
147#[derive(Debug, Clone, PartialEq, Eq)]
148pub struct BlockTimeDecoderError(encoding::UnexpectedEofError);
149
150#[cfg(feature = "encoding")]
151impl From<Infallible> for BlockTimeDecoderError {
152 fn from(never: Infallible) -> Self { match never {} }
153}
154
155#[cfg(feature = "encoding")]
156impl fmt::Display for BlockTimeDecoderError {
157 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158 write_err!(f, "block time decoder error"; self.0)
159 }
160}
161
162#[cfg(all(feature = "std", feature = "encoding"))]
163impl std::error::Error for BlockTimeDecoderError {
164 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
165}
166
167#[cfg(feature = "arbitrary")]
168impl<'a> Arbitrary<'a> for BlockTime {
169 #[inline]
170 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
171 let t: u32 = u.arbitrary()?;
172 Ok(Self::from(t))
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 #[cfg(feature = "alloc")]
179 use alloc::string::ToString;
180
181 #[cfg(feature = "encoding")]
182 use encoding::Decoder as _;
183 #[cfg(all(feature = "encoding", feature = "alloc"))]
184 use encoding::UnexpectedEofError;
185
186 use super::*;
187
188 #[test]
189 fn block_time_round_trip() {
190 let t = BlockTime::from(1_742_979_600); assert_eq!(u32::from(t), 1_742_979_600);
192 }
193
194 #[test]
195 #[cfg(feature = "serde")]
196 fn block_time_serde_round_trip() {
197 let t = BlockTime::from(1_765_364_400); let json = serde_json::to_string(&t).unwrap();
200 assert_eq!(json, "1765364400"); let roundtrip = serde_json::from_str::<BlockTime>(&json).unwrap();
203 assert_eq!(t, roundtrip);
204 }
205
206 #[test]
207 #[cfg(all(feature = "encoding", feature = "alloc"))]
208 fn block_time_decoding_error() {
209 let bytes = [0xb0, 0x52, 0x39]; let mut decoder = BlockTimeDecoder::default();
212 assert!(decoder.push_bytes(&mut bytes.as_slice()).unwrap());
213
214 let error = decoder.end().unwrap_err();
215 assert!(matches!(error, BlockTimeDecoderError(UnexpectedEofError { .. })));
216 }
217
218 #[test]
219 #[cfg(feature = "alloc")]
220 fn time_module_display() {
221 assert_eq!(BlockTime::from(1_765_364_400).to_string(), "1765364400");
222 }
223
224 #[test]
225 #[cfg(feature = "alloc")]
226 #[cfg(feature = "encoding")]
227 fn time_module_error_display() {
228 let bytes = [0xb0, 0x52, 0x39]; let mut decoder = BlockTimeDecoder::default();
232 assert!(decoder.push_bytes(&mut bytes.as_slice()).unwrap());
233
234 assert_ne!(decoder.end().unwrap_err().to_string(), "");
235 }
236}