Skip to content

Commit 336ac0e

Browse files
committed
feat: Reimplement rfc3339 serialization
1 parent d896831 commit 336ac0e

File tree

2 files changed

+91
-3
lines changed

2 files changed

+91
-3
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ serde_json = { version = "1.0.81", default-features = false }
2020
serde_repr = "0.1.9"
2121
serde_with = { version = "3.7.0", default-features = false, features = ["macros"] }
2222
thiserror = { version = "2.0.3", default-features = false }
23-
time = { version = "0.3.11", features = ["serde", "serde-well-known"], default-features = false }
23+
time = { version = "0.3.11", features = ["serde", "parsing"], default-features = false }
2424

2525
[dev-dependencies]
2626
pretty_assertions = "1.4.0"

src/thing.rs

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,94 @@ pub const TD_CONTEXT_10: &str = "https://www.w3.org/2019/wot/td/v1";
4545
/// description](https://www.w3.org/TR/wot-thing-description11/)
4646
pub const TD_CONTEXT_11: &str = "https://www.w3.org/2022/wot/td/v1.1";
4747

48+
mod rfc3339_option {
49+
use core::fmt;
50+
51+
use alloc::format;
52+
use serde::{ser::Error, Serialize, Serializer};
53+
use time::OffsetDateTime;
54+
55+
pub use time::serde::rfc3339::option::deserialize;
56+
57+
// time uses std::io::Write internally making the serializer unavailable
58+
// for no_std
59+
// https://github.com/time-rs/time/issues/375
60+
pub fn serialize<S: Serializer>(
61+
option: &Option<OffsetDateTime>,
62+
serializer: S,
63+
) -> Result<S::Ok, S::Error> {
64+
option
65+
.map(|odt| {
66+
let date = odt.date();
67+
let time = odt.time();
68+
let offset = odt.offset();
69+
70+
let year = date.year();
71+
72+
if !(0..10_000).contains(&year) {
73+
return Err(fmt::Error);
74+
}
75+
if offset.whole_hours().unsigned_abs() > 23 {
76+
return Err(fmt::Error);
77+
}
78+
if offset.seconds_past_minute() != 0 {
79+
return Err(fmt::Error);
80+
}
81+
82+
let month = u8::from(date.month());
83+
let day = date.day();
84+
85+
let hour = time.hour();
86+
let minute = time.minute();
87+
let second = time.second();
88+
89+
let ns = time.nanosecond();
90+
91+
let subsecond = if ns == 0 {
92+
""
93+
} else if ns % 10 != 0 {
94+
&format!(".{:09}", ns)
95+
} else if (ns / 10) % 10 != 0 {
96+
&format!(".{:08}", ns / 10)
97+
} else if (ns / 100) % 10 != 0 {
98+
&format!(".{:07}", ns / 100)
99+
} else if (ns / 1_000) % 10 != 0 {
100+
&format!(".{:06}", ns / 1_000)
101+
} else if (ns / 10_000) % 10 != 0 {
102+
&format!(".{:05}", ns / 10_000)
103+
} else if (ns / 100_000) % 10 != 0 {
104+
&format!(".{:04}", ns / 100_000)
105+
} else if (ns / 1_000_000) % 10 != 0 {
106+
&format!(".{:03}", ns / 1_000_000)
107+
} else if (ns / 10_000_000) % 10 != 0 {
108+
&format!(".{:02}", ns / 10_000_000)
109+
} else {
110+
&format!(".{:01}", ns / 100_000_000)
111+
};
112+
113+
let tz_h = offset.whole_hours().unsigned_abs();
114+
let tz_m = offset.minutes_past_hour().unsigned_abs();
115+
116+
let tzs = if offset.is_utc() {
117+
"Z"
118+
} else if offset.is_negative() {
119+
&format!("-{tz_h:02}:{tz_m:02}")
120+
} else {
121+
&format!("+{tz_h:02}:{tz_m:02}")
122+
};
123+
124+
let s = format!(
125+
"{year:02}-{month:02}-{day:02}T{hour:02}:{minute:02}:{second:02}{subsecond}{tzs}"
126+
);
127+
128+
Ok(s)
129+
})
130+
.transpose()
131+
.map_err(S::Error::custom)?
132+
.serialize(serializer)
133+
}
134+
}
135+
48136
/// An abstraction of a physical or a virtual entity
49137
///
50138
/// It contains metadata and a description of its interfaces.
@@ -86,13 +174,13 @@ pub struct Thing<Other: ExtendableThing = Nil> {
86174
/// Time of creation of this description
87175
///
88176
/// It may be used for caching purposes.
89-
#[serde(with = "time::serde::rfc3339::option", default)]
177+
#[serde(with = "rfc3339_option", default)]
90178
pub created: Option<OffsetDateTime>,
91179

92180
/// Time of last update of this description
93181
///
94182
/// It may be used for caching purposes.
95-
#[serde(with = "time::serde::rfc3339::option", default)]
183+
#[serde(with = "rfc3339_option", default)]
96184
pub modified: Option<OffsetDateTime>,
97185

98186
/// URI to the device maintainer

0 commit comments

Comments
 (0)