diff --git a/Cargo.toml b/Cargo.toml index 9d1c20f..7687a86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,21 +1,22 @@ [package] authors = ["Dylan MacKenzie "] name = "ksuid" -version = "0.1.0" +version = "0.3.0" description = "A library for efficiently generating, parsing and serializing Segment.io KSUIDs" repository = "https://github.com/ecstatic-morse/ksuid.git" readme = "README.md" keywords = ["uuid", "ksuid", "guid"] license = "MIT" +edition = "2021" [dependencies] -byteorder = "1.0.0" -rand = "0.3.15" -resize-slice = "0.1.2" -time = "0.1.37" +byteorder = "1.5.0" +rand = "0.8.5" +resize-slice = "0.1.3" +time = { version = "0.3.37", features = ["macros"] } [dev-dependencies] -num = "0.1.39" +num = "0.4.3" [features] # Set on nightly to enable benchmarks diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 59191aa..e3d7c2a 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,17 +1,17 @@ [package] authors = ["Dylan MacKenzie "] name = "ksuid-cli" -version = "0.1.0" +version = "0.1.1" description = "A command line interface for generating, parsing, and serializing Segment.io KSUIDs" repository = "https://github.com/ecstatic-morse/ksuid.git" readme = "../README.md" keywords = ["uuid", "ksuid", "guid"] license = "MIT" +edition = "2021" [dependencies] -docopt = "0.8.0" -ksuid = { version="0.1.0", path = ".." } -rand = "0.3.15" -serde = "1.0.8" -serde_derive = "1.0.8" -time = "0.1.37" +docopt = "1.1.1" +ksuid = { version="0.3.0", path = ".." } +rand = "0.8.5" +serde = "1.0.215" +serde_derive = "1.0.215" diff --git a/cli/src/main.rs b/cli/src/main.rs index d8c2974..f94612c 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -3,14 +3,12 @@ extern crate serde_derive; extern crate docopt; extern crate ksuid; -extern crate time; extern crate rand; use std::io::{self, Write}; use std::process::exit; use ksuid::Ksuid; -use rand::Rng; const USAGE: &str = " ksuid @@ -45,11 +43,8 @@ fn main() { fn generate(args: Args) { let out = io::stdout(); let mut locked = out.lock(); - - let mut rng = rand::thread_rng(); - for _ in 0..args.flag_count { - writeln!(&mut locked, "{}", rng.gen::().to_base62()).unwrap(); + writeln!(&mut locked, "{}", Ksuid::generate().to_base62()).unwrap(); } } @@ -85,7 +80,7 @@ COMPONENTS: " , ksuid.to_base62(), ksuid.to_hex(), - time::at(ksuid.time()).rfc822(), + ksuid.time(), ksuid.timestamp(), ksuid.to_hex().chars().skip(8).collect::()); } diff --git a/src/lib.rs b/src/lib.rs index b285020..5df9f90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,20 +22,20 @@ extern crate time; mod base62; use std::io; -use std::ascii::AsciiExt; use byteorder::{ByteOrder, BigEndian}; -use time::{Timespec, Duration}; -use rand::{Rng, Rand}; +use time::{OffsetDateTime, Duration}; +use rand::Rng; +use rand::RngCore; /// The KSUID epoch, 1.4 billion seconds after the UNIX epoch. /// /// ``` /// # extern crate ksuid; /// # extern crate time; -/// assert_eq!(ksuid::EPOCH, time::strptime("2014-5-13 16:53:20", "%Y-%m-%d %T").unwrap().to_timespec()); +/// use time::macros::datetime; +/// assert_eq!(ksuid::get_epoch(), datetime!(2014-5-13 16:53:20).assume_utc()); /// ``` -pub const EPOCH: Timespec = Timespec {sec: 1_400_000_000, nsec: 0}; const LEN: usize = 20; const EMPTY: [u8; LEN] = [0; LEN]; @@ -44,6 +44,12 @@ const HEX_LEN: usize = 40; const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; const MAX_BASE62_KSUID: &[u8] = b"aWgEPTl1tmebfsQzFP4bxwgy80V"; +/// Returns an OffsetDateTime representing Ksuid's start time. +/// The crate "time" >= 2 returns a Result, making it incompatible with const. +pub fn get_epoch() -> OffsetDateTime { + OffsetDateTime::from_unix_timestamp(1_400_000_000).unwrap() +} + /// Get the numeric value corresponding to the given ASCII hex digit. fn hex_digit(c: u8) -> io::Result { HEX_DIGITS.iter() @@ -82,19 +88,16 @@ impl Ksuid { /// Create a new identifier with a current timestamp and the given payload. pub fn with_payload(payload: [u8; 16]) -> Self { // TODO: check for overflow in timestamp - let elapsed = time::get_time() - EPOCH; - let ts = elapsed.num_seconds() as u32; + let elapsed = OffsetDateTime::now_utc() - get_epoch(); + let ts = elapsed.whole_seconds() as u32; Self::new(ts, payload) } /// Create a new identifier with a current timestamp and randomly generated payload. - /// - /// This function uses the thread local random number generator. this means that if you're - /// calling `generate()` in a loop, caching the generator can increase performance. See the - /// documentation of [`rand::random()`](https://doc.rust-lang.org/rand/rand/fn.random.html) for - /// an example. pub fn generate() -> Self { - rand::random() + let mut data = [0u8; 16]; + rand::thread_rng().fill_bytes(&mut data); + Self::with_payload(data) } /// Parse an identifier from its Base62-encoded string representation. @@ -206,14 +209,14 @@ impl Ksuid { } /// The number of seconds after the UNIX epoch when this identifier was created. - pub fn time(&self) -> Timespec { - EPOCH + Duration::seconds(self.timestamp().into()) + pub fn time(&self) -> OffsetDateTime { + get_epoch() + Duration::seconds(self.timestamp().into()) } /// Set the timestamp of the identifier to the given time. - pub fn set_time(&mut self, time: Timespec) { - let dur = time - EPOCH; - self.set_timestamp(dur.num_seconds() as u32); + pub fn set_time(&mut self, time: OffsetDateTime) { + let dur = time - get_epoch(); + self.set_timestamp(dur.whole_seconds() as u32); } /// The 16-byte random payload. @@ -227,7 +230,8 @@ impl Ksuid { } } -impl Rand for Ksuid { +impl Ksuid { + #[allow(dead_code)] fn rand(rng: &mut R) -> Self { Self::with_payload(rng.gen()) } @@ -283,9 +287,8 @@ mod tests { #[bench] fn bench_gen_lock_rng(b: &mut test::Bencher) { - let mut rng = rand::thread_rng(); b.iter(|| { - rng.gen::() + Ksuid::generate() }) } }