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:
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 }
|
||||
}
|
||||
Reference in New Issue
Block a user