amaru_kernel/utils/cbor/
serialised_as_pico.rs1use std::time::Duration;
16
17use num::BigUint;
18
19use crate::cbor;
20
21#[derive(Debug)]
32#[repr(transparent)]
33pub struct SerialisedAsPico(Duration);
34
35impl From<SerialisedAsPico> for Duration {
36 fn from(t: SerialisedAsPico) -> Self {
37 t.0
38 }
39}
40
41impl From<Duration> for SerialisedAsPico {
42 fn from(d: Duration) -> Self {
43 Self(d)
44 }
45}
46
47impl SerialisedAsPico {
48 pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
49 where
50 D: serde::Deserializer<'de>,
51 {
52 Ok(Duration::from_secs(serde::Deserialize::deserialize(deserializer)?))
53 }
54
55 pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
56 where
57 S: serde::Serializer,
58 {
59 serde::Serialize::serialize(&duration.as_secs(), serializer)
60 }
61}
62
63impl<C> cbor::Encode<C> for SerialisedAsPico {
64 fn encode<W: cbor::encode::Write>(
65 &self,
66 e: &mut cbor::Encoder<W>,
67 ctx: &mut C,
68 ) -> Result<(), cbor::encode::Error<W::Error>> {
69 let s = self.0.as_nanos();
70 match s.checked_mul(1000).and_then(|s| u64::try_from(s).ok()) {
71 Some(t) => t.encode(e, ctx),
72 None => {
73 e.tag(cbor::IanaTag::PosBignum)?;
74 e.bytes(&(BigUint::from(s) * 1000u16).to_bytes_be())?;
75 Ok(())
76 }
77 }
78 }
79}
80
81impl<'b, C> cbor::Decode<'b, C> for SerialisedAsPico {
82 #[allow(clippy::wildcard_enum_match_arm)]
83 fn decode(d: &mut cbor::Decoder<'b>, _ctx: &mut C) -> Result<Self, cbor::decode::Error> {
84 use cbor::Type::*;
85 match d.datatype()? {
86 Tag => {
87 cbor::expect_tag(d, cbor::IanaTag::PosBignum)?;
88 let nanos = BigUint::from_bytes_be(d.bytes()?) / 1000u16;
89 match u128::try_from(nanos) {
90 Ok(nanos) => {
91 if nanos < (u64::MAX as u128) * 1_000_000_000 {
92 Ok(Self(Duration::from_nanos_u128(nanos)))
93 } else {
94 Err(cbor::decode::Error::message(format!(
95 "cannot convert to Duration, too large: {nanos}ns"
96 )))
97 }
98 }
99 Err(nanos) => Err(cbor::decode::Error::message(format!(
100 "cannot convert to Duration, too large: {}ns",
101 nanos.into_original()
102 ))),
103 }
104 }
105 U64 | U32 | U16 | U8 => Ok(Self(Duration::from_nanos(d.u64()? / 1000))),
106 t => Err(cbor::decode::Error::message(format!("Unhandled type decoding SerialisedAsPico: {t}"))),
107 }
108 }
109}