Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #543 from QnnOkabayashi/impl-uuid-macro
Impl UUID macro
- Loading branch information
Showing
11 changed files
with
330 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
use uuid::{uuid, Uuid}; | ||
|
||
const _: Uuid = uuid!(""); | ||
const _: Uuid = uuid!("!"); | ||
const _: Uuid = uuid!("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45"); | ||
const _: Uuid = uuid!("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4"); | ||
const _: Uuid = uuid!("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4"); | ||
const _: Uuid = uuid!("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4"); | ||
const _: Uuid = uuid!("F9168C5E-CEB2-4faa"); | ||
const _: Uuid = uuid!("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4"); | ||
const _: Uuid = uuid!("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4"); | ||
const _: Uuid = uuid!("01020304-1112-2122-3132-41424344"); | ||
const _: Uuid = uuid!("67e5504410b1426f9247bb680e5fe0c88"); | ||
const _: Uuid = uuid!("67e5504410b1426f9247bb680e5fe0cg8"); | ||
const _: Uuid = uuid!("67e5504410b1426%9247bb680e5fe0c8"); | ||
|
||
// Test error reporting | ||
const _: Uuid = uuid!("67e5504410b1426f9247bb680e5fe0c"); | ||
const _: Uuid = uuid!("67e550X410b1426f9247bb680e5fe0cd"); | ||
const _: Uuid = uuid!("67e550-4105b1426f9247bb680e5fe0c"); | ||
const _: Uuid = uuid!("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4"); | ||
|
||
|
||
const _: Uuid = uuid!("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4"); | ||
const _: Uuid = uuid!("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4"); | ||
const _: Uuid = uuid!("01020304-1112-2122-3132-41424344"); | ||
const _: Uuid = uuid!("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4"); | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
error: invalid length: expected one of [36, 32], found 0 | ||
--> benches/macros/invalid_parse.rs:3:23 | ||
| | ||
3 | const _: Uuid = uuid!(""); | ||
| ^^ | ||
|
||
error: invalid length: expected one of [36, 32], found 1 | ||
--> benches/macros/invalid_parse.rs:4:23 | ||
| | ||
4 | const _: Uuid = uuid!("!"); | ||
| ^^^ | ||
|
||
error: invalid length: expected one of [36, 32], found 37 | ||
--> benches/macros/invalid_parse.rs:5:23 | ||
| | ||
5 | const _: Uuid = uuid!("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45"); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: invalid length: expected one of [36, 32], found 35 | ||
--> benches/macros/invalid_parse.rs:6:23 | ||
| | ||
6 | const _: Uuid = uuid!("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4"); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: invalid character: expected an optional prefix of `urn:uuid:` followed by 0123456789abcdefABCDEF-, found G at 20 | ||
--> benches/macros/invalid_parse.rs:7:44 | ||
| | ||
7 | const _: Uuid = uuid!("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4"); | ||
| ^ | ||
|
||
error: invalid number of groups: expected one of [1, 5], found 4 | ||
--> benches/macros/invalid_parse.rs:8:23 | ||
| | ||
8 | const _: Uuid = uuid!("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4"); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: invalid length: expected one of [36, 32], found 18 | ||
--> benches/macros/invalid_parse.rs:9:23 | ||
| | ||
9 | const _: Uuid = uuid!("F9168C5E-CEB2-4faa"); | ||
| ^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: invalid character: expected an optional prefix of `urn:uuid:` followed by 0123456789abcdefABCDEF-, found X at 18 | ||
--> benches/macros/invalid_parse.rs:10:42 | ||
| | ||
10 | const _: Uuid = uuid!("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4"); | ||
| ^ | ||
|
||
error: invalid group length: expected 4, found 3 in group 1 | ||
--> benches/macros/invalid_parse.rs:11:33 | ||
| | ||
11 | const _: Uuid = uuid!("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4"); | ||
| ^^^ | ||
|
||
error: invalid group length: expected 12, found 8 in group 4 | ||
--> benches/macros/invalid_parse.rs:12:48 | ||
| | ||
12 | const _: Uuid = uuid!("01020304-1112-2122-3132-41424344"); | ||
| ^^^^^^^^ | ||
|
||
error: invalid length: expected one of [36, 32], found 33 | ||
--> benches/macros/invalid_parse.rs:13:23 | ||
| | ||
13 | const _: Uuid = uuid!("67e5504410b1426f9247bb680e5fe0c88"); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: invalid length: expected one of [36, 32], found 33 | ||
--> benches/macros/invalid_parse.rs:14:23 | ||
| | ||
14 | const _: Uuid = uuid!("67e5504410b1426f9247bb680e5fe0cg8"); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: invalid character: expected an optional prefix of `urn:uuid:` followed by 0123456789abcdefABCDEF-, found % at 15 | ||
--> benches/macros/invalid_parse.rs:15:39 | ||
| | ||
15 | const _: Uuid = uuid!("67e5504410b1426%9247bb680e5fe0c8"); | ||
| ^ | ||
|
||
error: invalid length: expected one of [36, 32], found 31 | ||
--> benches/macros/invalid_parse.rs:18:23 | ||
| | ||
18 | const _: Uuid = uuid!("67e5504410b1426f9247bb680e5fe0c"); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: invalid character: expected an optional prefix of `urn:uuid:` followed by 0123456789abcdefABCDEF-, found X at 6 | ||
--> benches/macros/invalid_parse.rs:19:30 | ||
| | ||
19 | const _: Uuid = uuid!("67e550X410b1426f9247bb680e5fe0cd"); | ||
| ^ | ||
|
||
error: invalid group length: expected 8, found 6 in group 0 | ||
--> benches/macros/invalid_parse.rs:20:24 | ||
| | ||
20 | const _: Uuid = uuid!("67e550-4105b1426f9247bb680e5fe0c"); | ||
| ^^^^^^ | ||
|
||
error: invalid group length: expected 4, found 5 in group 3 | ||
--> benches/macros/invalid_parse.rs:21:43 | ||
| | ||
21 | const _: Uuid = uuid!("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4"); | ||
| ^^^^^ | ||
|
||
error: invalid length: expected one of [36, 32], found 35 | ||
--> benches/macros/invalid_parse.rs:24:23 | ||
| | ||
24 | const _: Uuid = uuid!("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4"); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: invalid character: expected an optional prefix of `urn:uuid:` followed by 0123456789abcdefABCDEF-, found G at 20 | ||
--> benches/macros/invalid_parse.rs:25:44 | ||
| | ||
25 | const _: Uuid = uuid!("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4"); | ||
| ^ | ||
|
||
error: invalid group length: expected 12, found 8 in group 4 | ||
--> benches/macros/invalid_parse.rs:26:48 | ||
| | ||
26 | const _: Uuid = uuid!("01020304-1112-2122-3132-41424344"); | ||
| ^^^^^^^^ | ||
|
||
error: invalid number of groups: expected one of [1, 5], found 4 | ||
--> benches/macros/invalid_parse.rs:27:23 | ||
| | ||
27 | const _: Uuid = uuid!("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4"); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
use ::uuid::{uuid as id, Uuid as Id}; | ||
|
||
mod uuid { | ||
struct MyType; | ||
} | ||
|
||
struct Uuid; | ||
|
||
const _: Id = id!("67e55044-10b1-426f-9247-bb680e5fe0c8"); | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
use uuid::{uuid, Uuid}; | ||
|
||
const _: Uuid = uuid!("00000000000000000000000000000000"); | ||
const _: Uuid = uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8"); | ||
const _: Uuid = uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8"); | ||
const _: Uuid = uuid!("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4"); | ||
const _: Uuid = uuid!("67e5504410b1426f9247bb680e5fe0c8"); | ||
const _: Uuid = uuid!("01020304-1112-2122-3132-414243444546"); | ||
const _: Uuid = uuid!("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8"); | ||
|
||
// Nil | ||
const _: Uuid = uuid!("00000000000000000000000000000000"); | ||
const _: Uuid = uuid!("00000000-0000-0000-0000-000000000000"); | ||
|
||
// valid hyphenated | ||
const _: Uuid = uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8"); | ||
// valid short | ||
const _: Uuid = uuid!("67e5504410b1426f9247bb680e5fe0c8"); | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,6 @@ edition = "2018" | |
proc-macro = true | ||
|
||
[dependencies] | ||
syn = "1.0.80" | ||
quote = "1.0.10" | ||
proc-macro2 = "1.0.29" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,81 @@ | ||
use std; | ||
use proc_macro::TokenStream; | ||
use proc_macro2::TokenStream as TokenStream2; | ||
use quote::{quote, quote_spanned}; | ||
use std::fmt; | ||
use syn::spanned::Spanned; | ||
|
||
#[cfg(any(feature = "std", test))] | ||
#[macro_use] | ||
extern crate std; | ||
|
||
#[cfg(all(not(feature = "std"), not(test)))] | ||
#[macro_use] | ||
extern crate core as std; | ||
|
||
#[path = "../../shared/error.rs"] | ||
#[allow(dead_code)] | ||
mod error; | ||
|
||
#[path = "../../shared/parser.rs"] | ||
#[allow(dead_code)] | ||
mod parser; | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
#[test] | ||
fn it_works() { | ||
assert_eq!(2 + 2, 4); | ||
#[proc_macro] | ||
pub fn parse_lit(input: TokenStream) -> TokenStream { | ||
build_uuid(input.clone()).unwrap_or_else(|e| { | ||
let msg = e.to_string(); | ||
let ts = TokenStream2::from(input); | ||
let span = match e { | ||
Error::UuidParse(error::Error( | ||
error::ErrorKind::InvalidCharacter { index, .. }, | ||
)) => { | ||
let mut s = proc_macro2::Literal::string(""); | ||
s.set_span(ts.span()); | ||
s.subspan(index + 1..=index + 1).unwrap() | ||
} | ||
Error::UuidParse(error::Error( | ||
error::ErrorKind::InvalidGroupLength { found, group, .. }, | ||
)) => { | ||
let start = | ||
parser::GROUP_LENS.iter().take(group).sum::<usize>() | ||
+ group | ||
+ 1; | ||
let mut s = proc_macro2::Literal::string(""); | ||
s.set_span(ts.span()); | ||
s.subspan(start..start + found).unwrap() | ||
} | ||
_ => ts.span(), | ||
}; | ||
TokenStream::from(quote_spanned! {span=> | ||
compile_error!(#msg) | ||
}) | ||
}) | ||
} | ||
|
||
enum Error { | ||
NonStringLiteral, | ||
UuidParse(error::Error), | ||
} | ||
|
||
impl fmt::Display for Error { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
match *self { | ||
Error::NonStringLiteral => f.write_str("expected string literal"), | ||
Error::UuidParse(ref e) => write!(f, "{}", e), | ||
} | ||
} | ||
} | ||
|
||
fn build_uuid(input: TokenStream) -> Result<TokenStream, Error> { | ||
let string = match syn::parse::<syn::Lit>(input) { | ||
Ok(syn::Lit::Str(literal)) => literal.value(), | ||
_ => return Err(Error::NonStringLiteral), | ||
}; | ||
|
||
let bytes = parser::parse_str(&string).map_err(Error::UuidParse)?; | ||
|
||
let tokens = bytes | ||
.iter() | ||
.map(|byte| quote! { #byte, }) | ||
.collect::<TokenStream2>(); | ||
|
||
Ok(quote! {[#tokens]}.into()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/// Parse [`Uuid`][uuid::Uuid]s from string literals at compile time. | ||
/// ## Usage | ||
/// This macro transforms the string literal representation of a | ||
/// [`Uuid`][uuid::Uuid] into the bytes representation, raising a compilation | ||
/// error if it cannot properly be parsed. | ||
/// | ||
/// ## Examples | ||
/// Setting a global constant: | ||
/// ``` | ||
/// # use uuid::{uuid, Uuid}; | ||
/// pub const SCHEMA_ATTR_CLASS: Uuid = uuid!("00000000-0000-0000-0000-ffff00000000"); | ||
/// pub const SCHEMA_ATTR_UUID: Uuid = uuid!("00000000-0000-0000-0000-ffff00000001"); | ||
/// pub const SCHEMA_ATTR_NAME: Uuid = uuid!("00000000-0000-0000-0000-ffff00000002"); | ||
/// ``` | ||
/// Defining a local variable: | ||
/// ``` | ||
/// # use uuid::{uuid, Uuid}; | ||
/// let uuid: Uuid = uuid!("urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4"); | ||
/// ``` | ||
/// ## Compilation Failures | ||
/// Invalid UUIDs are rejected: | ||
/// ```ignore | ||
/// # use uuid::{uuid, Uuid}; | ||
/// let uuid: Uuid = uuid!("F9168C5E-ZEB2-4FAA-B6BF-329BF39FA1E4"); | ||
/// ``` | ||
/// Provides the following compilation error: | ||
/// ```txt | ||
/// error: invalid character: expected an optional prefix of `urn:uuid:` followed by 0123456789abcdefABCDEF-, found Z at 9 | ||
/// | | ||
/// | let id: Uuid = uuid!("F9168C5E-ZEB2-4FAA-B6BF-329BF39FA1E4"); | ||
/// | ^ | ||
/// ``` | ||
/// Tokens that aren't string literals are also rejected: | ||
/// ```ignore | ||
/// # use uuid::{uuid, Uuid}; | ||
/// let uuid_str: &str = "550e8400e29b41d4a716446655440000"; | ||
/// let uuid: Uuid = uuid!(uuid_str); | ||
/// ``` | ||
/// Provides the following compilation error: | ||
/// ```txt | ||
/// error: expected string literal | ||
/// | | ||
/// | let uuid: Uuid = uuid!(uuid_str); | ||
/// | ^^^^^^^^ | ||
/// ``` | ||
/// | ||
/// [uuid::Uuid]: https://docs.rs/uuid/*/uuid/struct.Uuid.html | ||
#[macro_export] | ||
macro_rules! uuid { | ||
($uuid:tt) => {{ | ||
$crate::Uuid::from_bytes($crate::uuid_macros::parse_lit!($uuid)) | ||
}}; | ||
} |