chiark / gitweb /
wip new tz
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 15 Oct 2020 21:02:07 +0000 (22:02 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 15 Oct 2020 21:02:07 +0000 (22:02 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Cargo.lock.example
Cargo.toml
src/gamestate.rs
src/imports.rs
src/lib.rs
src/tz.rs [new file with mode: 0644]

index 1a9c692a5fd09a897352b688c5591033873b5f08..51e03b18c353dc60830d8e247d891e8d0f4f9c72 100644 (file)
@@ -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"
index 15ef616dcab0f0e405f826424c63f82c00944882..ee2385ad389a738c64545c1e6aba68a6924ce603 100644 (file)
@@ -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"
index 1572cf6248122e9d3b7c4b90c71c238de7907f9a..62f9df63fcb906db7689e2ee4a739abb83aa271b 100644 (file)
@@ -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
   }
 }
 
index e86d19897040a6c607521676d09087345576befc..6c293f41f62501de38c5e974563942bfae1d81d9 100644 (file)
@@ -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;
 
index e69492ef955565df7ff038386900182666f5337d..96163a0a76be090b9eb90abed37eb2e3626122c7 100644 (file)
@@ -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 (file)
index 0000000..9d75520
--- /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<dyn TimeFormatter>);
+
+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<TZ: chrono::TimeZone> {
+  name: String,
+  ctz: TZ,
+}
+  
+impl TimeFormatter<TZ: chrono::TimeZone> for ChronoTz<TZ> {
+  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<Option<HashMap<String, Timezone>>> = 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
+  }
+}