Remove unused deps, cleanup code, upgrade deps

This commit is contained in:
Michael Pfaff 2021-05-30 02:10:16 -04:00
parent 53e44556df
commit 315677cbfc
Signed by: michael
GPG Key ID: E53B118B12B5C7F9
4 changed files with 53 additions and 365 deletions

81
Cargo.lock generated
View File

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.0.1"
@ -21,28 +23,21 @@ dependencies = [
"libc",
"num-integer",
"num-traits",
"serde",
"time",
"winapi",
]
[[package]]
name = "getrandom"
version = "0.1.16"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
"wasi",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.82"
@ -51,13 +46,12 @@ checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
[[package]]
name = "nrid"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"chrono",
"rand",
"serde",
"thiserror",
"tracing",
]
[[package]]
@ -79,12 +73,6 @@ dependencies = [
"autocfg",
]
[[package]]
name = "pin-project-lite"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827"
[[package]]
name = "ppv-lite86"
version = "0.2.10"
@ -111,11 +99,10 @@ dependencies = [
[[package]]
name = "rand"
version = "0.7.3"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
dependencies = [
"getrandom",
"libc",
"rand_chacha",
"rand_core",
@ -124,9 +111,9 @@ dependencies = [
[[package]]
name = "rand_chacha"
version = "0.2.2"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
dependencies = [
"ppv-lite86",
"rand_core",
@ -134,18 +121,18 @@ dependencies = [
[[package]]
name = "rand_core"
version = "0.5.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
dependencies = [
"rand_core",
]
@ -194,54 +181,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"wasi",
"winapi",
]
[[package]]
name = "tracing"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3"
dependencies = [
"cfg-if",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f"
dependencies = [
"lazy_static",
]
[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"

View File

@ -1,17 +1,16 @@
[package]
name = "nrid"
version = "0.1.1"
version = "0.2.0"
authors = ["Michael Pfaff <michael@pfaff.dev>"]
edition = "2018"
license = "MIT OR Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["serde"]
[dependencies]
chrono = { version = "0.4.11", features = ["serde"] }
rand = { version = "0.7.3" }
#regex = { version = "1.3" }
serde = { version = "1" }
thiserror = { version = "1" }
tracing = { version = "0.1.15" }
chrono = "0.4.19"
rand = "0.8.3"
serde = { version = "1", optional = true }
thiserror = "1"

View File

@ -4,16 +4,24 @@
* Made of a 64-bit seconds, 32-bit nanoseconds, and 32-bit secure-randomness, the NRID is suitable for cases where you want a secure-random, unique identifier like a UUID, but you also want the identifier to be correlated with the time of creation.
*/
#[macro_use]
extern crate tracing;
use core::cmp::max;
use core::cmp::min;
use core::convert::TryFrom;
mod sentence;
/// rules: consist of 12 hex characters, a hyphen, 9 hex characters, a hyphen, and 9 hex characters
#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
pub enum NridError {
#[error("must be a total of 32 characters long")]
WrongLength,
/// Nano Unique Identifier. Stores the seconds since the epoch and nanoseconds since the second, along with 4 bytes of randomness.
#[error("must consist of hexadecimal characters and hyphens")]
IllegalCharacters,
#[error("segment {0} must be {1} hex characters long")]
WrongSegmentLength(u8, u8),
}
/// Nano-Random IDentifier. Stores the seconds since the epoch and nanoseconds since the second, along with 4 bytes of randomness.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C)]
pub struct Nrid {
@ -23,7 +31,7 @@ pub struct Nrid {
}
impl Nrid {
/// Returns a new `ObjectKey` with its timestamp taken from [`Utc::now`].
/// Returns a new `Nrid` with its timestamp taken from [`Utc::now`].
#[inline]
pub fn now() -> Self {
let now = chrono::Utc::now();
@ -63,6 +71,7 @@ impl From<Nrid> for String {
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Nrid {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
@ -72,14 +81,16 @@ impl serde::Serialize for Nrid {
}
}
#[cfg(feature = "serde")]
struct NridVisitor;
#[cfg(feature = "serde")]
impl<'de> serde::de::Visitor<'de> for NridVisitor {
type Value = Nrid;
fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use crate::sentence::ToSentence;
formatter.write_str(&format!("a string that must {}", NRID_RULES.to_sentence()))
formatter.write_str(&format!("a string that must consist of 12 hex characters, a hyphen, 9 hex characters, a hyphen, and 9 hex characters"))
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
@ -93,6 +104,7 @@ impl<'de> serde::de::Visitor<'de> for NridVisitor {
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Nrid {
fn deserialize<D>(deserializer: D) -> Result<Nrid, D::Error>
where
@ -115,28 +127,6 @@ impl From<Nrid> for chrono::DateTime<chrono::Utc> {
}
}
// commented out because it can't be deterministic due to the randomness in a Nrid not being representable in a DateTime.
// impl From<&DateTime<Utc>> for Nrid {
// #[inline]
// fn from(value: &DateTime<Utc>) -> Self {
// // let value = value.borrow();
// Self(
// // we ensure that the seconds value is not negative before casting out of an abundance of safety.
// max(value.timestamp(), 0) as u64,
// value.timestamp_subsec_nanos(),
// )
// }
// }
const NRID_RULES: &'static [&'static str] =
&["consist of 12 hex characters, a hyphen, 9 hex characters, a hyphen, and 9 hex characters"];
const NRID_LEN_RULES: &'static [&'static str] = &["be 32 characters long"];
const NRID_CHARS_RULES: &'static [&'static str] = &["consist of hexadecimal characters and hyphens"];
const SECONDS_RULES: &'static [&'static str] = &["be 12 hex characters"];
const NANOSECONDS_RULES: &'static [&'static str] = &["be 9 hex characters"];
const RANDOMNESS_RULES: &'static [&'static str] = &["be 9 hex characters"];
const SECONDS_LEN: usize = 12;
const NANOSECONDS_LEN: usize = 9;
const RANDOMNESS_LEN: usize = 9;
@ -146,35 +136,23 @@ const NANOSECONDS_OFFSET: usize = SECONDS_OFFSET+SECONDS_LEN+1;
const RANDOMNESS_OFFSET: usize = NANOSECONDS_OFFSET+NANOSECONDS_LEN+1;
impl TryFrom<&str> for Nrid {
type Error = ValidationError;
type Error = NridError;
fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
let value_len = value.len();
if value_len != (SECONDS_LEN + 1 + NANOSECONDS_LEN + 1 + RANDOMNESS_LEN) {
return Err(ValidationError::Rules {
rules: NRID_LEN_RULES,
offending_segment: value.to_string(),
}
.into());
return Err(NridError::WrongLength);
}
for (i, c) in value.chars().enumerate() {
if i == NANOSECONDS_OFFSET-1 || i == RANDOMNESS_OFFSET-1 {
if c != '-' {
return Err(ValidationError::Rules {
rules: NRID_CHARS_RULES,
offending_segment: c.to_string(),
}
.into());
return Err(NridError::IllegalCharacters);
}
} else {
if !char::is_ascii_hexdigit(&c) {
return Err(ValidationError::Rules {
rules: NRID_CHARS_RULES,
offending_segment: c.to_string(),
}
.into());
return Err(NridError::IllegalCharacters);
}
}
}
@ -192,110 +170,31 @@ impl TryFrom<&str> for Nrid {
nanoseconds: nsec,
randomness: rand,
}),
Err(err) => {
trace!(error = ?err, "parse randomness failed");
return Err(ValidationError::Rules {
rules: RANDOMNESS_RULES,
offending_segment: rand.to_string(),
}
.into());
Err(_) => {
return Err(NridError::WrongSegmentLength(3, 9));
}
}
}
Err(err) => {
trace!(error = ?err, "parse nanoseconds failed");
return Err(ValidationError::Rules {
rules: NANOSECONDS_RULES,
offending_segment: nsec.to_string(),
}
.into());
Err(_) => {
return Err(NridError::WrongSegmentLength(2, 9));
}
}
}
Err(err) => {
trace!(error = ?err, "parse seconds failed");
return Err(ValidationError::Rules {
rules: SECONDS_RULES,
offending_segment: sec.to_string(),
}
.into());
Err(_) => {
return Err(NridError::WrongSegmentLength(1, 12));
}
}
}
}
impl core::str::FromStr for Nrid {
type Err = ValidationError;
type Err = NridError;
fn from_str(value: &str) -> std::result::Result<Self, Self::Err> {
Self::try_from(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum ValidationError {
/// Length of input was not as expected.
LengthEqual {
/// The expected input length.
expected: usize,
/// The input segment that failed validation.
offending_segment: String,
},
/// Length of input was greater than expected.
LengthMax {
/// The maximum expected input length.
max: usize,
/// The input segment that failed validation.
offending_segment: String,
},
/// Length of input was less than expected
LengthMin {
/// The minimum expected input length.
min: usize,
/// The input segment that failed validation.
offending_segment: String,
},
/// Input failed to match rules.
Rules {
/// The rules the input must follow.
rules: &'static [&'static str],
/// The input segment that failed validation.
offending_segment: String,
},
}
impl std::fmt::Display for ValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
use crate::sentence::ToSentence;
match self {
Self::LengthEqual {
expected,
offending_segment,
} => write!(f, "`{}` is not equal to {}", offending_segment, expected),
Self::LengthMax {
max,
offending_segment,
} => write!(f, "`{}` is longer than {}", offending_segment, max),
Self::LengthMin {
min,
offending_segment,
} => write!(f, "`{}` is shorter than {}", offending_segment, min),
Self::Rules {
rules,
offending_segment,
} => write!(
f,
"`{}` must {} and fails one or more",
offending_segment,
rules.to_sentence()
),
}
}
}
#[cfg(test)]
mod test {
use core::convert::TryFrom;

View File

@ -1,159 +0,0 @@
/*!
* Provides traits and helpers for generating and manipulating written lanuage constructs
*/
/// A type that can be compiled into a sentence.
pub trait ToSentence {
/// Sentencifies self. The result should be suitable to be placed within a sentence.
fn to_sentence(&self) -> String;
/// Sentencifies self, upper-casing the first letter and adding a period to the end. Using this is discouraged due to its lack of flexibility (i.e. needing alternate punctuation or a lowercase first letter).
fn to_sentence_finalize(&self) -> String {
let s = self.to_sentence();
let mut c = s.chars();
match s.len() {
0 => format!(""),
1 => format!("{}.", s.to_uppercase()),
_ => format!("{}{}.", c.nth(0).unwrap().to_uppercase(), c.as_str()),
}
}
}
impl<'a, T> ToSentence for T where T: AsRef<[&'a str]> {
fn to_sentence(&self) -> String {
let s = self.as_ref();
let len = s.len();
let mut str = String::new();
for (i, seg) in s.iter().map(|s| s.as_ref()).enumerate() {
if i == 0 {
str.push_str(seg);
} else if i == len-1 {
if len == 2 {
str.push_str(&format!(" and {}", seg));
} else {
str.push_str(&format!(", and {}", seg));
}
} else {
str.push_str(&format!(", {}", seg));
}
}
str
}
}
// impl<T> ToSentence for T where T: AsRef<[String]> {
// fn to_sentence(&self) -> String {
// let s = self.as_ref();
// let len = s.len();
// let mut str = String::new();
// for (i, seg) in s.iter().map(|s| s.as_ref()).enumerate() {
// if i == 0 {
// str.push_str(seg);
// } else if i == len {
// if len == 2 {
// str.push_str(&format!(" and {}", seg));
// } else {
// str.push_str(&format!(", and {}", seg));
// }
// } else {
// str.push_str(&format!(", {}", seg));
// }
// }
// str
// }
// }
#[cfg(test)]
mod test {
use super::ToSentence;
const STRING_SLICE_A: &'static [&'static str] = &[
"a",
];
const STRING_SLICE_B: &'static [&'static str] = &[
"a",
"b",
];
const STRING_SLICE_C: &'static [&'static str] = &[
"a",
"b",
"c",
"d",
"e",
"f",
"g",
];
#[test]
fn str_slice_to_sentence() {
assert_eq!(STRING_SLICE_A.to_sentence(), "a");
assert_eq!(STRING_SLICE_B.to_sentence(), "a and b");
assert_eq!(STRING_SLICE_C.to_sentence(), "a, b, c, d, e, f, and g");
}
#[test]
fn str_slice_to_sentence_finalize() {
assert_eq!(STRING_SLICE_A.to_sentence_finalize(), "A.");
assert_eq!(STRING_SLICE_B.to_sentence_finalize(), "A and b.");
assert_eq!(STRING_SLICE_C.to_sentence_finalize(), "A, b, c, d, e, f, and g.");
}
#[test]
fn string_vec_to_sentence() {
let vec: Vec<String> = vec!{
"a".to_owned(),
};
assert_eq!(vec.iter().map(|e| e.as_ref()).collect::<Vec<&str>>().to_sentence(), "a");
let vec: Vec<String> = vec!{
"a".to_owned(),
"b".to_owned(),
};
assert_eq!(vec.iter().map(|e| e.as_ref()).collect::<Vec<&str>>().to_sentence(), "a and b");
let vec: Vec<String> = vec!{
"a".to_owned(),
"b".to_owned(),
"c".to_owned(),
"d".to_owned(),
"e".to_owned(),
"f".to_owned(),
"g".to_owned(),
};
assert_eq!(vec.iter().map(|e| e.as_ref()).collect::<Vec<&str>>().to_sentence(), "a, b, c, d, e, f, and g");
}
#[test]
fn string_vec_to_sentence_finalize() {
let vec: Vec<String> = vec!{
"a".to_owned(),
};
assert_eq!(vec.iter().map(|e| e.as_ref()).collect::<Vec<&str>>().to_sentence_finalize(), "A.");
let vec: Vec<String> = vec!{
"a".to_owned(),
"b".to_owned(),
};
assert_eq!(vec.iter().map(|e| e.as_ref()).collect::<Vec<&str>>().to_sentence_finalize(), "A and b.");
let vec: Vec<String> = vec!{
"a".to_owned(),
"b".to_owned(),
"c".to_owned(),
"d".to_owned(),
"e".to_owned(),
"f".to_owned(),
"g".to_owned(),
};
assert_eq!(vec.iter().map(|e| e.as_ref()).collect::<Vec<&str>>().to_sentence_finalize(), "A, b, c, d, e, f, and g.");
}
}