Skip to content

Commit 10aa504

Browse files
feat: Support typeid v0.3 spec
1 parent c8cf8c3 commit 10aa504

File tree

9 files changed

+66
-45
lines changed

9 files changed

+66
-45
lines changed

.github/workflows/ci.yaml

-4
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ jobs:
1414
with:
1515
toolchain: stable
1616
- run: cargo test --all-features
17-
env:
18-
RUSTFLAGS: "--cfg uuid_unstable"
1917
msrv:
2018
name: "Build / MSRV"
2119
runs-on: ubuntu-latest
@@ -25,5 +23,3 @@ jobs:
2523
with:
2624
toolchain: 1.60.0
2725
- run: cargo +1.60.0 build --all-features --manifest-path tests/smoke_test/Cargo.toml
28-
env:
29-
RUSTFLAGS: "--cfg uuid_unstable"

strong_id/Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ strong_id_macros = { version = "=0.3.0", path = "../strong_id_macros" }
3030
bitvec = { version = "1", default-features = false, features = ["atomic", "alloc"] }
3131
serde = { version = "1.0", optional = true, default-features = false, features = ["std"] }
3232
thiserror = "1.0"
33-
uuid = { version = "1.4", default-features = false, features = ["std"], optional = true }
33+
uuid = { version = "1.6", default-features = false, features = ["std"], optional = true }
3434

3535
[dev-dependencies]
3636
serde_json = "1.0"
@@ -58,6 +58,7 @@ uuid-v8 = ["strong_id_macros/uuid-v8", "uuid?/v8"]
5858
# note: the TypeID spec does not allow delimited prefixes, so this should be used alongside
5959
# `default-features = false`
6060
typeid = [
61+
"delimited",
6162
"uuid",
6263
"uuid-v7",
6364
]
@@ -77,7 +78,6 @@ all = [
7778
]
7879

7980
[package.metadata.docs.rs]
80-
rustc-args = ["--cfg", "uuid_unstable"]
81-
rustdoc-args = ["--cfg", "docsrs", "--cfg", "uuid_unstable"]
81+
rustdoc-args = ["--cfg", "docsrs"]
8282
targets = ["x86_64-unknown-linux-gnu"]
8383
all-features = true

strong_id/src/dynamic.rs

+23-14
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,25 @@ fn map_prefix<'p, I: Into<Prefix<'p>>>(prefix: I) -> Result<Prefix<'p>, Error> {
1111
return Err(Error::PrefixTooLong(prefix.inner.len()));
1212
}
1313

14-
for b in prefix.inner.as_bytes() {
14+
if prefix.inner.is_empty() {
15+
return Err(Error::PrefixExpected);
16+
}
17+
18+
let underscore = b'_';
19+
let bytes = prefix.inner.as_bytes();
20+
21+
if *bytes.first().unwrap() == underscore || *bytes.last().unwrap() == underscore {
22+
return Err(Error::IncorrectPrefixCharacter(underscore as char));
23+
}
24+
25+
for b in bytes {
1526
if cfg!(feature = "delimited") && *b == b'_' {
1627
continue;
1728
} else if !b.is_ascii_lowercase() {
1829
return Err(Error::IncorrectPrefixCharacter(*b as char));
1930
}
2031
}
21-
if prefix.inner.is_empty() {
22-
return Err(Error::PrefixExpected);
23-
}
32+
2433
Ok(prefix)
2534
}
2635

@@ -322,7 +331,7 @@ impl<'p> DynamicStrongId<'p, Uuid> {
322331
}
323332
}
324333

325-
#[cfg(all(uuid_unstable, feature = "uuid-v6"))]
334+
#[cfg(feature = "uuid-v6")]
326335
#[cfg_attr(docsrs, doc(cfg(feature = "uuid-v6")))]
327336
/// Create a new UUID-backed ID by generating a v6 UUID with a prefix
328337
///
@@ -338,7 +347,7 @@ impl<'p> DynamicStrongId<'p, Uuid> {
338347
})
339348
}
340349

341-
#[cfg(all(uuid_unstable, feature = "uuid-v6"))]
350+
#[cfg(feature = "uuid-v6")]
342351
#[cfg_attr(docsrs, doc(cfg(feature = "uuid-v6")))]
343352
/// Create a new UUID-backed ID by generating a v6 UUID without a prefix
344353
///
@@ -350,7 +359,7 @@ impl<'p> DynamicStrongId<'p, Uuid> {
350359
}
351360
}
352361

353-
#[cfg(all(uuid_unstable, feature = "uuid-v6"))]
362+
#[cfg(feature = "uuid-v6")]
354363
#[cfg_attr(docsrs, doc(cfg(feature = "uuid-v6")))]
355364
/// Create a new UUID-backed ID by generating a v6 UUID with a prefix
356365
///
@@ -362,7 +371,7 @@ impl<'p> DynamicStrongId<'p, Uuid> {
362371
})
363372
}
364373

365-
#[cfg(all(uuid_unstable, feature = "uuid-v6"))]
374+
#[cfg(feature = "uuid-v6")]
366375
#[cfg_attr(docsrs, doc(cfg(feature = "uuid-v6")))]
367376
/// Create a new UUID-backed ID by generating a v6 UUID without a prefix
368377
///
@@ -374,7 +383,7 @@ impl<'p> DynamicStrongId<'p, Uuid> {
374383
}
375384
}
376385

377-
#[cfg(all(uuid_unstable, feature = "uuid-v7"))]
386+
#[cfg(feature = "uuid-v7")]
378387
#[cfg_attr(docsrs, doc(cfg(feature = "uuid-v7")))]
379388
/// Create a new UUID-backed ID by generating a v7 UUID with a prefix
380389
///
@@ -386,7 +395,7 @@ impl<'p> DynamicStrongId<'p, Uuid> {
386395
})
387396
}
388397

389-
#[cfg(all(uuid_unstable, feature = "uuid-v7"))]
398+
#[cfg(feature = "uuid-v7")]
390399
#[cfg_attr(docsrs, doc(cfg(feature = "uuid-v7")))]
391400
/// Create a new UUID-backed ID by generating a v7 UUID without a prefix
392401
///
@@ -398,7 +407,7 @@ impl<'p> DynamicStrongId<'p, Uuid> {
398407
}
399408
}
400409

401-
#[cfg(all(uuid_unstable, feature = "uuid-v7"))]
410+
#[cfg(feature = "uuid-v7")]
402411
#[cfg_attr(docsrs, doc(cfg(feature = "uuid-v7")))]
403412
/// Create a new UUID-backed ID by generating a v7 UUID with a prefix
404413
///
@@ -410,7 +419,7 @@ impl<'p> DynamicStrongId<'p, Uuid> {
410419
})
411420
}
412421

413-
#[cfg(all(uuid_unstable, feature = "uuid-v7"))]
422+
#[cfg(feature = "uuid-v7")]
414423
#[cfg_attr(docsrs, doc(cfg(feature = "uuid-v7")))]
415424
/// Create a new UUID-backed ID by generating a v7 UUID without a prefix
416425
///
@@ -422,7 +431,7 @@ impl<'p> DynamicStrongId<'p, Uuid> {
422431
}
423432
}
424433

425-
#[cfg(all(uuid_unstable, feature = "uuid-v8"))]
434+
#[cfg(feature = "uuid-v8")]
426435
#[cfg_attr(docsrs, doc(cfg(feature = "uuid-v8")))]
427436
/// Create a new UUID-backed ID by generating a v7 UUID with a prefix
428437
///
@@ -434,7 +443,7 @@ impl<'p> DynamicStrongId<'p, Uuid> {
434443
})
435444
}
436445

437-
#[cfg(all(uuid_unstable, feature = "uuid-v8"))]
446+
#[cfg(feature = "uuid-v8")]
438447
#[cfg_attr(docsrs, doc(cfg(feature = "uuid-v8")))]
439448
/// Create a new UUID-backed ID by generating a v7 UUID without a prefix
440449
///

strong_id/src/lib.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -244,24 +244,24 @@ pub trait StrongUuid {
244244
#[cfg_attr(docsrs, doc(cfg(feature = "uuid-v5")))]
245245
fn new_v5(namespace: &Uuid, name: &[u8]) -> Self;
246246

247-
#[cfg(all(uuid_unstable, feature = "uuid-v6"))]
248-
#[cfg_attr(docsrs, doc(cfg(all(uuid_unstable, feature = "uuid-v6"))))]
247+
#[cfg(feature = "uuid-v6")]
248+
#[cfg_attr(docsrs, doc(cfg(all(feature = "uuid-v6"))))]
249249
fn new_v6(ts: uuid::Timestamp, node_id: &[u8; 6]) -> Self;
250250

251-
#[cfg(all(uuid_unstable, feature = "uuid-v6"))]
252-
#[cfg_attr(docsrs, doc(cfg(all(uuid_unstable, feature = "uuid-v6"))))]
251+
#[cfg(feature = "uuid-v6")]
252+
#[cfg_attr(docsrs, doc(cfg(all(feature = "uuid-v6"))))]
253253
fn now_v6(node_id: &[u8; 6]) -> Self;
254254

255-
#[cfg(all(uuid_unstable, feature = "uuid-v7"))]
256-
#[cfg_attr(docsrs, doc(cfg(all(uuid_unstable, feature = "uuid-v7"))))]
255+
#[cfg(feature = "uuid-v7")]
256+
#[cfg_attr(docsrs, doc(cfg(all(feature = "uuid-v7"))))]
257257
fn new_v7(ts: uuid::Timestamp) -> Self;
258258

259-
#[cfg(all(uuid_unstable, feature = "uuid-v7"))]
260-
#[cfg_attr(docsrs, doc(cfg(all(uuid_unstable, feature = "uuid-v7"))))]
259+
#[cfg(feature = "uuid-v7")]
260+
#[cfg_attr(docsrs, doc(cfg(all(feature = "uuid-v7"))))]
261261
fn now_v7() -> Self;
262262

263-
#[cfg(all(uuid_unstable, feature = "uuid-v8"))]
264-
#[cfg_attr(docsrs, doc(cfg(all(uuid_unstable, feature = "uuid-v8"))))]
263+
#[cfg(feature = "uuid-v8")]
264+
#[cfg_attr(docsrs, doc(cfg(all(feature = "uuid-v8"))))]
265265
fn new_v8(buf: [u8; 16]) -> Self;
266266
}
267267

@@ -280,7 +280,7 @@ macro_rules! impl_strong_uint {
280280
if val.len() != encoded_len::<$t>() {
281281
return Err(::strong_id::Error::InvalidLength(encoded_len::<$t>(), val.len()));
282282
}
283-
283+
284284
let mut out = [0; ::core::mem::size_of::<$t>()];
285285
::strong_id::base32::decode(val.as_bytes(), &mut out)?;
286286

strong_id_macros/src/lib.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,17 @@ use quote::quote;
44
use syn::{parse_macro_input, Data, DeriveInput, Fields, LitStr, Type};
55

66
fn assert_prefix_valid(prefix: &str) {
7+
assert!(!prefix.is_empty(), "prefix must be non-empty");
78
assert!(prefix.len() < 64, "prefix is longer than 63 characters");
89

9-
for b in prefix.as_bytes() {
10-
if cfg!(feature = "delimited") && *b == b'_' {
10+
let underscore = b'_';
11+
let bytes = prefix.as_bytes();
12+
13+
assert_ne!(*bytes.first().unwrap(), underscore, "prefix cannot start with an underscore");
14+
assert_ne!(*bytes.last().unwrap(), underscore, "prefix cannot end with an underscore");
15+
16+
for (index, b) in prefix.as_bytes().iter().enumerate() {
17+
if cfg!(feature = "delimited") && *b == underscore && index > 0 {
1118
continue;
1219
}
1320

@@ -194,7 +201,7 @@ pub fn derive_strong_id_uuid(input: proc_macro::TokenStream) -> proc_macro::Toke
194201
quote!()
195202
};
196203

197-
let uuid_v6_impl = if cfg!(all(uuid_unstable, feature = "uuid-v6")) {
204+
let uuid_v6_impl = if cfg!(feature = "uuid-v6") {
198205
quote! {
199206
fn new_v6(ts: ::strong_id::uuid::Timestamp, node_id: &[u8; 6]) -> Self {
200207
Self(::strong_id::uuid::Uuid::new_v6(ts, node_id))
@@ -208,7 +215,7 @@ pub fn derive_strong_id_uuid(input: proc_macro::TokenStream) -> proc_macro::Toke
208215
quote!()
209216
};
210217

211-
let uuid_v7_impl = if cfg!(all(uuid_unstable, feature = "uuid-v7")) {
218+
let uuid_v7_impl = if cfg!(feature = "uuid-v7") {
212219
quote! {
213220
fn new_v7(ts: ::strong_id::uuid::Timestamp) -> Self {
214221
Self(::strong_id::uuid::Uuid::new_v7(ts))
@@ -222,7 +229,7 @@ pub fn derive_strong_id_uuid(input: proc_macro::TokenStream) -> proc_macro::Toke
222229
quote!()
223230
};
224231

225-
let uuid_v8_impl = if cfg!(all(uuid_unstable, feature = "uuid-v8")) {
232+
let uuid_v8_impl = if cfg!(feature = "uuid-v8") {
226233
quote! {
227234
fn new_v8(buf: [u8; 16]) -> Self {
228235
Self(::strong_id::uuid::Uuid::new_v8(buf))

tests/smoke_test/.cargo/config.toml

-2
This file was deleted.

tests/typeid_spec/.cargo/config.toml

-2
This file was deleted.

tests/typeid_spec/Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ edition = "2021"
55
publish = false
66

77
[dependencies]
8-
libtest-mimic = "0.6"
9-
reqwest = { version = "0.11", features = ["blocking", "json"] }
8+
libtest-mimic = "0.7.3"
9+
reqwest = { version = "0.12.4", features = ["blocking", "json"] }
1010
serde = { version = "1.0", features = ["derive"] }
11-
uuid = { version = "1.4.0", features = ["v7"] }
11+
uuid = { version = "1.6.0", features = ["v7"] }
1212

1313
[dependencies.strong_id]
1414
path = "../../strong_id"

tests/typeid_spec/src/main.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ fn fetch_cases<T: Case + DeserializeOwned>() -> Vec<T> {
5353

5454
strong_uuid!(struct NoPrefix(Uuid));
5555
strong_uuid!(struct Prefix(Uuid => "prefix"));
56+
strong_uuid!(struct PrefixUnderscore(Uuid => "pre_fix"));
5657

5758
fn main() {
5859
let valid_cases = fetch_cases::<ValidCase>();
@@ -84,7 +85,7 @@ fn main() {
8485
.chain(valid_cases.into_iter().map(|case| {
8586
Trial::test(format!("valid::static::{}", case.name), move || {
8687
match case.prefix() {
87-
Some(_prefix) => {
88+
Some(prefix) if !prefix.contains('_') => {
8889
let uuid = Uuid::from_str(&case.uuid).unwrap();
8990
// encode
9091
let encoded = Prefix::from(uuid);
@@ -96,6 +97,18 @@ fn main() {
9697
assert_eq!(encoded.to_string(), case.typeid);
9798
assert_eq!(*encoded.id(), uuid);
9899
}
100+
Some(_) => {
101+
let uuid = Uuid::from_str(&case.uuid).unwrap();
102+
// encode
103+
let encoded = PrefixUnderscore::from(uuid);
104+
assert_eq!(encoded.to_string(), case.typeid);
105+
assert_eq!(*encoded.id(), uuid);
106+
107+
// decode
108+
let encoded = PrefixUnderscore::from_str(&case.typeid).unwrap();
109+
assert_eq!(encoded.to_string(), case.typeid);
110+
assert_eq!(*encoded.id(), uuid);
111+
}
99112
None => {
100113
let uuid = Uuid::from_str(&case.uuid).unwrap();
101114
// encode

0 commit comments

Comments
 (0)