@@ -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/)
4646pub 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