mirror of
https://git.proxmox.com/git/proxmox
synced 2025-08-02 19:39:33 +00:00
update to syn 2
This mostly affected attribute parsing (due to the syn::Meta changes). Also creating `DelimSpan`s for custom-built `syn::Attribute`s is a bit... ugly. Upshot: turns out we can drop some helpers in util.rs with the new `syn::Meta` changes. Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
eb1abe45b6
commit
b232b580a0
@ -75,7 +75,7 @@ regex = "1.5"
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_plain = "1.0"
|
||||
syn = { version = "1.0", features = [ "full", "visit-mut" ] }
|
||||
syn = { version = "2", features = [ "full", "visit-mut" ] }
|
||||
tar = "0.4"
|
||||
tokio = "1.6"
|
||||
tokio-openssl = "0.6.1"
|
||||
|
@ -1,8 +1,7 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use syn::{Meta, NestedMeta};
|
||||
use syn::meta::ParseNestedMeta;
|
||||
|
||||
use crate::util::{self, default_false, parse_str_value_to_option, set_bool};
|
||||
use crate::util;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UpdaterFieldAttributes {
|
||||
@ -20,46 +19,42 @@ impl UpdaterFieldAttributes {
|
||||
pub fn from_attributes(input: &mut Vec<syn::Attribute>) -> Self {
|
||||
let mut this = Self::default();
|
||||
|
||||
util::extract_attributes(input, "updater", |attr, meta| this.parse(attr, meta));
|
||||
for attr in std::mem::take(input) {
|
||||
if attr.style != syn::AttrStyle::Outer || !attr.path().is_ident("updater") {
|
||||
input.push(attr);
|
||||
continue;
|
||||
}
|
||||
match attr.parse_nested_meta(|meta| this.parse(meta)) {
|
||||
Ok(()) => (),
|
||||
Err(err) => crate::add_error(err),
|
||||
}
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
fn parse(&mut self, attr: &syn::Attribute, input: NestedMeta) -> Result<(), syn::Error> {
|
||||
match input {
|
||||
NestedMeta::Lit(lit) => bail!(lit => "unexpected literal"),
|
||||
NestedMeta::Meta(meta) => self.parse_meta(attr, meta),
|
||||
}
|
||||
}
|
||||
fn parse(&mut self, meta: ParseNestedMeta<'_>) -> Result<(), syn::Error> {
|
||||
let path = &meta.path;
|
||||
|
||||
fn parse_meta(&mut self, attr: &syn::Attribute, meta: Meta) -> Result<(), syn::Error> {
|
||||
match meta {
|
||||
Meta::Path(ref path) if path.is_ident("skip") => {
|
||||
set_bool(&mut self.skip, path, true);
|
||||
if path.is_ident("skip") {
|
||||
if !meta.input.is_empty() {
|
||||
return Err(meta.error("'skip' attribute does not take any data"));
|
||||
}
|
||||
Meta::NameValue(ref nv) if nv.path.is_ident("type") => {
|
||||
parse_str_value_to_option(&mut self.ty, nv)
|
||||
}
|
||||
Meta::NameValue(m) => bail!(&m => "invalid updater attribute: {:?}", m.path),
|
||||
Meta::List(m) if m.path.is_ident("serde") => {
|
||||
let mut tokens = TokenStream::new();
|
||||
m.paren_token
|
||||
.surround(&mut tokens, |tokens| m.nested.to_tokens(tokens));
|
||||
self.serde.push(syn::Attribute {
|
||||
path: m.path,
|
||||
tokens,
|
||||
..attr.clone()
|
||||
});
|
||||
}
|
||||
Meta::List(m) => bail!(&m => "invalid updater attribute: {:?}", m.path),
|
||||
Meta::Path(m) => bail!(&m => "invalid updater attribute: {:?}", m),
|
||||
util::set_bool(&mut self.skip, path, true);
|
||||
} else if path.is_ident("type") {
|
||||
util::parse_str_value_to_option(&mut self.ty, path, meta.value()?);
|
||||
} else if path.is_ident("serde") {
|
||||
let content: TokenStream = meta.input.parse()?;
|
||||
self.serde.push(syn::parse_quote! { # [ #path #content ] });
|
||||
} else {
|
||||
return Err(meta.error(format!("invalid updater attribute: {path:?}")));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn skip(&self) -> bool {
|
||||
default_false(self.skip.as_ref())
|
||||
util::default_false(self.skip.as_ref())
|
||||
}
|
||||
|
||||
pub fn ty(&self) -> Option<&syn::TypePath> {
|
||||
@ -68,7 +63,7 @@ impl UpdaterFieldAttributes {
|
||||
|
||||
pub fn replace_serde_attributes(&self, attrs: &mut Vec<syn::Attribute>) {
|
||||
if !self.serde.is_empty() {
|
||||
attrs.retain(|attr| !attr.path.is_ident("serde"));
|
||||
attrs.retain(|attr| !attr.path().is_ident("serde"));
|
||||
attrs.extend(self.serde.iter().cloned())
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ pub fn handle_enum(
|
||||
};
|
||||
|
||||
if derives_default {
|
||||
if let Some(attr) = variant.attrs.iter().find(|a| a.path.is_ident("default")) {
|
||||
if let Some(attr) = variant.attrs.iter().find(|a| a.path().is_ident("default")) {
|
||||
if let Some(default_value) = &default_value {
|
||||
error!(attr => "multiple default values defined");
|
||||
error!(default_value => "default previously defined here");
|
||||
|
@ -114,7 +114,7 @@ impl TryFrom<JSONObject> for Schema {
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
span: obj.brace_token.span,
|
||||
span: obj.span(),
|
||||
description,
|
||||
item: SchemaItem::try_extract_from(&mut obj)?,
|
||||
properties: obj
|
||||
|
@ -32,7 +32,7 @@ pub fn handle_struct(attribs: JSONObject, stru: syn::ItemStruct) -> Result<Token
|
||||
handle_newtype_struct(attribs, stru)
|
||||
}
|
||||
syn::Fields::Unnamed(fields) => bail!(
|
||||
fields.paren_token.span,
|
||||
fields.paren_token.span.open(),
|
||||
"api macro does not support tuple structs"
|
||||
),
|
||||
syn::Fields::Named(_) => handle_regular_struct(attribs, stru),
|
||||
|
@ -5,7 +5,8 @@
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::util::AttrArgs;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::Token;
|
||||
|
||||
/// Serde name types.
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
@ -134,19 +135,28 @@ impl TryFrom<&[syn::Attribute]> for ContainerAttrib {
|
||||
let mut this: Self = Default::default();
|
||||
|
||||
for attrib in attributes {
|
||||
if !attrib.path.is_ident("serde") {
|
||||
continue;
|
||||
}
|
||||
let list = match &attrib.meta {
|
||||
syn::Meta::List(list) if list.path.is_ident("serde") => list,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let args: AttrArgs = syn::parse2(attrib.tokens.clone())?;
|
||||
for arg in args.args {
|
||||
if let syn::NestedMeta::Meta(syn::Meta::NameValue(var)) = arg {
|
||||
if var.path.is_ident("rename_all") {
|
||||
let rename_all = RenameAll::try_from(&var.lit)?;
|
||||
if this.rename_all.is_some() && this.rename_all != Some(rename_all) {
|
||||
error!(var.lit => "multiple conflicting 'rename_all' attributes");
|
||||
let args =
|
||||
list.parse_args_with(Punctuated::<syn::Meta, Token![,]>::parse_terminated)?;
|
||||
|
||||
for arg in args {
|
||||
if let syn::Meta::NameValue(var) = arg {
|
||||
if !var.path.is_ident("rename_all") {
|
||||
continue;
|
||||
}
|
||||
match &var.value {
|
||||
syn::Expr::Lit(lit) => {
|
||||
let rename_all = RenameAll::try_from(&lit.lit)?;
|
||||
if this.rename_all.is_some() && this.rename_all != Some(rename_all) {
|
||||
error!(var.value => "multiple conflicting 'rename_all' attributes");
|
||||
}
|
||||
this.rename_all = Some(rename_all);
|
||||
}
|
||||
this.rename_all = Some(rename_all);
|
||||
_ => error!(var.value => "invalid 'rename_all' value type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,30 +175,31 @@ pub struct SerdeAttrib {
|
||||
|
||||
impl SerdeAttrib {
|
||||
pub fn parse_attribute(&mut self, attrib: &syn::Attribute) -> Result<(), syn::Error> {
|
||||
use syn::{Meta, NestedMeta};
|
||||
let list = match &attrib.meta {
|
||||
syn::Meta::List(list) if list.path.is_ident("serde") => list,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
|
||||
if !attrib.path.is_ident("serde") {
|
||||
return Ok(());
|
||||
}
|
||||
let args = list.parse_args_with(Punctuated::<syn::Meta, Token![,]>::parse_terminated)?;
|
||||
|
||||
let args: AttrArgs = syn::parse2(attrib.tokens.clone())?;
|
||||
for arg in args.args {
|
||||
match arg {
|
||||
NestedMeta::Meta(Meta::NameValue(var)) if var.path.is_ident("rename") => {
|
||||
match var.lit {
|
||||
syn::Lit::Str(rename) => {
|
||||
if self.rename.is_some() && self.rename.as_ref() != Some(&rename) {
|
||||
error!(&rename => "multiple conflicting 'rename' attributes");
|
||||
}
|
||||
self.rename = Some(rename);
|
||||
for arg in args {
|
||||
let path = arg.path();
|
||||
if path.is_ident("rename") {
|
||||
match &arg.require_name_value()?.value {
|
||||
syn::Expr::Lit(syn::ExprLit {
|
||||
lit: syn::Lit::Str(rename),
|
||||
..
|
||||
}) => {
|
||||
if self.rename.is_some() && self.rename.as_ref() != Some(rename) {
|
||||
error!(&rename => "multiple conflicting 'rename' attributes");
|
||||
}
|
||||
_ => error!(var.lit => "'rename' value must be a string literal"),
|
||||
self.rename = Some(rename.clone());
|
||||
}
|
||||
value => error!(value => "'rename' value must be a string literal"),
|
||||
}
|
||||
NestedMeta::Meta(Meta::Path(path)) if path.is_ident("flatten") => {
|
||||
self.flatten = true;
|
||||
}
|
||||
_ => continue,
|
||||
} else if path.is_ident("flatten") {
|
||||
arg.require_path_only()?;
|
||||
self.flatten = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ impl JSONValue {
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
JSONValue::Object(obj) => obj.brace_token.span,
|
||||
JSONValue::Object(obj) => obj.span(),
|
||||
JSONValue::Expr(expr) => expr.span(),
|
||||
}
|
||||
}
|
||||
@ -194,7 +194,7 @@ impl TryFrom<JSONValue> for syn::Expr {
|
||||
type Error = syn::Error;
|
||||
fn try_from(value: JSONValue) -> Result<Self, syn::Error> {
|
||||
match value {
|
||||
JSONValue::Object(s) => bail!(s.brace_token.span, "unexpected object"),
|
||||
JSONValue::Object(s) => bail!(s.span(), "unexpected object"),
|
||||
JSONValue::Expr(e) => Ok(e),
|
||||
}
|
||||
}
|
||||
@ -298,7 +298,7 @@ impl Parse for JSONValue {
|
||||
|
||||
/// The "core" of our schema is a json object.
|
||||
pub struct JSONObject {
|
||||
pub brace_token: syn::token::Brace,
|
||||
pub brace_token: Option<syn::token::Brace>,
|
||||
pub elements: HashMap<FieldName, JSONValue>,
|
||||
}
|
||||
|
||||
@ -308,8 +308,7 @@ impl JSONObject {
|
||||
}
|
||||
|
||||
fn parse_elements(input: ParseStream) -> syn::Result<HashMap<FieldName, JSONValue>> {
|
||||
let map_elems: Punctuated<JSONMapEntry, Token![,]> =
|
||||
input.parse_terminated(JSONMapEntry::parse)?;
|
||||
let map_elems = input.parse_terminated(JSONMapEntry::parse, Token![,])?;
|
||||
let mut elems = HashMap::with_capacity(map_elems.len());
|
||||
for c in map_elems {
|
||||
if elems.insert(c.key.clone(), c.value).is_some() {
|
||||
@ -321,9 +320,7 @@ impl JSONObject {
|
||||
|
||||
pub fn parse_inner(input: ParseStream) -> syn::Result<Self> {
|
||||
Ok(Self {
|
||||
brace_token: syn::token::Brace {
|
||||
span: Span::call_site(),
|
||||
},
|
||||
brace_token: None,
|
||||
elements: Self::parse_elements(input)?,
|
||||
})
|
||||
}
|
||||
@ -333,7 +330,7 @@ impl Parse for JSONObject {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let content;
|
||||
Ok(Self {
|
||||
brace_token: syn::braced!(content in input),
|
||||
brace_token: Some(syn::braced!(content in input)),
|
||||
elements: Self::parse_elements(&content)?,
|
||||
})
|
||||
}
|
||||
@ -355,7 +352,10 @@ impl std::ops::DerefMut for JSONObject {
|
||||
|
||||
impl JSONObject {
|
||||
pub fn span(&self) -> Span {
|
||||
self.brace_token.span
|
||||
match &self.brace_token {
|
||||
Some(brace) => brace.span.join(),
|
||||
None => Span::call_site(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_required_element(&mut self, name: &str) -> Result<JSONValue, syn::Error> {
|
||||
@ -415,12 +415,20 @@ pub fn get_doc_comments(attributes: &[syn::Attribute]) -> Result<(String, Span),
|
||||
continue;
|
||||
}
|
||||
|
||||
if attr.path.is_ident("doc") {
|
||||
let doc: BareAssignment<syn::LitStr> = syn::parse2(attr.tokens.clone())?;
|
||||
let nv = match &attr.meta {
|
||||
syn::Meta::NameValue(nv) if nv.path.is_ident("doc") => &nv.value,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
if let syn::Expr::Lit(syn::ExprLit {
|
||||
lit: syn::Lit::Str(doc),
|
||||
..
|
||||
}) = nv
|
||||
{
|
||||
if !doc_comment.is_empty() {
|
||||
doc_comment.push('\n');
|
||||
}
|
||||
doc_comment.push_str(doc.content.value().trim());
|
||||
doc_comment.push_str(doc.value().trim());
|
||||
}
|
||||
}
|
||||
|
||||
@ -554,7 +562,7 @@ pub fn make_ident_path(ident: Ident) -> syn::Path {
|
||||
pub fn make_path(span: Span, leading_colon: bool, path: &[&str]) -> syn::Path {
|
||||
syn::Path {
|
||||
leading_colon: if leading_colon {
|
||||
Some(syn::token::Colon2 {
|
||||
Some(syn::token::PathSep {
|
||||
spans: [span, span],
|
||||
})
|
||||
} else {
|
||||
@ -570,30 +578,6 @@ pub fn make_path(span: Span, leading_colon: bool, path: &[&str]) -> syn::Path {
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper to do basically what `parse_macro_input!` does, except the macro expects a
|
||||
/// `TokenStream_1`, and we always have a `TokenStream` from `proc_macro2`.
|
||||
pub struct AttrArgs {
|
||||
pub paren_token: syn::token::Paren,
|
||||
pub args: Punctuated<syn::NestedMeta, Token![,]>,
|
||||
}
|
||||
|
||||
impl Parse for AttrArgs {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let content;
|
||||
Ok(Self {
|
||||
paren_token: syn::parenthesized!(content in input),
|
||||
args: Punctuated::parse_terminated(&content)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for AttrArgs {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.paren_token
|
||||
.surround(tokens, |inner| self.args.to_tokens(inner));
|
||||
}
|
||||
}
|
||||
|
||||
/// Join an iterator over `Display` values.
|
||||
pub fn join<T>(separator: &str, iter: impl Iterator<Item = T>) -> String
|
||||
where
|
||||
@ -701,7 +685,7 @@ pub fn derives_trait(attributes: &[syn::Attribute], ident: &str) -> bool {
|
||||
|
||||
/// Iterator over the types found in `#[derive(...)]` attributes.
|
||||
pub struct DerivedItems<'a> {
|
||||
current: Option<<Punctuated<syn::NestedMeta, Token![,]> as IntoIterator>::IntoIter>,
|
||||
current: Option<<Punctuated<syn::Meta, Token![,]> as IntoIterator>::IntoIter>,
|
||||
attributes: std::slice::Iter<'a, syn::Attribute>,
|
||||
}
|
||||
|
||||
@ -713,7 +697,7 @@ impl<'a> Iterator for DerivedItems<'a> {
|
||||
if let Some(current) = &mut self.current {
|
||||
loop {
|
||||
match current.next() {
|
||||
Some(syn::NestedMeta::Meta(syn::Meta::Path(path))) => return Some(path),
|
||||
Some(syn::Meta::Path(path)) => return Some(path),
|
||||
Some(_) => continue,
|
||||
None => {
|
||||
self.current = None;
|
||||
@ -728,15 +712,16 @@ impl<'a> Iterator for DerivedItems<'a> {
|
||||
continue;
|
||||
}
|
||||
|
||||
match attr.parse_meta() {
|
||||
Ok(syn::Meta::List(list)) if list.path.is_ident("derive") => {
|
||||
self.current = Some(list.nested.into_iter());
|
||||
match &attr.meta {
|
||||
syn::Meta::List(list) if list.path.is_ident("derive") => {
|
||||
if let Ok(items) =
|
||||
list.parse_args_with(Punctuated::<syn::Meta, Token![,]>::parse_terminated)
|
||||
{
|
||||
self.current = Some(items.into_iter());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// ignore anything that isn't a `derive(...)` attribute
|
||||
Ok(_) => continue,
|
||||
// ignore parse errors
|
||||
Err(_) => continue,
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -756,102 +741,71 @@ where
|
||||
continue;
|
||||
}
|
||||
|
||||
if !attr.path.is_ident("derive") {
|
||||
attributes.push(attr);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut args: AttrArgs = match syn::parse2(attr.tokens.clone()) {
|
||||
Ok(args) => args,
|
||||
Err(_) => {
|
||||
// if we can't parse it, we don't care
|
||||
attributes.push(attr);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
for arg in std::mem::take(&mut args.args).into_pairs() {
|
||||
match arg {
|
||||
Pair::Punctuated(item, punct) => {
|
||||
if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = &item {
|
||||
if !func(path) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
args.args.push_value(item);
|
||||
args.args.push_punct(punct);
|
||||
}
|
||||
Pair::End(item) => {
|
||||
if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = &item {
|
||||
if !func(path) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
args.args.push_value(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !args.args.is_empty() {
|
||||
attr.tokens = args.into_token_stream();
|
||||
attributes.push(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_attribute(span: Span, path: syn::Path, tokens: TokenStream) -> syn::Attribute {
|
||||
syn::Attribute {
|
||||
pound_token: syn::token::Pound { spans: [span] },
|
||||
style: syn::AttrStyle::Outer,
|
||||
bracket_token: syn::token::Bracket { span },
|
||||
path,
|
||||
tokens,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_derive_attribute(span: Span, content: TokenStream) -> syn::Attribute {
|
||||
make_attribute(
|
||||
span,
|
||||
make_ident_path(Ident::new("derive", span)),
|
||||
quote::quote! { (#content) },
|
||||
)
|
||||
}
|
||||
|
||||
/// Extract (remove) an attribute from a list and run a callback on its parameters.
|
||||
pub fn extract_attributes(
|
||||
attributes: &mut Vec<syn::Attribute>,
|
||||
attr_name: &str,
|
||||
mut func_matching: impl FnMut(&syn::Attribute, syn::NestedMeta) -> Result<(), syn::Error>,
|
||||
) {
|
||||
for attr in std::mem::take(attributes) {
|
||||
if attr.style != syn::AttrStyle::Outer {
|
||||
attributes.push(attr);
|
||||
continue;
|
||||
}
|
||||
|
||||
let meta = match attr.parse_meta() {
|
||||
Ok(meta) => meta,
|
||||
Err(err) => {
|
||||
crate::add_error(err);
|
||||
attributes.push(attr);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let list = match meta {
|
||||
syn::Meta::List(list) if list.path.is_ident(attr_name) => list,
|
||||
let list = match &mut attr.meta {
|
||||
syn::Meta::List(list) if list.path.is_ident("derive") => list,
|
||||
_ => {
|
||||
attributes.push(attr);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
for entry in list.nested {
|
||||
match func_matching(&attr, entry) {
|
||||
Ok(()) => (),
|
||||
Err(err) => crate::add_error(err),
|
||||
let mut args =
|
||||
match list.parse_args_with(Punctuated::<syn::Meta, Token![,]>::parse_terminated) {
|
||||
Ok(args) => args,
|
||||
Err(_) => {
|
||||
// if we can't parse it, we don't care
|
||||
attributes.push(attr);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
for arg in std::mem::take(&mut args).into_pairs() {
|
||||
match arg {
|
||||
Pair::Punctuated(item, punct) => {
|
||||
if let syn::Meta::Path(path) = &item {
|
||||
if !func(path) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
args.push_value(item);
|
||||
args.push_punct(punct);
|
||||
}
|
||||
Pair::End(item) => {
|
||||
if let syn::Meta::Path(path) = &item {
|
||||
if !func(path) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
args.push_value(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !args.is_empty() {
|
||||
list.tokens = args.into_token_stream();
|
||||
attributes.push(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_derive_attribute(span: Span, content: TokenStream) -> syn::Attribute {
|
||||
// FIXME: syn2 wtf come on...
|
||||
let bracket_span =
|
||||
proc_macro2::Group::new(proc_macro2::Delimiter::Bracket, TokenStream::new()).delim_span();
|
||||
let paren_span =
|
||||
proc_macro2::Group::new(proc_macro2::Delimiter::Parenthesis, TokenStream::new())
|
||||
.delim_span();
|
||||
|
||||
syn::Attribute {
|
||||
pound_token: syn::token::Pound { spans: [span] },
|
||||
style: syn::AttrStyle::Outer,
|
||||
bracket_token: syn::token::Bracket { span: bracket_span },
|
||||
//meta: syn::Meta::List(syn::parse_quote_spanned!(span => derive ( #content )).unwrap()),
|
||||
meta: syn::Meta::List(syn::MetaList {
|
||||
path: make_ident_path(Ident::new("derive", span)),
|
||||
delimiter: syn::MacroDelimiter::Paren(syn::token::Paren { span: paren_span }),
|
||||
tokens: content,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -906,14 +860,15 @@ pub fn respan(mut token: TokenTree, span: Span) -> TokenTree {
|
||||
|
||||
/// Parse a string attribute into a value, producing a duplication error if it has already been
|
||||
/// set.
|
||||
pub fn parse_str_value_to_option<T: Parse>(target: &mut Option<T>, nv: &syn::MetaNameValue) {
|
||||
duplicate(&*target, &nv.path);
|
||||
match &nv.lit {
|
||||
syn::Lit::Str(s) => match parse_lit_str(s) {
|
||||
Ok(value) => *target = Some(value),
|
||||
Err(err) => crate::add_error(err),
|
||||
},
|
||||
other => error!(other => "bad value for '{:?}' attribute", nv.path),
|
||||
pub fn parse_str_value_to_option<T: Parse>(
|
||||
target: &mut Option<T>,
|
||||
path: &syn::Path,
|
||||
nv: syn::parse::ParseStream<'_>,
|
||||
) {
|
||||
duplicate(&*target, &path);
|
||||
match nv.parse().and_then(|lit| parse_lit_str(&lit)) {
|
||||
Ok(value) => *target = Some(value),
|
||||
Err(err) => crate::add_error(err),
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user