It's 3.30.2 release day, upload a tarball and fix that hidden pesky bug that you missed in .1 🦛

Update rustfmt configuration

parent 31ff9880
Pipeline #35863 passed with stages
in 7 minutes
......@@ -5,4 +5,4 @@ newline_style = "Unix"
format_strings = true
normalize_comments = true
use_field_init_shorthand = true
edition = "Edition2018"
edition = "2018"
// use lalrpop_intern::InternedString;
use parser::keywords;
use proc_macro2::Ident;
use syn::punctuated::Punctuated;
use syn::{Attribute, Lit};
use parser::keywords;
use syn::token;
use syn::spanned::Spanned;
use syn::token;
use syn::{Attribute, Lit};
use syn::{Block, FieldsNamed, FnArg, Path, ReturnType, Type};
pub struct Program {
......@@ -50,7 +50,8 @@ pub fn get_program_classes<'a>(program: &'a Program) -> Vec<&'a Class> {
} else {
None
}
}).collect()
})
.collect()
}
pub struct Class {
......@@ -90,21 +91,20 @@ pub enum ImplItemKind {
ReserveSlots(Lit),
}
impl ImplItemKind
{
impl ImplItemKind {
pub fn ident_span(&self) -> ::proc_macro2::Span {
match self {
ImplItemKind::Method(ImplItemMethod { ref name, ..}) => name.span(),
ImplItemKind::Prop(ImplProp { ref name, ..}) => name.span(),
ImplItemKind::Method(ImplItemMethod { ref name, .. }) => name.span(),
ImplItemKind::Prop(ImplProp { ref name, .. }) => name.span(),
ImplItemKind::ReserveSlots(ref l) => l.span(),
}
}
}
pub struct ImplItemMethod {
pub public: Option<Token![pub]>, // requires body
pub public: Option<Token![pub]>, // requires body
pub virtual_: Option<Token![virtual]>, // implies public, doesn't need body
pub signal: Option<keywords::signal>, // ignore
pub signal: Option<keywords::signal>, // ignore
pub fn_: Token![fn],
pub name: Ident,
pub parem_token: token::Paren,
......@@ -113,16 +113,13 @@ pub struct ImplItemMethod {
pub body: ImplItemMethodBlock,
}
pub enum ImplItemMethodBlock
{
pub enum ImplItemMethodBlock {
Block(Block),
Empty(Token![;]),
}
impl ImplItemMethodBlock
{
pub fn as_ref(&self) -> Option<&Block>
{
impl ImplItemMethodBlock {
pub fn as_ref(&self) -> Option<&Block> {
match self {
ImplItemMethodBlock::Block(ref b) => Some(b),
ImplItemMethodBlock::Empty(_) => None,
......
......@@ -28,7 +28,7 @@ pub mod tests {
fn checks_empty_class() -> Result<()> {
let raw = "class Foo {}";
let program : ast::Program = ::syn::parse_str(raw)?;
let program: ast::Program = ::syn::parse_str(raw)?;
check_program(&program)
}
......
......@@ -4,13 +4,13 @@ use quote::ToTokens;
use xml::writer::{EmitterConfig, XmlEvent};
use xml::EventWriter;
use hir::{Program, Class, Slot, Method, Ty, FnArg};
use glib_utils::*;
use gen::names::Names;
use glib_utils::*;
use hir::{Class, FnArg, Method, Program, Slot, Ty};
use errors::*;
use xml::writer::{Result as EmitterResult};
use xml::writer::Result as EmitterResult;
pub fn generate(program: &Program) -> Result<()> {
for class in program.classes.iter() {
......@@ -22,7 +22,8 @@ pub fn generate(program: &Program) -> Result<()> {
pub fn generate_gir(class: &Class) -> Result<()> {
if let Some(ref s) = class.gir {
let mut f = File::create(&s.value()).map_err(|err| Error::new(s.span(), err.to_string()))?;;
let mut f =
File::create(&s.value()).map_err(|err| Error::new(s.span(), err.to_string()))?;;
generate_gir_xml(class, &mut f).map_err(|err| Error::new(s.span(), err.to_string()))?;
}
......@@ -30,11 +31,8 @@ pub fn generate_gir(class: &Class) -> Result<()> {
Ok(())
}
fn generate_gir_xml(class: &Class, f: &mut File) -> EmitterResult<()>
{
let mut w = EmitterConfig::new()
.perform_indent(true)
.create_writer(f);
fn generate_gir_xml(class: &Class, f: &mut File) -> EmitterResult<()> {
let mut w = EmitterConfig::new().perform_indent(true).create_writer(f);
let name = class.name.to_string();
let lower_name = lower_case_instance_name(&name).to_string();
......@@ -51,37 +49,42 @@ fn generate_gir_xml(class: &Class, f: &mut File) -> EmitterResult<()>
// the dep should be `("GLib", "2.0")` lib and version
let deps: Vec<(&str, &str)> = vec![];
w.write(XmlEvent::start_element("repository")
.attr("version", "1.2")
.attr("xmlns", "http://www.gtk.org/introspection/core/1.0")
.attr("xmlns:c", "http://www.gtk.org/introspection/c/1.0")
.attr("xmlns:glib", "http://www.gtk.org/introspection/glib/1.0"))?;
w.write(
XmlEvent::start_element("repository")
.attr("version", "1.2")
.attr("xmlns", "http://www.gtk.org/introspection/core/1.0")
.attr("xmlns:c", "http://www.gtk.org/introspection/c/1.0")
.attr("xmlns:glib", "http://www.gtk.org/introspection/glib/1.0"),
)?;
// <include name="GLib" version="2.0"/>
for (name, version) in deps {
w.write(XmlEvent::start_element("include")
.attr("name", name)
.attr("version", version)
w.write(
XmlEvent::start_element("include")
.attr("name", name)
.attr("version", version),
)?;
w.write(XmlEvent::end_element())?;
}
w.write(XmlEvent::start_element("namespace")
.attr("name", &name)
.attr("c:identifier-prefixes", &name)
.attr("c:symbol-prefixes", &lower_name)
.attr("version", &version)
.attr("shared-library", &slib)
w.write(
XmlEvent::start_element("namespace")
.attr("name", &name)
.attr("c:identifier-prefixes", &name)
.attr("c:symbol-prefixes", &lower_name)
.attr("version", &version)
.attr("shared-library", &slib),
)?;
w.write(XmlEvent::start_element("class")
.attr("name", &name)
.attr("c:type", &name)
.attr("glib:type-name", &name)
.attr("c:symbol-prefix", &lower_name)
.attr("glib:type-struct", &names.vtable().to_string())
.attr("glib:get-type", &names.get_type_fn().to_string())
.attr("parent", &parent_name)
w.write(
XmlEvent::start_element("class")
.attr("name", &name)
.attr("c:type", &name)
.attr("glib:type-name", &name)
.attr("c:symbol-prefix", &lower_name)
.attr("glib:type-struct", &names.vtable().to_string())
.attr("glib:get-type", &names.get_type_fn().to_string())
.attr("parent", &parent_name),
)?;
gen_constructor_xml(&mut w, &names)?;
......@@ -129,31 +132,43 @@ fn gen_slot_xml(w: &mut EventWriter<&mut File>, names: &Names, slot: &Slot) -> E
let name = sig.name.to_string();
let identifier = names.exported_fn(&sig.name).to_string();
let output_ctype = type_to_ctype(&sig.output);
w.write(XmlEvent::start_element("method")
.attr("name", &name)
.attr("c:identifier", &identifier)
w.write(
XmlEvent::start_element("method")
.attr("name", &name)
.attr("c:identifier", &identifier),
)?;
// FIXME, calculate the ownership transfer for pointer types
w.write(XmlEvent::start_element("return-value").attr("transfer-ownership", "none"))?;
w.write(XmlEvent::start_element("type").attr("name", &output_ctype)
.attr("c:type", &output_ctype))?;
w.write(
XmlEvent::start_element("type")
.attr("name", &output_ctype)
.attr("c:type", &output_ctype),
)?;
w.write(XmlEvent::end_element())?; // closing type
w.write(XmlEvent::end_element())?; // closing return-value
// TODO: add parameters here
w.write(XmlEvent::start_element("parameters"))?;
for param in sig.inputs.iter() {
if let FnArg::Arg { ref name, ref ty, .. } = param {
if let FnArg::Arg {
ref name, ref ty, ..
} = param
{
let ownership = "none";
let ctype = type_to_ctype(ty);
w.write(XmlEvent::start_element("parameter")
.attr("name", &name.to_string())
.attr("transfer-ownership", ownership))?;
w.write(XmlEvent::start_element("type")
.attr("name", &ctype).attr("c:type", &ctype))?;
w.write(
XmlEvent::start_element("parameter")
.attr("name", &name.to_string())
.attr("transfer-ownership", ownership),
)?;
w.write(
XmlEvent::start_element("type")
.attr("name", &ctype)
.attr("c:type", &ctype),
)?;
w.write(XmlEvent::end_element())?; // closing type
w.write(XmlEvent::end_element())?; // closing parameter
......@@ -164,7 +179,7 @@ fn gen_slot_xml(w: &mut EventWriter<&mut File>, names: &Names, slot: &Slot) -> E
// TODO: add doc here?
w.write(XmlEvent::end_element())?;
},
}
_ => {
// VirtualMethod or Signal
}
......@@ -183,13 +198,18 @@ fn gen_constructor_xml(w: &mut EventWriter<&mut File>, names: &Names) -> Emitter
let identifier = names.exported_fn_from_str("new").to_string();
let name = names.instance().to_string();
let ctype = format!("{}*", name);
w.write(XmlEvent::start_element("constructor")
.attr("name", "new")
.attr("c:identifier", &identifier)
w.write(
XmlEvent::start_element("constructor")
.attr("name", "new")
.attr("c:identifier", &identifier),
)?;
w.write(XmlEvent::start_element("return-value").attr("transfer-ownership", "full"))?;
w.write(XmlEvent::start_element("type").attr("name", &name).attr("c:type", &ctype))?;
w.write(
XmlEvent::start_element("type")
.attr("name", &name)
.attr("c:type", &ctype),
)?;
w.write(XmlEvent::end_element())?; // closing type
w.write(XmlEvent::end_element())?; // closing return-value
......@@ -217,10 +237,11 @@ fn gen_record_xml(w: &mut EventWriter<&mut File>, names: &Names) -> EmitterResul
// disguised="1"
// glib:is-gtype-struct-for="Counter">
// </record>
w.write(XmlEvent::start_element("record")
.attr("name", &names.vtable().to_string())
.attr("disguised", "1")
.attr("glib:is-gtype-struct-for", &names.instance().to_string())
w.write(
XmlEvent::start_element("record")
.attr("name", &names.vtable().to_string())
.attr("disguised", "1")
.attr("glib:is-gtype-struct-for", &names.instance().to_string()),
)?;
w.write(XmlEvent::end_element())?;
......
......@@ -33,7 +33,8 @@ pub fn slot_assignments<'ast>(names: &Names, slots: &[Slot<'ast>]) -> Vec<TokenS
vtable.#signalname = Some(#InstanceNameFfi::#trampoline_name);
})
}
}).collect::<Vec<_>>()
})
.collect::<Vec<_>>()
}
// If you rename this function, or move stuff out of it, please
......@@ -84,7 +85,8 @@ pub fn instance_slot_trampolines<'ast>(
Slot::VirtualMethod(VirtualMethod { ref sig, .. }) => Some(tokens(sig, None)),
Slot::Signal(ref signal) => Some(tokens(&signal.sig, None)),
}).collect::<Vec<_>>();
})
.collect::<Vec<_>>();
if let Some(overrides) = overrides {
ret.extend(
......@@ -193,9 +195,8 @@ pub fn extern_methods<'ast>(names: &Names, slots: &[Slot<'ast>]) -> Vec<TokenStr
.iter()
.filter_map(|slot| {
match *slot {
Slot::Method(Method { public: false, .. }) => None, /* these don't get exposed
* in the C API */
Slot::Method(Method { public: false, .. }) => None, // these don't get exposed
// in the C API
Slot::Method(Method {
public: true,
ref sig,
......@@ -245,5 +246,6 @@ pub fn extern_methods<'ast>(names: &Names, slots: &[Slot<'ast>]) -> Vec<TokenStr
Slot::Signal(_) => None, // these don't get exposed in the C API
}
}).collect()
})
.collect()
}
......@@ -7,6 +7,7 @@ use std::fmt::Display;
mod boilerplate;
mod class;
mod cstringliteral;
pub mod gir;
mod imp;
mod instance_ext;
mod interface;
......@@ -15,7 +16,6 @@ mod properties;
mod signals;
mod signatures;
mod slots;
pub mod gir;
use self::class::ClassContext;
use self::interface::InterfaceContext;
......@@ -29,7 +29,8 @@ pub fn codegen(program: &Program) -> TokenStream {
.map(|class| {
let cx = ClassContext::new(program, class);
cx.gen_class()
}).collect::<Vec<_>>();
})
.collect::<Vec<_>>();
let interface_tokens = program
.interfaces
......@@ -37,7 +38,8 @@ pub fn codegen(program: &Program) -> TokenStream {
.map(|iface| {
let cx = InterfaceContext::new(program, iface);
cx.gen_interface()
}).collect::<Vec<_>>();
})
.collect::<Vec<_>>();
quote! {
#(#class_tokens)*
......
......@@ -15,7 +15,8 @@ pub fn properties_enum<'ast>(properties: &[Property<'ast>]) -> TokenStream {
let name = &prop.name;
let index = (i as u32) + 1;
quote! { #name = #index }
}).collect();
})
.collect();
quote! {
#[repr(u32)]
......@@ -42,7 +43,8 @@ pub fn property_setter<'ast>(properties: &[Property<'ast>]) -> TokenStream {
#body
}
}
}).collect();
})
.collect();
quote! {
#[allow(dead_code, unused_variables)]
......@@ -80,7 +82,8 @@ pub fn property_getter<'ast>(properties: &[Property<'ast>]) -> TokenStream {
}
}
}
}).collect();
})
.collect();
quote! {
#[allow(dead_code, unused_variables)]
......@@ -116,7 +119,8 @@ pub fn set_properties<'ast>(properties: &[Property<'ast>]) -> Vec<TokenStream> {
}
}
}
}).collect()
})
.collect()
}
pub fn get_properties<'ast>(properties: &[Property<'ast>]) -> Vec<TokenStream> {
......@@ -142,7 +146,8 @@ pub fn get_properties<'ast>(properties: &[Property<'ast>]) -> Vec<TokenStream> {
value.get::<#type_>().unwrap()
}
}
}).collect()
})
.collect()
}
pub fn set_properties_fn<'ast>(properties: &[Property<'ast>]) -> Vec<TokenStream> {
......@@ -158,7 +163,8 @@ pub fn set_properties_fn<'ast>(properties: &[Property<'ast>]) -> Vec<TokenStream
quote! {
fn #name(&self, v: #type_);
}
}).collect()
})
.collect()
}
pub fn get_properties_fn<'ast>(properties: &[Property<'ast>]) -> Vec<TokenStream> {
......@@ -174,7 +180,8 @@ pub fn get_properties_fn<'ast>(properties: &[Property<'ast>]) -> Vec<TokenStream
quote! {
fn #name(&self) -> #type_;
}
}).collect()
})
.collect()
}
fn prop_registration<'ast>(properties: &[Property<'ast>]) -> Vec<TokenStream> {
......@@ -213,7 +220,8 @@ fn prop_registration<'ast>(properties: &[Property<'ast>]) -> Vec<TokenStream> {
//| gobject_ffi::G_PARAM_CONSTRUCT_ONLY,
));
}
}).collect()
})
.collect()
}
pub fn properties_registration<'ast>(properties: &[Property<'ast>]) -> TokenStream {
......
......@@ -63,7 +63,8 @@ pub fn signal_emit_methods<'ast>(
}
}
}
}).collect()
})
.collect()
}
pub fn signal_id_names<'ast>(signals: impl Iterator<Item = &'ast Signal<'ast>>) -> Vec<Ident> {
......@@ -92,7 +93,10 @@ pub fn signal_declarations<'ast>(
assert!(!signal.sig.inputs.is_empty());
let n_params = (signal.sig.inputs.len() - 1) as u32;
let param_gtypes: Vec<Path> = signal.sig.inputs.iter()
let param_gtypes: Vec<Path> = signal
.sig
.inputs
.iter()
.skip(1) // skip &self
.map(|arg| {
if let FnArg::Arg { ref ty, .. } = arg {
......@@ -125,7 +129,8 @@ pub fn signal_declarations<'ast>(
mut_override(param_gtypes.as_ptr())
);
}
}).collect()
})
.collect()
}
pub fn signal_trampolines<'ast>(
......@@ -165,7 +170,8 @@ pub fn signal_trampolines<'ast>(
#ret
}
}
}).collect()
})
.collect()
}
/// From a signal called `foo`, generate `foo_signal_id`. This is used to
......
......@@ -117,18 +117,21 @@ impl<'ast> ToTokens for ToGlibType<'ast> {
Ty::Char(ref i) | Ty::Bool(ref i) => {
(quote! {
<#i as ToGlib>::GlibType
}).to_tokens(tokens);
})
.to_tokens(tokens);
}
Ty::Borrowed(ref t) => {
(quote! {
<#t as GlibPtrDefault>::GlibType
}).to_tokens(tokens);
})
.to_tokens(tokens);
}
Ty::Integer(ref i) => i.to_tokens(tokens),
Ty::Owned(ref t) => {
(quote! {
<#t as GlibPtrDefault>::GlibType
}).to_tokens(tokens);
})
.to_tokens(tokens);
}
}
}
......@@ -146,17 +149,20 @@ impl<'ast, T: ToTokens> ToTokens for ToGlib<'ast, T> {
Ty::Char(ref i) | Ty::Bool(ref i) => {
(quote! {
<#i as ToGlib>::to_glib(&#expr)
}).to_tokens(tokens);
})
.to_tokens(tokens);
}
Ty::Borrowed(ref t) => {
(quote! {
<#t as ToGlibPtr<_>>::to_glib_none(#expr).0
}).to_tokens(tokens);
})
.to_tokens(tokens);
}
Ty::Owned(ref t) => {
(quote! {
<#t as ToGlibPtr<_>>::to_glib_full(&#expr)
}).to_tokens(tokens);
})
.to_tokens(tokens);
}
}
}
......@@ -167,20 +173,23 @@ struct FromGlib<'ast>(&'ast Ty<'ast>, TokenStream);
impl<'ast> ToTokens for FromGlib<'ast> {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
FromGlib(Ty::Unit, inner) => { inner.to_tokens(tokens); }, // no conversion necessary
FromGlib(Ty::Unit, inner) => {
inner.to_tokens(tokens);
} // no conversion necessary
FromGlib(Ty::Char(ref i), inner) | FromGlib(Ty::Bool(ref i), inner) => {
tokens.extend(quote! {
<#i as FromGlib<_>>::from_glib(#inner)
}) },
FromGlib(Ty::Borrowed(ref t), inner) => {
tokens.extend(quote! {
&<#t as FromGlibPtrBorrow<_>>::from_glib_borrow(#inner)
}) },
})
}
FromGlib(Ty::Borrowed(ref t), inner) => tokens.extend(quote! {
&<#t as FromGlibPtrBorrow<_>>::from_glib_borrow(#inner)
}),
FromGlib(Ty::Integer(_), inner) => inner.to_tokens(tokens), // no conversion necessary
FromGlib(Ty::Owned(t), inner) => {
tokens.extend(quote! {
unsafe { <#t as FromGlibPtrFull<_>>::from_glib_full(#inner) }
}); }
});
}
}
}
}
......
......@@ -28,7 +28,8 @@ impl<'ast> ToTokens for SlotDeclaration<'ast> {
this: *mut #InstanceNameFfi,
#inputs
) -> #output>,
}).to_tokens(tokens);
})
.to_tokens(tokens);
}
Slot::Signal(ref signal) => {
......@@ -41,7 +42,8 @@ impl<'ast> ToTokens for SlotDeclaration<'ast> {
this: *mut #InstanceNameFfi,
#inputs
) -> #output>,
}).to_tokens(tokens);
})
.to_tokens(tokens);
}
}
}
......
......@@ -24,7 +24,8 @@ pub fn tokens_ParentInstance(class: &ast::Class) -> TokenStream {
let mut tokens = TokenStream::new();
path.to_tokens(&mut tokens);
tokens
}).unwrap_or_else(tokens_GObject)
})
.unwrap_or_else(tokens_GObject)
}
pub fn tokens_ParentInstanceFfi(class: &ast::Class) -> TokenStream {
......
This diff is collapsed.
......@@ -151,13 +151,14 @@ fn gobject_gen_inner(input: proc_macro::TokenStream) -> Result<proc_macro::Token
config.set().write_mode(rustfmt::config::WriteMode::Plain);
config.set().error_on_line_overflow(false);
let stream: String = tokens.to_string();
rustfmt::format_input(rustfmt::Input::Text(stream),
&config,
Some(&mut out))
rustfmt::format_input(rustfmt::Input::Text(stream), &config, Some(&mut out))
.map_err(|e| errors::Error::new(proc_macro2::Span::call_site(), format!("{:?}", &e)))?;
let output = String::from_utf8(out).unwrap();
println!("/********************************************************************************/\n{}", output);
println!(
"/********************************************************************************/\n{}",
output
);
Ok(tokens.into())
}
......@@ -173,4 +174,4 @@ fn testme_inner(input: proc_macro::TokenStream) -> Result<proc_macro::TokenStrea
parser::tests::run()?;
gen::tests::run();
Ok(input)
}
\ No newline at end of file
}
use proc_macro;
use proc_macro2::{TokenStream};
use syn::parse::{Result, Parse, ParseStream};
use proc_macro2::TokenStream;
use syn;
use syn::parse::{Parse, ParseStream, Result};
use ast;
pub mod keywords
{
pub mod keywords {
custom_keyword!(class);
custom_keyword!(interface);
custom_keyword!(property);
......@@ -23,7 +22,9 @@ pub fn parse_program(token_stream: proc_macro::TokenStream) -> Result<ast::Progr
impl Parse for ast::Program {
fn parse(input: ParseStream) -> Result<Self> {
Ok(ast::Program { items: ast::Item::parse_outer(input)? })
Ok(ast::Program {
items: ast::Item::parse_outer(input)?,
})
}
}
......@@ -32,21 +33,25 @@ impl Parse for ast::Item {
let attrs = syn::Attribute::parse_outer(input)?;
let lookahead = input.lookahead1();
if lookahead.peek(keywords::class) {
input.parse().map(|mut res : ast::Class| { res.attrs = attrs; ast::Item::Class(res) })
} else if lookahead.peek(Token![impl]) {
input.parse().map(|mut res: ast::Class| {
res.attrs = attrs;
ast::Item::Class(res)
})
} else if lookahead.peek(Token![impl ]) {
input.parse().map(ast::Item::Impl)
} else if lookahead.peek(keywords::interface) {
input.parse().map(|mut res : ast::Interface| { res.attrs = attrs; ast::Item::Interface(res) })
input.parse().map(|mut res: ast::Interface| {
res.attrs = attrs;
ast::Item::Interface(res)
})
} else {
Err(lookahead.error())
}
}
}
impl ast::Item
{
fn parse_outer(input: ParseStream) -> Result<Vec<Self>>
{
impl ast::Item {
fn parse_outer(input: ParseStream) -> Result<Vec<Self>> {
let mut res = Vec::new();
while !input.is_empty() {
res.push(input.parse()?);
......@@ -59,8 +64,12 @@ impl Parse for ast::Class {
fn parse(input: ParseStream) -> Result<Self> {
let class = input.parse()?;
let name = input.parse()?;
let colon : Option<Token![:]> = input.parse()?;
let extends = if colon.is_some() { Some(input.parse()?) } else { None };
let colon: Option<Token![:]> = input.parse()?;
let extends = if colon.is_some() {
Some(input.parse()?)
} else {
None
};
let fields = input.parse()?;
Ok(ast::Class {
attrs: Vec::new(),
......@@ -88,8 +97,8 @@ impl Parse for ast::Interface {
impl Parse for ast::Impl {
fn parse(input: ParseStream) -> Result<Self> {
input.parse::<Token![impl]>()?;
let interface : Option<keywords::interface> = input.parse()?;
input.parse::<Token![impl ]>()?;
let interface: Option<keywords::interface> = input.parse()?;
let trait_ = if input.peek2(Token![for]) {
let trait_ = input.parse()?;
input.parse::<Token![for]>()?;
......@@ -107,9 +116,9 @@ impl Parse for ast::Impl {
Ok(ast::Impl {
is_interface: interface.is_some(),
trait_: trait_,
self_path: self_path,
items: items,
trait_,
self_path,
items,
})
}
}
......@@ -118,15 +127,13 @@ impl Parse for ast::ImplItem {
fn parse(input: ParseStream) -> Result<Self> {
Ok(ast::ImplItem {
attrs: input.call(syn::Attribute::parse_outer)?,
node: input.parse()?