chore: remove AsRef impl from the StringLiteral macro since I don't like that behavior, reorganize it to prevent leaking proc-macro2 / syn / quote
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -2230,6 +2230,13 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "string-literal-macros"
|
name = "string-literal-macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"string-literal-macros-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "string-literal-macros-impl"
|
||||||
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ members = [
|
|||||||
"python-utils-macros-impl",
|
"python-utils-macros-impl",
|
||||||
"string-literal",
|
"string-literal",
|
||||||
"string-literal-macros",
|
"string-literal-macros",
|
||||||
|
"string-literal-macros-impl",
|
||||||
]
|
]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
|
|
||||||
|
|||||||
11
string-literal-macros-impl/Cargo.toml
Normal file
11
string-literal-macros-impl/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "string-literal-macros-impl"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
darling = "0.23.0"
|
||||||
|
proc-macro2 = { workspace = true }
|
||||||
|
quote = { workspace = true }
|
||||||
|
syn = { workspace = true }
|
||||||
71
string-literal-macros-impl/src/lib.rs
Normal file
71
string-literal-macros-impl/src/lib.rs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
use darling::FromDeriveInput;
|
||||||
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
use quote::{ToTokens, quote};
|
||||||
|
use syn::{Ident, LitStr, Path, parse_quote, parse2};
|
||||||
|
|
||||||
|
#[derive(FromDeriveInput)]
|
||||||
|
#[darling(supports(struct_unit))]
|
||||||
|
#[darling(attributes(string_literal))]
|
||||||
|
struct StringLiteral {
|
||||||
|
ident: Ident,
|
||||||
|
value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for StringLiteral {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let Self { ident, value } = self;
|
||||||
|
|
||||||
|
let display_trait: Path = parse_quote!(::std::fmt::Display);
|
||||||
|
let from_trait: Path = parse_quote!(::core::convert::From);
|
||||||
|
let from_str_trait: Path = parse_quote!(::std::str::FromStr);
|
||||||
|
let result: Path = parse_quote!(::core::result::Result);
|
||||||
|
let wrong_literal_error_generic: Path = parse_quote!(::string_literal::WrongLiteralError);
|
||||||
|
let wrong_literal_error: Path = parse_quote!(#wrong_literal_error_generic<#ident>);
|
||||||
|
let write_macro: Path = parse_quote!(::std::write);
|
||||||
|
|
||||||
|
let value_literal = LitStr::new(value.as_str(), Span::call_site());
|
||||||
|
|
||||||
|
let output = quote! {
|
||||||
|
impl #from_trait<&#ident> for &'static str {
|
||||||
|
fn from(unit: &#ident) -> Self {
|
||||||
|
#value_literal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #from_str_trait for #ident {
|
||||||
|
type Err = #wrong_literal_error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> #result<Self, Self::Err> {
|
||||||
|
if s == #value_literal {
|
||||||
|
Ok(Self)
|
||||||
|
} else {
|
||||||
|
Err(#wrong_literal_error_generic { actual: s.to_owned(), expected: #ident })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #display_trait for #ident {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
|
#write_macro!(f, "state_changed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dbg!(&output.to_string());
|
||||||
|
|
||||||
|
tokens.extend(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn string_literal_impl(input: TokenStream) -> TokenStream {
|
||||||
|
let derive_input = match parse2(input) {
|
||||||
|
Ok(derive_input) => derive_input,
|
||||||
|
Err(error) => return error.into_compile_error(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let string_literal = match StringLiteral::from_derive_input(&derive_input) {
|
||||||
|
Ok(string_literal) => string_literal,
|
||||||
|
Err(error) => return error.write_errors(),
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! { #string_literal }
|
||||||
|
}
|
||||||
@@ -8,7 +8,4 @@ license.workspace = true
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
darling = "0.23.0"
|
string-literal-macros-impl = { path = "../string-literal-macros-impl" }
|
||||||
proc-macro2 = { workspace = true }
|
|
||||||
quote = { workspace = true }
|
|
||||||
syn = { workspace = true }
|
|
||||||
|
|||||||
@@ -1,88 +1,6 @@
|
|||||||
use darling::FromDeriveInput;
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::{Span as Span2, TokenStream as TokenStream2};
|
|
||||||
use quote::{ToTokens, quote};
|
|
||||||
use syn::{Ident, LitStr, Path, parse_quote, parse2};
|
|
||||||
|
|
||||||
#[derive(FromDeriveInput)]
|
|
||||||
#[darling(supports(struct_unit))]
|
|
||||||
#[darling(attributes(string_literal))]
|
|
||||||
struct StringLiteral {
|
|
||||||
ident: Ident,
|
|
||||||
value: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for StringLiteral {
|
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
|
||||||
let Self { ident, value } = self;
|
|
||||||
|
|
||||||
dbg!("reached this point");
|
|
||||||
|
|
||||||
let as_ref_trait: Path = parse_quote!(::core::convert::AsRef);
|
|
||||||
let display_trait: Path = parse_quote!(::std::fmt::Display);
|
|
||||||
let from_trait: Path = parse_quote!(::core::convert::From);
|
|
||||||
let from_str_trait: Path = parse_quote!(::std::str::FromStr);
|
|
||||||
let result: Path = parse_quote!(::core::result::Result);
|
|
||||||
let wrong_literal_error_generic: Path = parse_quote!(::string_literal::WrongLiteralError);
|
|
||||||
let wrong_literal_error: Path = parse_quote!(#wrong_literal_error_generic<#ident>);
|
|
||||||
let write_macro: Path = parse_quote!(::std::write);
|
|
||||||
|
|
||||||
let value_literal = LitStr::new(value.as_str(), Span2::call_site());
|
|
||||||
|
|
||||||
dbg!("reached this point");
|
|
||||||
|
|
||||||
let output = quote! {
|
|
||||||
impl #from_trait<#ident> for &'static str {
|
|
||||||
fn from(unit: #ident) -> Self {
|
|
||||||
#value_literal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl #from_str_trait for #ident {
|
|
||||||
type Err = #wrong_literal_error;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> #result<Self, Self::Err> {
|
|
||||||
if s == #value_literal {
|
|
||||||
Ok(Self)
|
|
||||||
} else {
|
|
||||||
Err(#wrong_literal_error_generic { actual: s.to_owned(), expected: #ident })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl #display_trait for #ident {
|
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
|
||||||
#write_macro!(f, "state_changed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl #as_ref_trait<str> for #ident {
|
|
||||||
fn as_ref(&self) -> &str {
|
|
||||||
#value_literal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
dbg!(&output.to_string());
|
|
||||||
|
|
||||||
tokens.extend(output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn string_literal_impl(input: TokenStream2) -> TokenStream2 {
|
|
||||||
let derive_input = match parse2(input) {
|
|
||||||
Ok(derive_input) => derive_input,
|
|
||||||
Err(error) => return error.into_compile_error(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let string_literal = match StringLiteral::from_derive_input(&derive_input) {
|
|
||||||
Ok(string_literal) => string_literal,
|
|
||||||
Err(error) => return error.write_errors(),
|
|
||||||
};
|
|
||||||
|
|
||||||
quote! { #string_literal }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro_derive(StringLiteral, attributes(string_literal))]
|
#[proc_macro_derive(StringLiteral, attributes(string_literal))]
|
||||||
pub fn string_literal(input: TokenStream) -> TokenStream {
|
pub fn string_literal(input: TokenStream) -> TokenStream {
|
||||||
string_literal_impl(input.into()).into()
|
string_literal_macros_impl::string_literal_impl(input.into()).into()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ pub struct WrongLiteralError<S> {
|
|||||||
|
|
||||||
impl<S> Display for WrongLiteralError<S>
|
impl<S> Display for WrongLiteralError<S>
|
||||||
where
|
where
|
||||||
S: AsRef<str>,
|
&'static str: for<'a> From<&'a S>,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let Self { actual, expected } = self;
|
let Self { actual, expected } = self;
|
||||||
let expected_str = expected.as_ref();
|
let expected_str = <&'static str>::from(&expected);
|
||||||
|
|
||||||
write!(f, "expected {expected_str:?} but got {actual:?}")
|
write!(f, "expected {expected_str:?} but got {actual:?}")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user