From fdd33e40293ce6f8da4a681f9d085f57669b063d Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Thu, 15 Oct 2020 22:02:07 +0100 Subject: [PATCH] wip new tz Signed-off-by: Ian Jackson --- Cargo.lock.example | 60 +++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/gamestate.rs | 21 ++--------- src/imports.rs | 3 ++ src/lib.rs | 1 + src/tz.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 156 insertions(+), 18 deletions(-) create mode 100644 src/tz.rs diff --git a/Cargo.lock.example b/Cargo.lock.example index 1a9c692a..51e03b18 100644 --- a/Cargo.lock.example +++ b/Cargo.lock.example @@ -239,6 +239,15 @@ dependencies = [ "parse-zoneinfo", ] +[[package]] +name = "cloudabi" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" +dependencies = [ + "bitflags", +] + [[package]] name = "console_error_panic_hook" version = "0.1.6" @@ -747,6 +756,15 @@ dependencies = [ "libc", ] +[[package]] +name = "instant" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66" +dependencies = [ + "cfg-if", +] + [[package]] name = "inventory" version = "0.1.9" @@ -836,6 +854,15 @@ version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" +[[package]] +name = "lock_api" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.3.9" @@ -1057,6 +1084,7 @@ dependencies = [ "num-traits", "ordered-float", "otter-zcoord", + "parking_lot", "percent-encoding 2.1.0", "pwd", "rand", @@ -1101,6 +1129,32 @@ dependencies = [ "thiserror", ] +[[package]] +name = "parking_lot" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" +dependencies = [ + "cfg-if", + "cloudabi", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi 0.3.9", +] + [[package]] name = "parse-zoneinfo" version = "0.3.0" @@ -1464,6 +1518,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "serde" version = "1.0.116" diff --git a/Cargo.toml b/Cargo.toml index 15ef616d..ee2385ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ log = "0.4" nix = "0.18" num-traits = "0.2" ordered-float = "2" +parking_lot = "0.11" percent-encoding = "2" pwd = "1" rand = "0" diff --git a/src/gamestate.rs b/src/gamestate.rs index 1572cf62..62f9df63 100644 --- a/src/gamestate.rs +++ b/src/gamestate.rs @@ -174,24 +174,9 @@ impl Timestamp { } pub fn render(&self, tz: &Timezone) -> String { - #[derive(Error,Debug)] - enum E { - #[from] SystemTime(SystemTimeError); - #[from] Other(&'static str); - }; - - (||{ - let then = SytemTime::UNIX_EPOCH.checked_add( - Duration::from_secs(tz.0) - ).ok_or("SystemTime wrap error!")?; - let elapsed = then.elapsed()?; - if elapsed > 86400/2 { - - } - let now = SystemTime::now(); - let elapsed = now.duration_since(then); - - None => format!("TS{}(@{:?})", self.0, tz) + let s = String::with_capacity(30); + tz.format(&mut s).unwrap(); + s } } diff --git a/src/imports.rs b/src/imports.rs index e86d1989..6c293f41 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -43,6 +43,9 @@ pub use serde::{Serialize,Deserialize,de::DeserializeOwned}; pub use serde::{Serializer,Deserializer}; pub use serde::ser::SerializeTuple; +pub use serde_with::DeserializeFromStr; +pub use serde_with::SerializeDisplay; + pub use rocket_contrib::helmet::*; pub use rocket_contrib::templates::Template; diff --git a/src/lib.rs b/src/lib.rs index e69492ef..96163a0a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,4 +24,5 @@ pub mod utils; pub mod mgmtchannel; pub mod debugreader; pub mod shapelib; +pub mod tz; #[path="slotmap-slot-idx.rs"] pub mod slotmap_slot_idx; diff --git a/src/tz.rs b/src/tz.rs new file mode 100644 index 00000000..9d75520e --- /dev/null +++ b/src/tz.rs @@ -0,0 +1,88 @@ +// Copyright 2020 Ian Jackson +// SPDX-License-Identifier: AGPL-3.0-or-later +// There is NO WARRANTY. + +use crate::imports::*; + +use parking_lot::{RwLock, const_rwlock}; + +#[derive(SerializeDisplay)] +#[derive(DeserializeFromStr)] +pub struct Timezone (Arc); + +pub trait TimeFormatter : Debug { + fn format(&self, ts: Timestamp, f: &mut Formatter) -> fmt::Result<()>; + fn name(&self) -> &str; +} + +impl Display for Timezone { + fn fmt(&self, f: &mut Formatter) -> io::Result<()> { + write!(f, "{}", self.0.name()) + } +} + +#[derive(Clone,Debug,Default,Serialize,Deserialize)] +struct ChronoTz { + name: String, + ctz: TZ, +} + +impl TimeFormatter for ChronoTz { + fn name(&self) -> &str { &self.name() } + + #[throws(fmt::Result)] + fn format(&self, ts: Timestamp, f: &mut Formatter) { + write!(f, "TS{}(@{:?})", ts, &self); + +/* #[derive(Error,Debug)] + enum E { + #[from] SystemTime(SystemTimeError); + #[from] Other(&'static str); + }; + + (||{ + let then = SytemTime::UNIX_EPOCH.checked_add( + Duration::from_secs(tz.0) + ).ok_or("SystemTime wrap error!")?; + let elapsed = then.elapsed()?; + if elapsed > 86400/2 { + + } + let now = SystemTime::now(); + let elapsed = now.duration_since(then); + + None => format!("TS{}(@{:?})", self.0, tz) + } +*/ + + } +} + +static memo: RwLock>> = const_rwlock(None); + +impl FromStr for Timezone { + fn from_str(name: &str) -> Self { + let get = |memor,s| memor?.get(name).map(Clone::clone); + if let Some(got) = get(memo.read(), s) { return got } + + // slow path + let memow = memo.write(); + if let Some(got) = get(memow, s) { return got } + + // really slow path + let name = name.to_string(); + let out = match chrono_tz::Tz::from_str(name) { + Ok(ctz) => { + Arc::new(ChronoTz { ctz, name }) + }, + Err(emsg) => { + error!("Error loading timezone {:?}: {}, using UTC", name, emsg); + let ctz = chrono::offset::Utc; + Arc::new(ChroniTz { ctz, name }) + }, + }; + meow.get_or_insert_with(default) + .set(name.to_string(), r.clone()); + out + } +} -- 2.30.2