xsd_types/value/duration/
mod.rs

1use crate::{
2	format_nanoseconds,
3	lexical::{InvalidDuration, LexicalFormOf},
4	Datatype, DurationDatatype, ParseXsd, XsdValue,
5};
6use core::fmt;
7use std::str::FromStr;
8
9pub mod day_time_duration;
10pub use day_time_duration::*;
11
12pub mod year_month_duration;
13pub use year_month_duration::*;
14
15#[derive(Debug, Clone, Copy)]
16pub struct Duration {
17	is_negative: bool,
18	months: u32,
19	seconds: u32,
20	nano_seconds: u32,
21}
22
23impl Duration {
24	pub fn new(is_negative: bool, months: u32, mut seconds: u32, mut nano_seconds: u32) -> Self {
25		// Normalize nanoseconds.
26		let s = nano_seconds / 1_000_000_000;
27		if s > 0 {
28			seconds += s;
29			nano_seconds -= s * 1_000_000_000;
30		}
31
32		Self {
33			is_negative,
34			months,
35			seconds,
36			nano_seconds,
37		}
38	}
39
40	pub fn into_string(self) -> String {
41		self.to_string()
42	}
43}
44
45impl XsdValue for Duration {
46	fn datatype(&self) -> Datatype {
47		Datatype::Duration(DurationDatatype::Duration)
48	}
49}
50
51impl ParseXsd for Duration {
52	type LexicalForm = crate::lexical::Duration;
53}
54
55impl FromStr for Duration {
56	type Err = InvalidDuration<String>;
57
58	fn from_str(s: &str) -> Result<Self, Self::Err> {
59		let lexical_value = crate::lexical::Duration::new(s)
60			.map_err(|InvalidDuration(s)| InvalidDuration(s.to_owned()))?;
61		Ok(lexical_value.as_value())
62	}
63}
64
65impl fmt::Display for Duration {
66	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67		let year = self.months / 12;
68		let month = self.months - year * 12;
69
70		let mut minute = self.seconds / 60;
71		let second = self.seconds - minute * 60;
72
73		let mut hour = minute / 60;
74		minute -= hour * 60;
75
76		let day = hour / 24;
77		hour -= day * 24;
78
79		if self.is_negative {
80			write!(f, "-")?;
81		}
82
83		write!(f, "P")?;
84
85		if year > 0 {
86			write!(f, "{year}Y")?;
87		}
88
89		if month > 0 {
90			write!(f, "{month}M")?;
91		}
92
93		if day > 0 {
94			write!(f, "{day}D")?;
95		}
96
97		if hour > 0 || minute > 0 || second > 0 || self.nano_seconds > 0 {
98			write!(f, "T")?;
99
100			if hour > 0 {
101				write!(f, "{hour}H")?;
102			}
103
104			if minute > 0 {
105				write!(f, "{minute}M")?;
106			}
107
108			if second > 0 || self.nano_seconds > 0 {
109				if second > 0 {
110					second.fmt(f)?;
111				}
112
113				format_nanoseconds(self.nano_seconds, f)?;
114				write!(f, "S")?;
115			}
116		}
117
118		Ok(())
119	}
120}
121
122#[cfg(feature = "serde")]
123impl serde::Serialize for Duration {
124	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
125	where
126		S: serde::Serializer,
127	{
128		self.into_string().serialize(serializer)
129	}
130}
131
132#[cfg(feature = "serde")]
133impl<'de> serde::Deserialize<'de> for Duration {
134	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
135	where
136		D: serde::Deserializer<'de>,
137	{
138		struct Visitor;
139
140		impl<'de> serde::de::Visitor<'de> for Visitor {
141			type Value = Duration;
142
143			fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
144				formatter.write_str("a http://www.w3.org/2001/XMLSchema#duration")
145			}
146
147			fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
148			where
149				E: serde::de::Error,
150			{
151				v.parse().map_err(|e| E::custom(e))
152			}
153		}
154
155		deserializer.deserialize_str(Visitor)
156	}
157}