1use core::fmt;
11
12#[cfg(feature = "arbitrary")]
13use arbitrary::{Arbitrary, Unstructured};
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Deserializer, Serialize, Serializer};
16
17use crate::parse_int::{self, PrefixedHexError, UnprefixedHexError};
18
19#[rustfmt::skip] #[cfg(feature = "encoding")]
21#[doc(no_inline)]
22pub use self::error::BlockTimeDecoderError;
23
24mod encapsulate {
25 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
38 pub struct BlockTime(u32);
39
40 impl BlockTime {
41 #[inline]
43 pub const fn from_u32(t: u32) -> Self { Self(t) }
44
45 #[inline]
47 pub const fn to_u32(self) -> u32 { self.0 }
48 }
49}
50#[doc(inline)]
51pub use encapsulate::BlockTime;
52
53impl BlockTime {
54 #[inline]
61 pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
62 let block_time = parse_int::hex_u32_prefixed(s)?;
63 Ok(Self::from_u32(block_time))
64 }
65
66 #[inline]
73 pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
74 let block_time = parse_int::hex_u32_unprefixed(s)?;
75 Ok(Self::from_u32(block_time))
76 }
77}
78
79crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(BlockTime, to_u32);
80
81impl fmt::Display for BlockTime {
82 #[inline]
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.to_u32(), f) }
84}
85
86impl From<u32> for BlockTime {
87 #[inline]
88 fn from(t: u32) -> Self { Self::from_u32(t) }
89}
90
91impl From<BlockTime> for u32 {
92 #[inline]
93 fn from(t: BlockTime) -> Self { t.to_u32() }
94}
95
96parse_int::impl_parse_str_from_int_infallible!(BlockTime, u32, from_u32);
97
98#[cfg(feature = "serde")]
99impl Serialize for BlockTime {
100 #[inline]
101 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
102 where
103 S: Serializer,
104 {
105 u32::serialize(&self.to_u32(), s)
106 }
107}
108
109#[cfg(feature = "serde")]
110impl<'de> Deserialize<'de> for BlockTime {
111 #[inline]
112 fn deserialize<D>(d: D) -> Result<Self, D::Error>
113 where
114 D: Deserializer<'de>,
115 {
116 Ok(Self::from_u32(u32::deserialize(d)?))
117 }
118}
119
120#[cfg(feature = "encoding")]
121impl encoding::Encode for BlockTime {
122 type Encoder<'e> = BlockTimeEncoder<'e>;
123 #[inline]
124 fn encoder(&self) -> Self::Encoder<'_> {
125 BlockTimeEncoder::new(encoding::ArrayEncoder::without_length_prefix(
126 self.to_u32().to_le_bytes(),
127 ))
128 }
129}
130
131#[cfg(feature = "encoding")]
132impl encoding::Decode for BlockTime {
133 type Decoder = BlockTimeDecoder;
134}
135
136#[cfg(feature = "encoding")]
137encoding::encoder_newtype_exact! {
138 #[derive(Debug, Clone)]
140 pub struct BlockTimeEncoder<'e>(encoding::ArrayEncoder<4>);
141}
142
143#[cfg(feature = "encoding")]
144crate::decoder_newtype! {
145 #[derive(Debug, Clone)]
147 pub struct BlockTimeDecoder(encoding::ArrayDecoder<4>);
148
149 pub const fn new() -> Self { Self(encoding::ArrayDecoder::new()) }
151
152 fn end(result: Result<[u8; 4], encoding::UnexpectedEofError>) -> Result<BlockTime, BlockTimeDecoderError> {
153 let value = result.map_err(BlockTimeDecoderError)?;
154 let n = u32::from_le_bytes(value);
155 Ok(BlockTime::from_u32(n))
156 }
157}
158
159pub mod error {
161 #[cfg(feature = "encoding")]
162 use core::convert::Infallible;
163 #[cfg(feature = "encoding")]
164 use core::fmt;
165
166 #[cfg(feature = "encoding")]
167 use internals::write_err;
168
169 #[cfg(feature = "encoding")]
171 #[derive(Debug, Clone, PartialEq, Eq)]
172 pub struct BlockTimeDecoderError(pub(super) encoding::UnexpectedEofError);
173
174 #[cfg(feature = "encoding")]
175 impl From<Infallible> for BlockTimeDecoderError {
176 fn from(never: Infallible) -> Self { match never {} }
177 }
178
179 #[cfg(feature = "encoding")]
180 impl fmt::Display for BlockTimeDecoderError {
181 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182 write_err!(f, "block time decoder error"; self.0)
183 }
184 }
185
186 #[cfg(feature = "encoding")]
187 #[cfg(feature = "std")]
188 impl std::error::Error for BlockTimeDecoderError {
189 #[inline]
190 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
191 }
192}
193
194#[cfg(feature = "arbitrary")]
195impl<'a> Arbitrary<'a> for BlockTime {
196 #[inline]
197 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
198 let t: u32 = u.arbitrary()?;
199 Ok(Self::from(t))
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 #[cfg(feature = "alloc")]
206 use alloc::string::ToString;
207 #[cfg(feature = "encoding")]
208 #[cfg(feature = "std")]
209 use std::error::Error;
210
211 #[cfg(feature = "encoding")]
212 use encoding::Decoder as _;
213 #[cfg(feature = "alloc")]
214 #[cfg(feature = "encoding")]
215 use encoding::UnexpectedEofError;
216
217 use super::*;
218
219 #[test]
220 fn block_time_round_trip() {
221 let t = BlockTime::from(1_742_979_600); assert_eq!(u32::from(t), 1_742_979_600);
223 }
224
225 #[test]
226 #[cfg(feature = "serde")]
227 fn block_time_serde_round_trip() {
228 let t = BlockTime::from(1_765_364_400); let json = serde_json::to_string(&t).unwrap();
231 assert_eq!(json, "1765364400"); let roundtrip = serde_json::from_str::<BlockTime>(&json).unwrap();
234 assert_eq!(t, roundtrip);
235 }
236
237 #[test]
238 #[cfg(feature = "alloc")]
239 #[cfg(feature = "encoding")]
240 fn block_time_decoding_error() {
241 let bytes = [0xb0, 0x52, 0x39]; let mut decoder = BlockTimeDecoder::default();
244 assert!(decoder.push_bytes(&mut bytes.as_slice()).unwrap().needs_more());
245
246 let error = decoder.end().unwrap_err();
247 assert!(matches!(error, BlockTimeDecoderError(UnexpectedEofError { .. })));
248 }
249
250 #[test]
251 #[cfg(feature = "alloc")]
252 fn time_module_display() {
253 assert_eq!(BlockTime::from(1_765_364_400).to_string(), "1765364400");
254 }
255
256 #[test]
257 #[cfg(feature = "alloc")]
258 #[cfg(feature = "encoding")]
259 fn time_module_error_display() {
260 let bytes = [0xb0, 0x52, 0x39]; let mut decoder = BlockTimeDecoder::default();
264 let _ = decoder.push_bytes(&mut bytes.as_slice());
265
266 let e = decoder.end().unwrap_err();
267 assert!(!e.to_string().is_empty());
268 #[cfg(feature = "std")]
269 assert!(e.source().is_some());
270 }
271}