summaryrefslogtreecommitdiffstats
path: root/third_party/rust/plist/src/date.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/plist/src/date.rs
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/plist/src/date.rs')
-rw-r--r--third_party/rust/plist/src/date.rs156
1 files changed, 156 insertions, 0 deletions
diff --git a/third_party/rust/plist/src/date.rs b/third_party/rust/plist/src/date.rs
new file mode 100644
index 0000000000..5268c54902
--- /dev/null
+++ b/third_party/rust/plist/src/date.rs
@@ -0,0 +1,156 @@
+use humantime;
+use std::{
+ fmt,
+ time::{Duration, SystemTime, UNIX_EPOCH},
+};
+
+/// A UTC timestamp used for serialization to and from the plist date type.
+///
+/// Note that while this type implements `Serialize` and `Deserialize` it will behave strangely if
+/// used with serializers from outside this crate.
+#[derive(Clone, Copy, Eq, Hash, PartialEq)]
+pub struct Date {
+ inner: SystemTime,
+}
+
+pub(crate) struct InfiniteOrNanDate;
+
+impl Date {
+ /// The unix timestamp of the plist epoch.
+ const PLIST_EPOCH_UNIX_TIMESTAMP: Duration = Duration::from_secs(978_307_200);
+
+ pub(crate) fn from_rfc3339(date: &str) -> Result<Self, ()> {
+ Ok(Date {
+ inner: humantime::parse_rfc3339(date).map_err(|_| ())?,
+ })
+ }
+
+ pub(crate) fn to_rfc3339(&self) -> String {
+ format!("{}", humantime::format_rfc3339(self.inner))
+ }
+
+ pub(crate) fn from_seconds_since_plist_epoch(
+ timestamp: f64,
+ ) -> Result<Date, InfiniteOrNanDate> {
+ // `timestamp` is the number of seconds since the plist epoch of 1/1/2001 00:00:00.
+ let plist_epoch = UNIX_EPOCH + Date::PLIST_EPOCH_UNIX_TIMESTAMP;
+
+ if !timestamp.is_finite() {
+ return Err(InfiniteOrNanDate);
+ }
+
+ let is_negative = timestamp < 0.0;
+ let timestamp = timestamp.abs();
+ let seconds = timestamp.floor() as u64;
+ let subsec_nanos = (timestamp.fract() * 1e9) as u32;
+
+ let dur_since_plist_epoch = Duration::new(seconds, subsec_nanos);
+
+ let inner = if is_negative {
+ plist_epoch - dur_since_plist_epoch
+ } else {
+ plist_epoch + dur_since_plist_epoch
+ };
+
+ Ok(Date { inner })
+ }
+
+ pub(crate) fn to_seconds_since_plist_epoch(&self) -> f64 {
+ // needed until #![feature(duration_float)] is stabilized
+ fn as_secs_f64(d: Duration) -> f64 {
+ const NANOS_PER_SEC: f64 = 1_000_000_000.00;
+ (d.as_secs() as f64) + f64::from(d.subsec_nanos()) / NANOS_PER_SEC
+ }
+
+ let plist_epoch = UNIX_EPOCH + Date::PLIST_EPOCH_UNIX_TIMESTAMP;
+ match self.inner.duration_since(plist_epoch) {
+ Ok(dur_since_plist_epoch) => as_secs_f64(dur_since_plist_epoch),
+ Err(err) => -as_secs_f64(err.duration()),
+ }
+ }
+}
+
+impl fmt::Debug for Date {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ let rfc3339 = humantime::format_rfc3339(self.inner);
+ <humantime::Rfc3339Timestamp as fmt::Display>::fmt(&rfc3339, f)
+ }
+}
+
+impl From<SystemTime> for Date {
+ fn from(date: SystemTime) -> Self {
+ Date { inner: date }
+ }
+}
+
+impl Into<SystemTime> for Date {
+ fn into(self) -> SystemTime {
+ self.inner
+ }
+}
+
+#[cfg(feature = "serde")]
+pub mod serde_impls {
+ use serde::{
+ de::{Deserialize, Deserializer, Error, Unexpected, Visitor},
+ ser::{Serialize, Serializer},
+ };
+ use std::fmt;
+
+ use crate::Date;
+
+ pub const DATE_NEWTYPE_STRUCT_NAME: &str = "PLIST-DATE";
+
+ impl Serialize for Date {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let date_str = self.to_rfc3339();
+ serializer.serialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, &date_str)
+ }
+ }
+
+ struct DateNewtypeVisitor;
+
+ impl<'de> Visitor<'de> for DateNewtypeVisitor {
+ type Value = Date;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a plist date newtype")
+ }
+
+ fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_str(DateStrVisitor)
+ }
+ }
+
+ struct DateStrVisitor;
+
+ impl<'de> Visitor<'de> for DateStrVisitor {
+ type Value = Date;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a plist date string")
+ }
+
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ Date::from_rfc3339(v).map_err(|()| E::invalid_value(Unexpected::Str(v), &self))
+ }
+ }
+
+ impl<'de> Deserialize<'de> for Date {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, DateNewtypeVisitor)
+ }
+ }
+}