use crate::algorithm::Printer; use crate::iter::IterDelimited; use crate::path::PathKind; use crate::INDENT; use proc_macro2::TokenStream; use syn::{ Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType, ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod, ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver, Signature, StaticMutability, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, Variadic, }; impl Printer { pub fn item(&mut self, item: &Item) { match item { #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] Item::Const(item) => self.item_const(item), Item::Enum(item) => self.item_enum(item), Item::ExternCrate(item) => self.item_extern_crate(item), Item::Fn(item) => self.item_fn(item), Item::ForeignMod(item) => self.item_foreign_mod(item), Item::Impl(item) => self.item_impl(item), Item::Macro(item) => self.item_macro(item), Item::Mod(item) => self.item_mod(item), Item::Static(item) => self.item_static(item), Item::Struct(item) => self.item_struct(item), Item::Trait(item) => self.item_trait(item), Item::TraitAlias(item) => self.item_trait_alias(item), Item::Type(item) => self.item_type(item), Item::Union(item) => self.item_union(item), Item::Use(item) => self.item_use(item), Item::Verbatim(item) => self.item_verbatim(item), _ => unimplemented!("unknown Item"), } } fn item_const(&mut self, item: &ItemConst) { self.outer_attrs(&item.attrs); self.cbox(0); self.visibility(&item.vis); self.word("const "); self.ident(&item.ident); self.generics(&item.generics); self.word(": "); self.ty(&item.ty); self.word(" = "); self.neverbreak(); self.expr(&item.expr); self.word(";"); self.end(); self.hardbreak(); } fn item_enum(&mut self, item: &ItemEnum) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.visibility(&item.vis); self.word("enum "); self.ident(&item.ident); self.generics(&item.generics); self.where_clause_for_body(&item.generics.where_clause); self.word("{"); self.hardbreak_if_nonempty(); for variant in &item.variants { self.variant(variant); self.word(","); self.hardbreak(); } self.offset(-INDENT); self.end(); self.word("}"); self.hardbreak(); } fn item_extern_crate(&mut self, item: &ItemExternCrate) { self.outer_attrs(&item.attrs); self.visibility(&item.vis); self.word("extern crate "); self.ident(&item.ident); if let Some((_as_token, rename)) = &item.rename { self.word(" as "); self.ident(rename); } self.word(";"); self.hardbreak(); } fn item_fn(&mut self, item: &ItemFn) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.visibility(&item.vis); self.signature(&item.sig); self.where_clause_for_body(&item.sig.generics.where_clause); self.word("{"); self.hardbreak_if_nonempty(); self.inner_attrs(&item.attrs); for stmt in &item.block.stmts { self.stmt(stmt); } self.offset(-INDENT); self.end(); self.word("}"); self.hardbreak(); } fn item_foreign_mod(&mut self, item: &ItemForeignMod) { self.outer_attrs(&item.attrs); self.cbox(INDENT); if item.unsafety.is_some() { self.word("unsafe "); } self.abi(&item.abi); self.word("{"); self.hardbreak_if_nonempty(); self.inner_attrs(&item.attrs); for foreign_item in &item.items { self.foreign_item(foreign_item); } self.offset(-INDENT); self.end(); self.word("}"); self.hardbreak(); } fn item_impl(&mut self, item: &ItemImpl) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.ibox(-INDENT); self.cbox(INDENT); if item.defaultness.is_some() { self.word("default "); } if item.unsafety.is_some() { self.word("unsafe "); } self.word("impl"); self.generics(&item.generics); self.end(); self.nbsp(); if let Some((negative_polarity, path, _for_token)) = &item.trait_ { if negative_polarity.is_some() { self.word("!"); } self.path(path, PathKind::Type); self.space(); self.word("for "); } self.ty(&item.self_ty); self.end(); self.where_clause_for_body(&item.generics.where_clause); self.word("{"); self.hardbreak_if_nonempty(); self.inner_attrs(&item.attrs); for impl_item in &item.items { self.impl_item(impl_item); } self.offset(-INDENT); self.end(); self.word("}"); self.hardbreak(); } fn item_macro(&mut self, item: &ItemMacro) { self.outer_attrs(&item.attrs); let semicolon = true; self.mac(&item.mac, item.ident.as_ref(), semicolon); self.hardbreak(); } fn item_mod(&mut self, item: &ItemMod) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.visibility(&item.vis); if item.unsafety.is_some() { self.word("unsafe "); } self.word("mod "); self.ident(&item.ident); if let Some((_brace, items)) = &item.content { self.word(" {"); self.hardbreak_if_nonempty(); self.inner_attrs(&item.attrs); for item in items { self.item(item); } self.offset(-INDENT); self.end(); self.word("}"); } else { self.word(";"); self.end(); } self.hardbreak(); } fn item_static(&mut self, item: &ItemStatic) { self.outer_attrs(&item.attrs); self.cbox(0); self.visibility(&item.vis); self.word("static "); self.static_mutability(&item.mutability); self.ident(&item.ident); self.word(": "); self.ty(&item.ty); self.word(" = "); self.neverbreak(); self.expr(&item.expr); self.word(";"); self.end(); self.hardbreak(); } fn item_struct(&mut self, item: &ItemStruct) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.visibility(&item.vis); self.word("struct "); self.ident(&item.ident); self.generics(&item.generics); match &item.fields { Fields::Named(fields) => { self.where_clause_for_body(&item.generics.where_clause); self.word("{"); self.hardbreak_if_nonempty(); for field in &fields.named { self.field(field); self.word(","); self.hardbreak(); } self.offset(-INDENT); self.end(); self.word("}"); } Fields::Unnamed(fields) => { self.fields_unnamed(fields); self.where_clause_semi(&item.generics.where_clause); self.end(); } Fields::Unit => { self.where_clause_semi(&item.generics.where_clause); self.end(); } } self.hardbreak(); } fn item_trait(&mut self, item: &ItemTrait) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.visibility(&item.vis); if item.unsafety.is_some() { self.word("unsafe "); } if item.auto_token.is_some() { self.word("auto "); } self.word("trait "); self.ident(&item.ident); self.generics(&item.generics); for supertrait in item.supertraits.iter().delimited() { if supertrait.is_first { self.word(": "); } else { self.word(" + "); } self.type_param_bound(&supertrait); } self.where_clause_for_body(&item.generics.where_clause); self.word("{"); self.hardbreak_if_nonempty(); self.inner_attrs(&item.attrs); for trait_item in &item.items { self.trait_item(trait_item); } self.offset(-INDENT); self.end(); self.word("}"); self.hardbreak(); } fn item_trait_alias(&mut self, item: &ItemTraitAlias) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.visibility(&item.vis); self.word("trait "); self.ident(&item.ident); self.generics(&item.generics); self.word(" = "); self.neverbreak(); for bound in item.bounds.iter().delimited() { if !bound.is_first { self.space(); self.word("+ "); } self.type_param_bound(&bound); } self.where_clause_semi(&item.generics.where_clause); self.end(); self.hardbreak(); } fn item_type(&mut self, item: &ItemType) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.visibility(&item.vis); self.word("type "); self.ident(&item.ident); self.generics(&item.generics); self.where_clause_oneline(&item.generics.where_clause); self.word("= "); self.neverbreak(); self.ibox(-INDENT); self.ty(&item.ty); self.end(); self.word(";"); self.end(); self.hardbreak(); } fn item_union(&mut self, item: &ItemUnion) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.visibility(&item.vis); self.word("union "); self.ident(&item.ident); self.generics(&item.generics); self.where_clause_for_body(&item.generics.where_clause); self.word("{"); self.hardbreak_if_nonempty(); for field in &item.fields.named { self.field(field); self.word(","); self.hardbreak(); } self.offset(-INDENT); self.end(); self.word("}"); self.hardbreak(); } fn item_use(&mut self, item: &ItemUse) { self.outer_attrs(&item.attrs); self.visibility(&item.vis); self.word("use "); if item.leading_colon.is_some() { self.word("::"); } self.use_tree(&item.tree); self.word(";"); self.hardbreak(); } #[cfg(not(feature = "verbatim"))] fn item_verbatim(&mut self, item: &TokenStream) { if !item.is_empty() { unimplemented!("Item::Verbatim `{}`", item); } self.hardbreak(); } #[cfg(feature = "verbatim")] fn item_verbatim(&mut self, tokens: &TokenStream) { use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::{ braced, parenthesized, token, Attribute, Generics, Ident, Lifetime, Token, Visibility, }; use verbatim::{ FlexibleItemConst, FlexibleItemFn, FlexibleItemStatic, FlexibleItemType, WhereClauseLocation, }; enum ItemVerbatim { Empty, Ellipsis, ConstFlexible(FlexibleItemConst), FnFlexible(FlexibleItemFn), ImplFlexible(ImplFlexible), Macro2(Macro2), StaticFlexible(FlexibleItemStatic), TypeFlexible(FlexibleItemType), UseBrace(UseBrace), } struct ImplFlexible { attrs: Vec, vis: Visibility, defaultness: bool, unsafety: bool, generics: Generics, constness: ImplConstness, negative_impl: bool, trait_: Option, self_ty: Type, items: Vec, } enum ImplConstness { None, MaybeConst, Const, } struct Macro2 { attrs: Vec, vis: Visibility, ident: Ident, args: Option, body: TokenStream, } struct UseBrace { attrs: Vec, vis: Visibility, trees: Punctuated, } struct RootUseTree { leading_colon: Option, inner: UseTree, } impl Parse for ImplConstness { fn parse(input: ParseStream) -> Result { if input.parse::>()?.is_some() { input.parse::()?; Ok(ImplConstness::MaybeConst) } else if input.parse::>()?.is_some() { Ok(ImplConstness::Const) } else { Ok(ImplConstness::None) } } } impl Parse for RootUseTree { fn parse(input: ParseStream) -> Result { Ok(RootUseTree { leading_colon: input.parse()?, inner: input.parse()?, }) } } impl Parse for ItemVerbatim { fn parse(input: ParseStream) -> Result { if input.is_empty() { return Ok(ItemVerbatim::Empty); } else if input.peek(Token![...]) { input.parse::()?; return Ok(ItemVerbatim::Ellipsis); } let mut attrs = input.call(Attribute::parse_outer)?; let vis: Visibility = input.parse()?; let lookahead = input.lookahead1(); if lookahead.peek(Token![const]) && (input.peek2(Ident) || input.peek2(Token![_])) { let defaultness = false; let flexible_item = FlexibleItemConst::parse(attrs, vis, defaultness, input)?; Ok(ItemVerbatim::ConstFlexible(flexible_item)) } else if input.peek(Token![const]) || lookahead.peek(Token![async]) || lookahead.peek(Token![unsafe]) && !input.peek2(Token![impl]) || lookahead.peek(Token![extern]) || lookahead.peek(Token![fn]) { let defaultness = false; let flexible_item = FlexibleItemFn::parse(attrs, vis, defaultness, input)?; Ok(ItemVerbatim::FnFlexible(flexible_item)) } else if lookahead.peek(Token![default]) || input.peek(Token![unsafe]) || lookahead.peek(Token![impl]) { let defaultness = input.parse::>()?.is_some(); let unsafety = input.parse::>()?.is_some(); input.parse::()?; let has_generics = input.peek(Token![<]) && (input.peek2(Token![>]) || input.peek2(Token![#]) || (input.peek2(Ident) || input.peek2(Lifetime)) && (input.peek3(Token![:]) || input.peek3(Token![,]) || input.peek3(Token![>]) || input.peek3(Token![=])) || input.peek2(Token![const])); let mut generics: Generics = if has_generics { input.parse()? } else { Generics::default() }; let constness: ImplConstness = input.parse()?; let negative_impl = !input.peek2(token::Brace) && input.parse::>()?.is_some(); let first_ty: Type = input.parse()?; let (trait_, self_ty) = if input.parse::>()?.is_some() { (Some(first_ty), input.parse()?) } else { (None, first_ty) }; generics.where_clause = input.parse()?; let content; braced!(content in input); let inner_attrs = content.call(Attribute::parse_inner)?; attrs.extend(inner_attrs); let mut items = Vec::new(); while !content.is_empty() { items.push(content.parse()?); } Ok(ItemVerbatim::ImplFlexible(ImplFlexible { attrs, vis, defaultness, unsafety, generics, constness, negative_impl, trait_, self_ty, items, })) } else if lookahead.peek(Token![macro]) { input.parse::()?; let ident: Ident = input.parse()?; let args = if input.peek(token::Paren) { let paren_content; parenthesized!(paren_content in input); Some(paren_content.parse::()?) } else { None }; let brace_content; braced!(brace_content in input); let body: TokenStream = brace_content.parse()?; Ok(ItemVerbatim::Macro2(Macro2 { attrs, vis, ident, args, body, })) } else if lookahead.peek(Token![static]) { let flexible_item = FlexibleItemStatic::parse(attrs, vis, input)?; Ok(ItemVerbatim::StaticFlexible(flexible_item)) } else if lookahead.peek(Token![type]) { let defaultness = false; let flexible_item = FlexibleItemType::parse( attrs, vis, defaultness, input, WhereClauseLocation::BeforeEq, )?; Ok(ItemVerbatim::TypeFlexible(flexible_item)) } else if lookahead.peek(Token![use]) { input.parse::()?; let content; braced!(content in input); let trees = content.parse_terminated(RootUseTree::parse, Token![,])?; input.parse::()?; Ok(ItemVerbatim::UseBrace(UseBrace { attrs, vis, trees })) } else { Err(lookahead.error()) } } } let item: ItemVerbatim = match syn::parse2(tokens.clone()) { Ok(item) => item, Err(_) => unimplemented!("Item::Verbatim `{}`", tokens), }; match item { ItemVerbatim::Empty => { self.hardbreak(); } ItemVerbatim::Ellipsis => { self.word("..."); self.hardbreak(); } ItemVerbatim::ConstFlexible(item) => { self.flexible_item_const(&item); } ItemVerbatim::FnFlexible(item) => { self.flexible_item_fn(&item); } ItemVerbatim::ImplFlexible(item) => { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.ibox(-INDENT); self.cbox(INDENT); self.visibility(&item.vis); if item.defaultness { self.word("default "); } if item.unsafety { self.word("unsafe "); } self.word("impl"); self.generics(&item.generics); self.end(); self.nbsp(); match item.constness { ImplConstness::None => {} ImplConstness::MaybeConst => self.word("?const "), ImplConstness::Const => self.word("const "), } if item.negative_impl { self.word("!"); } if let Some(trait_) = &item.trait_ { self.ty(trait_); self.space(); self.word("for "); } self.ty(&item.self_ty); self.end(); self.where_clause_for_body(&item.generics.where_clause); self.word("{"); self.hardbreak_if_nonempty(); self.inner_attrs(&item.attrs); for impl_item in &item.items { self.impl_item(impl_item); } self.offset(-INDENT); self.end(); self.word("}"); self.hardbreak(); } ItemVerbatim::Macro2(item) => { self.outer_attrs(&item.attrs); self.visibility(&item.vis); self.word("macro "); self.ident(&item.ident); if let Some(args) = &item.args { self.word("("); self.cbox(INDENT); self.zerobreak(); self.ibox(0); self.macro_rules_tokens(args.clone(), true); self.end(); self.zerobreak(); self.offset(-INDENT); self.end(); self.word(")"); } self.word(" {"); if !item.body.is_empty() { self.neverbreak(); self.cbox(INDENT); self.hardbreak(); self.ibox(0); self.macro_rules_tokens(item.body.clone(), false); self.end(); self.hardbreak(); self.offset(-INDENT); self.end(); } self.word("}"); self.hardbreak(); } ItemVerbatim::StaticFlexible(item) => { self.flexible_item_static(&item); } ItemVerbatim::TypeFlexible(item) => { self.flexible_item_type(&item); } ItemVerbatim::UseBrace(item) => { self.outer_attrs(&item.attrs); self.visibility(&item.vis); self.word("use "); if item.trees.len() == 1 { self.word("::"); self.use_tree(&item.trees[0].inner); } else { self.cbox(INDENT); self.word("{"); self.zerobreak(); self.ibox(0); for use_tree in item.trees.iter().delimited() { if use_tree.leading_colon.is_some() { self.word("::"); } self.use_tree(&use_tree.inner); if !use_tree.is_last { self.word(","); let mut use_tree = &use_tree.inner; while let UseTree::Path(use_path) = use_tree { use_tree = &use_path.tree; } if let UseTree::Group(_) = use_tree { self.hardbreak(); } else { self.space(); } } } self.end(); self.trailing_comma(true); self.offset(-INDENT); self.word("}"); self.end(); } self.word(";"); self.hardbreak(); } } } fn use_tree(&mut self, use_tree: &UseTree) { match use_tree { UseTree::Path(use_path) => self.use_path(use_path), UseTree::Name(use_name) => self.use_name(use_name), UseTree::Rename(use_rename) => self.use_rename(use_rename), UseTree::Glob(use_glob) => self.use_glob(use_glob), UseTree::Group(use_group) => self.use_group(use_group), } } fn use_path(&mut self, use_path: &UsePath) { self.ident(&use_path.ident); self.word("::"); self.use_tree(&use_path.tree); } fn use_name(&mut self, use_name: &UseName) { self.ident(&use_name.ident); } fn use_rename(&mut self, use_rename: &UseRename) { self.ident(&use_rename.ident); self.word(" as "); self.ident(&use_rename.rename); } fn use_glob(&mut self, use_glob: &UseGlob) { let _ = use_glob; self.word("*"); } fn use_group(&mut self, use_group: &UseGroup) { if use_group.items.is_empty() { self.word("{}"); } else if use_group.items.len() == 1 && match &use_group.items[0] { UseTree::Rename(use_rename) => use_rename.ident != "self", _ => true, } { self.use_tree(&use_group.items[0]); } else { self.cbox(INDENT); self.word("{"); self.zerobreak(); self.ibox(0); for use_tree in use_group.items.iter().delimited() { self.use_tree(&use_tree); if !use_tree.is_last { self.word(","); let mut use_tree = *use_tree; while let UseTree::Path(use_path) = use_tree { use_tree = &use_path.tree; } if let UseTree::Group(_) = use_tree { self.hardbreak(); } else { self.space(); } } } self.end(); self.trailing_comma(true); self.offset(-INDENT); self.word("}"); self.end(); } } fn foreign_item(&mut self, foreign_item: &ForeignItem) { match foreign_item { #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] ForeignItem::Fn(item) => self.foreign_item_fn(item), ForeignItem::Static(item) => self.foreign_item_static(item), ForeignItem::Type(item) => self.foreign_item_type(item), ForeignItem::Macro(item) => self.foreign_item_macro(item), ForeignItem::Verbatim(item) => self.foreign_item_verbatim(item), _ => unimplemented!("unknown ForeignItem"), } } fn foreign_item_fn(&mut self, foreign_item: &ForeignItemFn) { self.outer_attrs(&foreign_item.attrs); self.cbox(INDENT); self.visibility(&foreign_item.vis); self.signature(&foreign_item.sig); self.where_clause_semi(&foreign_item.sig.generics.where_clause); self.end(); self.hardbreak(); } fn foreign_item_static(&mut self, foreign_item: &ForeignItemStatic) { self.outer_attrs(&foreign_item.attrs); self.cbox(0); self.visibility(&foreign_item.vis); self.word("static "); self.static_mutability(&foreign_item.mutability); self.ident(&foreign_item.ident); self.word(": "); self.ty(&foreign_item.ty); self.word(";"); self.end(); self.hardbreak(); } fn foreign_item_type(&mut self, foreign_item: &ForeignItemType) { self.outer_attrs(&foreign_item.attrs); self.cbox(0); self.visibility(&foreign_item.vis); self.word("type "); self.ident(&foreign_item.ident); self.generics(&foreign_item.generics); self.word(";"); self.end(); self.hardbreak(); } fn foreign_item_macro(&mut self, foreign_item: &ForeignItemMacro) { self.outer_attrs(&foreign_item.attrs); let semicolon = true; self.mac(&foreign_item.mac, None, semicolon); self.hardbreak(); } #[cfg(not(feature = "verbatim"))] fn foreign_item_verbatim(&mut self, foreign_item: &TokenStream) { if !foreign_item.is_empty() { unimplemented!("ForeignItem::Verbatim `{}`", foreign_item); } self.hardbreak(); } #[cfg(feature = "verbatim")] fn foreign_item_verbatim(&mut self, tokens: &TokenStream) { use syn::parse::{Parse, ParseStream, Result}; use syn::{Attribute, Token, Visibility}; use verbatim::{FlexibleItemFn, FlexibleItemStatic, FlexibleItemType, WhereClauseLocation}; enum ForeignItemVerbatim { Empty, Ellipsis, FnFlexible(FlexibleItemFn), StaticFlexible(FlexibleItemStatic), TypeFlexible(FlexibleItemType), } impl Parse for ForeignItemVerbatim { fn parse(input: ParseStream) -> Result { if input.is_empty() { return Ok(ForeignItemVerbatim::Empty); } else if input.peek(Token![...]) { input.parse::()?; return Ok(ForeignItemVerbatim::Ellipsis); } let attrs = input.call(Attribute::parse_outer)?; let vis: Visibility = input.parse()?; let defaultness = false; let lookahead = input.lookahead1(); if lookahead.peek(Token![const]) || lookahead.peek(Token![async]) || lookahead.peek(Token![unsafe]) || lookahead.peek(Token![extern]) || lookahead.peek(Token![fn]) { let flexible_item = FlexibleItemFn::parse(attrs, vis, defaultness, input)?; Ok(ForeignItemVerbatim::FnFlexible(flexible_item)) } else if lookahead.peek(Token![static]) { let flexible_item = FlexibleItemStatic::parse(attrs, vis, input)?; Ok(ForeignItemVerbatim::StaticFlexible(flexible_item)) } else if lookahead.peek(Token![type]) { let flexible_item = FlexibleItemType::parse( attrs, vis, defaultness, input, WhereClauseLocation::Both, )?; Ok(ForeignItemVerbatim::TypeFlexible(flexible_item)) } else { Err(lookahead.error()) } } } let foreign_item: ForeignItemVerbatim = match syn::parse2(tokens.clone()) { Ok(foreign_item) => foreign_item, Err(_) => unimplemented!("ForeignItem::Verbatim `{}`", tokens), }; match foreign_item { ForeignItemVerbatim::Empty => { self.hardbreak(); } ForeignItemVerbatim::Ellipsis => { self.word("..."); self.hardbreak(); } ForeignItemVerbatim::FnFlexible(foreign_item) => { self.flexible_item_fn(&foreign_item); } ForeignItemVerbatim::StaticFlexible(foreign_item) => { self.flexible_item_static(&foreign_item); } ForeignItemVerbatim::TypeFlexible(foreign_item) => { self.flexible_item_type(&foreign_item); } } } fn trait_item(&mut self, trait_item: &TraitItem) { match trait_item { #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] TraitItem::Const(item) => self.trait_item_const(item), TraitItem::Fn(item) => self.trait_item_fn(item), TraitItem::Type(item) => self.trait_item_type(item), TraitItem::Macro(item) => self.trait_item_macro(item), TraitItem::Verbatim(item) => self.trait_item_verbatim(item), _ => unimplemented!("unknown TraitItem"), } } fn trait_item_const(&mut self, trait_item: &TraitItemConst) { self.outer_attrs(&trait_item.attrs); self.cbox(0); self.word("const "); self.ident(&trait_item.ident); self.generics(&trait_item.generics); self.word(": "); self.ty(&trait_item.ty); if let Some((_eq_token, default)) = &trait_item.default { self.word(" = "); self.neverbreak(); self.expr(default); } self.word(";"); self.end(); self.hardbreak(); } fn trait_item_fn(&mut self, trait_item: &TraitItemFn) { self.outer_attrs(&trait_item.attrs); self.cbox(INDENT); self.signature(&trait_item.sig); if let Some(block) = &trait_item.default { self.where_clause_for_body(&trait_item.sig.generics.where_clause); self.word("{"); self.hardbreak_if_nonempty(); self.inner_attrs(&trait_item.attrs); for stmt in &block.stmts { self.stmt(stmt); } self.offset(-INDENT); self.end(); self.word("}"); } else { self.where_clause_semi(&trait_item.sig.generics.where_clause); self.end(); } self.hardbreak(); } fn trait_item_type(&mut self, trait_item: &TraitItemType) { self.outer_attrs(&trait_item.attrs); self.cbox(INDENT); self.word("type "); self.ident(&trait_item.ident); self.generics(&trait_item.generics); for bound in trait_item.bounds.iter().delimited() { if bound.is_first { self.word(": "); } else { self.space(); self.word("+ "); } self.type_param_bound(&bound); } if let Some((_eq_token, default)) = &trait_item.default { self.word(" = "); self.neverbreak(); self.ibox(-INDENT); self.ty(default); self.end(); } self.where_clause_oneline_semi(&trait_item.generics.where_clause); self.end(); self.hardbreak(); } fn trait_item_macro(&mut self, trait_item: &TraitItemMacro) { self.outer_attrs(&trait_item.attrs); let semicolon = true; self.mac(&trait_item.mac, None, semicolon); self.hardbreak(); } #[cfg(not(feature = "verbatim"))] fn trait_item_verbatim(&mut self, trait_item: &TokenStream) { if !trait_item.is_empty() { unimplemented!("TraitItem::Verbatim `{}`", trait_item); } self.hardbreak(); } #[cfg(feature = "verbatim")] fn trait_item_verbatim(&mut self, tokens: &TokenStream) { use syn::parse::{Parse, ParseStream, Result}; use syn::{Attribute, Ident, Token, Visibility}; use verbatim::{FlexibleItemConst, FlexibleItemType, WhereClauseLocation}; enum TraitItemVerbatim { Empty, Ellipsis, ConstFlexible(FlexibleItemConst), TypeFlexible(FlexibleItemType), PubOrDefault(PubOrDefaultTraitItem), } struct PubOrDefaultTraitItem { attrs: Vec, vis: Visibility, defaultness: bool, trait_item: TraitItem, } impl Parse for TraitItemVerbatim { fn parse(input: ParseStream) -> Result { if input.is_empty() { return Ok(TraitItemVerbatim::Empty); } else if input.peek(Token![...]) { input.parse::()?; return Ok(TraitItemVerbatim::Ellipsis); } let attrs = input.call(Attribute::parse_outer)?; let vis: Visibility = input.parse()?; let defaultness = input.parse::>()?.is_some(); let lookahead = input.lookahead1(); if lookahead.peek(Token![const]) && (input.peek2(Ident) || input.peek2(Token![_])) { let flexible_item = FlexibleItemConst::parse(attrs, vis, defaultness, input)?; Ok(TraitItemVerbatim::ConstFlexible(flexible_item)) } else if lookahead.peek(Token![type]) { let flexible_item = FlexibleItemType::parse( attrs, vis, defaultness, input, WhereClauseLocation::AfterEq, )?; Ok(TraitItemVerbatim::TypeFlexible(flexible_item)) } else if (input.peek(Token![const]) || lookahead.peek(Token![async]) || lookahead.peek(Token![unsafe]) || lookahead.peek(Token![extern]) || lookahead.peek(Token![fn])) && (!matches!(vis, Visibility::Inherited) || defaultness) { Ok(TraitItemVerbatim::PubOrDefault(PubOrDefaultTraitItem { attrs, vis, defaultness, trait_item: input.parse()?, })) } else { Err(lookahead.error()) } } } let impl_item: TraitItemVerbatim = match syn::parse2(tokens.clone()) { Ok(impl_item) => impl_item, Err(_) => unimplemented!("TraitItem::Verbatim `{}`", tokens), }; match impl_item { TraitItemVerbatim::Empty => { self.hardbreak(); } TraitItemVerbatim::Ellipsis => { self.word("..."); self.hardbreak(); } TraitItemVerbatim::ConstFlexible(trait_item) => { self.flexible_item_const(&trait_item); } TraitItemVerbatim::TypeFlexible(trait_item) => { self.flexible_item_type(&trait_item); } TraitItemVerbatim::PubOrDefault(trait_item) => { self.outer_attrs(&trait_item.attrs); self.visibility(&trait_item.vis); if trait_item.defaultness { self.word("default "); } self.trait_item(&trait_item.trait_item); } } } fn impl_item(&mut self, impl_item: &ImplItem) { match impl_item { #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] ImplItem::Const(item) => self.impl_item_const(item), ImplItem::Fn(item) => self.impl_item_fn(item), ImplItem::Type(item) => self.impl_item_type(item), ImplItem::Macro(item) => self.impl_item_macro(item), ImplItem::Verbatim(item) => self.impl_item_verbatim(item), _ => unimplemented!("unknown ImplItem"), } } fn impl_item_const(&mut self, impl_item: &ImplItemConst) { self.outer_attrs(&impl_item.attrs); self.cbox(0); self.visibility(&impl_item.vis); if impl_item.defaultness.is_some() { self.word("default "); } self.word("const "); self.ident(&impl_item.ident); self.generics(&impl_item.generics); self.word(": "); self.ty(&impl_item.ty); self.word(" = "); self.neverbreak(); self.expr(&impl_item.expr); self.word(";"); self.end(); self.hardbreak(); } fn impl_item_fn(&mut self, impl_item: &ImplItemFn) { self.outer_attrs(&impl_item.attrs); self.cbox(INDENT); self.visibility(&impl_item.vis); if impl_item.defaultness.is_some() { self.word("default "); } self.signature(&impl_item.sig); self.where_clause_for_body(&impl_item.sig.generics.where_clause); self.word("{"); self.hardbreak_if_nonempty(); self.inner_attrs(&impl_item.attrs); for stmt in &impl_item.block.stmts { self.stmt(stmt); } self.offset(-INDENT); self.end(); self.word("}"); self.hardbreak(); } fn impl_item_type(&mut self, impl_item: &ImplItemType) { self.outer_attrs(&impl_item.attrs); self.cbox(INDENT); self.visibility(&impl_item.vis); if impl_item.defaultness.is_some() { self.word("default "); } self.word("type "); self.ident(&impl_item.ident); self.generics(&impl_item.generics); self.word(" = "); self.neverbreak(); self.ibox(-INDENT); self.ty(&impl_item.ty); self.end(); self.where_clause_oneline_semi(&impl_item.generics.where_clause); self.end(); self.hardbreak(); } fn impl_item_macro(&mut self, impl_item: &ImplItemMacro) { self.outer_attrs(&impl_item.attrs); let semicolon = true; self.mac(&impl_item.mac, None, semicolon); self.hardbreak(); } #[cfg(not(feature = "verbatim"))] fn impl_item_verbatim(&mut self, impl_item: &TokenStream) { if !impl_item.is_empty() { unimplemented!("ImplItem::Verbatim `{}`", impl_item); } self.hardbreak(); } #[cfg(feature = "verbatim")] fn impl_item_verbatim(&mut self, tokens: &TokenStream) { use syn::parse::{Parse, ParseStream, Result}; use syn::{Attribute, Ident, Token, Visibility}; use verbatim::{FlexibleItemConst, FlexibleItemFn, FlexibleItemType, WhereClauseLocation}; enum ImplItemVerbatim { Empty, Ellipsis, ConstFlexible(FlexibleItemConst), FnFlexible(FlexibleItemFn), TypeFlexible(FlexibleItemType), } impl Parse for ImplItemVerbatim { fn parse(input: ParseStream) -> Result { if input.is_empty() { return Ok(ImplItemVerbatim::Empty); } else if input.peek(Token![...]) { input.parse::()?; return Ok(ImplItemVerbatim::Ellipsis); } let attrs = input.call(Attribute::parse_outer)?; let vis: Visibility = input.parse()?; let defaultness = input.parse::>()?.is_some(); let lookahead = input.lookahead1(); if lookahead.peek(Token![const]) && (input.peek2(Ident) || input.peek2(Token![_])) { let flexible_item = FlexibleItemConst::parse(attrs, vis, defaultness, input)?; Ok(ImplItemVerbatim::ConstFlexible(flexible_item)) } else if input.peek(Token![const]) || lookahead.peek(Token![async]) || lookahead.peek(Token![unsafe]) || lookahead.peek(Token![extern]) || lookahead.peek(Token![fn]) { let flexible_item = FlexibleItemFn::parse(attrs, vis, defaultness, input)?; Ok(ImplItemVerbatim::FnFlexible(flexible_item)) } else if lookahead.peek(Token![type]) { let flexible_item = FlexibleItemType::parse( attrs, vis, defaultness, input, WhereClauseLocation::AfterEq, )?; Ok(ImplItemVerbatim::TypeFlexible(flexible_item)) } else { Err(lookahead.error()) } } } let impl_item: ImplItemVerbatim = match syn::parse2(tokens.clone()) { Ok(impl_item) => impl_item, Err(_) => unimplemented!("ImplItem::Verbatim `{}`", tokens), }; match impl_item { ImplItemVerbatim::Empty => { self.hardbreak(); } ImplItemVerbatim::Ellipsis => { self.word("..."); self.hardbreak(); } ImplItemVerbatim::ConstFlexible(impl_item) => { self.flexible_item_const(&impl_item); } ImplItemVerbatim::FnFlexible(impl_item) => { self.flexible_item_fn(&impl_item); } ImplItemVerbatim::TypeFlexible(impl_item) => { self.flexible_item_type(&impl_item); } } } fn signature(&mut self, signature: &Signature) { if signature.constness.is_some() { self.word("const "); } if signature.asyncness.is_some() { self.word("async "); } if signature.unsafety.is_some() { self.word("unsafe "); } if let Some(abi) = &signature.abi { self.abi(abi); } self.word("fn "); self.ident(&signature.ident); self.generics(&signature.generics); self.word("("); self.neverbreak(); self.cbox(0); self.zerobreak(); for input in signature.inputs.iter().delimited() { self.fn_arg(&input); let is_last = input.is_last && signature.variadic.is_none(); self.trailing_comma(is_last); } if let Some(variadic) = &signature.variadic { self.variadic(variadic); self.zerobreak(); } self.offset(-INDENT); self.end(); self.word(")"); self.cbox(-INDENT); self.return_type(&signature.output); self.end(); } fn fn_arg(&mut self, fn_arg: &FnArg) { match fn_arg { FnArg::Receiver(receiver) => self.receiver(receiver), FnArg::Typed(pat_type) => self.pat_type(pat_type), } } fn receiver(&mut self, receiver: &Receiver) { self.outer_attrs(&receiver.attrs); if let Some((_ampersand, lifetime)) = &receiver.reference { self.word("&"); if let Some(lifetime) = lifetime { self.lifetime(lifetime); self.nbsp(); } } if receiver.mutability.is_some() { self.word("mut "); } self.word("self"); if receiver.colon_token.is_some() { self.word(": "); self.ty(&receiver.ty); } else { let consistent = match (&receiver.reference, &receiver.mutability, &*receiver.ty) { (Some(_), mutability, Type::Reference(ty)) => { mutability.is_some() == ty.mutability.is_some() && match &*ty.elem { Type::Path(ty) => ty.qself.is_none() && ty.path.is_ident("Self"), _ => false, } } (None, _, Type::Path(ty)) => ty.qself.is_none() && ty.path.is_ident("Self"), _ => false, }; if !consistent { self.word(": "); self.ty(&receiver.ty); } } } fn variadic(&mut self, variadic: &Variadic) { self.outer_attrs(&variadic.attrs); if let Some((pat, _colon)) = &variadic.pat { self.pat(pat); self.word(": "); } self.word("..."); } fn static_mutability(&mut self, mutability: &StaticMutability) { match mutability { #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] StaticMutability::Mut(_) => self.word("mut "), StaticMutability::None => {} _ => unimplemented!("unknown StaticMutability"), } } } #[cfg(feature = "verbatim")] mod verbatim { use crate::algorithm::Printer; use crate::iter::IterDelimited; use crate::INDENT; use syn::ext::IdentExt; use syn::parse::{ParseStream, Result}; use syn::{ braced, token, Attribute, Block, Expr, Generics, Ident, Signature, StaticMutability, Stmt, Token, Type, TypeParamBound, Visibility, WhereClause, }; pub struct FlexibleItemConst { pub attrs: Vec, pub vis: Visibility, pub defaultness: bool, pub ident: Ident, pub generics: Generics, pub ty: Type, pub value: Option, } pub struct FlexibleItemFn { pub attrs: Vec, pub vis: Visibility, pub defaultness: bool, pub sig: Signature, pub body: Option>, } pub struct FlexibleItemStatic { pub attrs: Vec, pub vis: Visibility, pub mutability: StaticMutability, pub ident: Ident, pub ty: Option, pub expr: Option, } pub struct FlexibleItemType { pub attrs: Vec, pub vis: Visibility, pub defaultness: bool, pub ident: Ident, pub generics: Generics, pub bounds: Vec, pub definition: Option, pub where_clause_after_eq: Option, } pub enum WhereClauseLocation { // type Ty where T: 'static = T; BeforeEq, // type Ty = T where T: 'static; AfterEq, // TODO: goes away once the migration period on rust-lang/rust#89122 is over Both, } impl FlexibleItemConst { pub fn parse( attrs: Vec, vis: Visibility, defaultness: bool, input: ParseStream, ) -> Result { input.parse::()?; let ident = input.call(Ident::parse_any)?; let mut generics: Generics = input.parse()?; input.parse::()?; let ty: Type = input.parse()?; let value = if input.parse::>()?.is_some() { let expr: Expr = input.parse()?; Some(expr) } else { None }; generics.where_clause = input.parse()?; input.parse::()?; Ok(FlexibleItemConst { attrs, vis, defaultness, ident, generics, ty, value, }) } } impl FlexibleItemFn { pub fn parse( mut attrs: Vec, vis: Visibility, defaultness: bool, input: ParseStream, ) -> Result { let sig: Signature = input.parse()?; let lookahead = input.lookahead1(); let body = if lookahead.peek(Token![;]) { input.parse::()?; None } else if lookahead.peek(token::Brace) { let content; braced!(content in input); attrs.extend(content.call(Attribute::parse_inner)?); Some(content.call(Block::parse_within)?) } else { return Err(lookahead.error()); }; Ok(FlexibleItemFn { attrs, vis, defaultness, sig, body, }) } } impl FlexibleItemStatic { pub fn parse(attrs: Vec, vis: Visibility, input: ParseStream) -> Result { input.parse::()?; let mutability: StaticMutability = input.parse()?; let ident = input.parse()?; let lookahead = input.lookahead1(); let has_type = lookahead.peek(Token![:]); let has_expr = lookahead.peek(Token![=]); if !has_type && !has_expr { return Err(lookahead.error()); } let ty: Option = if has_type { input.parse::()?; input.parse().map(Some)? } else { None }; let expr: Option = if input.parse::>()?.is_some() { input.parse().map(Some)? } else { None }; input.parse::()?; Ok(FlexibleItemStatic { attrs, vis, mutability, ident, ty, expr, }) } } impl FlexibleItemType { pub fn parse( attrs: Vec, vis: Visibility, defaultness: bool, input: ParseStream, where_clause_location: WhereClauseLocation, ) -> Result { input.parse::()?; let ident: Ident = input.parse()?; let mut generics: Generics = input.parse()?; let mut bounds = Vec::new(); if input.parse::>()?.is_some() { loop { if input.peek(Token![where]) || input.peek(Token![=]) || input.peek(Token![;]) { break; } bounds.push(input.parse::()?); if input.peek(Token![where]) || input.peek(Token![=]) || input.peek(Token![;]) { break; } input.parse::()?; } } match where_clause_location { WhereClauseLocation::BeforeEq | WhereClauseLocation::Both => { generics.where_clause = input.parse()?; } WhereClauseLocation::AfterEq => {} } let definition = if input.parse::>()?.is_some() { Some(input.parse()?) } else { None }; let where_clause_after_eq = match where_clause_location { WhereClauseLocation::AfterEq | WhereClauseLocation::Both if generics.where_clause.is_none() => { input.parse()? } _ => None, }; input.parse::()?; Ok(FlexibleItemType { attrs, vis, defaultness, ident, generics, bounds, definition, where_clause_after_eq, }) } } impl Printer { pub fn flexible_item_const(&mut self, item: &FlexibleItemConst) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.visibility(&item.vis); if item.defaultness { self.word("default "); } self.word("const "); self.ident(&item.ident); self.generics(&item.generics); self.word(": "); self.cbox(-INDENT); self.ty(&item.ty); self.end(); if let Some(value) = &item.value { self.word(" = "); self.neverbreak(); self.ibox(-INDENT); self.expr(value); self.end(); } self.where_clause_oneline_semi(&item.generics.where_clause); self.end(); self.hardbreak(); } pub fn flexible_item_fn(&mut self, item: &FlexibleItemFn) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.visibility(&item.vis); if item.defaultness { self.word("default "); } self.signature(&item.sig); if let Some(body) = &item.body { self.where_clause_for_body(&item.sig.generics.where_clause); self.word("{"); self.hardbreak_if_nonempty(); self.inner_attrs(&item.attrs); for stmt in body { self.stmt(stmt); } self.offset(-INDENT); self.end(); self.word("}"); } else { self.where_clause_semi(&item.sig.generics.where_clause); self.end(); } self.hardbreak(); } pub fn flexible_item_static(&mut self, item: &FlexibleItemStatic) { self.outer_attrs(&item.attrs); self.cbox(0); self.visibility(&item.vis); self.word("static "); self.static_mutability(&item.mutability); self.ident(&item.ident); if let Some(ty) = &item.ty { self.word(": "); self.ty(ty); } if let Some(expr) = &item.expr { self.word(" = "); self.neverbreak(); self.expr(expr); } self.word(";"); self.end(); self.hardbreak(); } pub fn flexible_item_type(&mut self, item: &FlexibleItemType) { self.outer_attrs(&item.attrs); self.cbox(INDENT); self.visibility(&item.vis); if item.defaultness { self.word("default "); } self.word("type "); self.ident(&item.ident); self.generics(&item.generics); for bound in item.bounds.iter().delimited() { if bound.is_first { self.word(": "); } else { self.space(); self.word("+ "); } self.type_param_bound(&bound); } if let Some(definition) = &item.definition { self.where_clause_oneline(&item.generics.where_clause); self.word("= "); self.neverbreak(); self.ibox(-INDENT); self.ty(definition); self.end(); self.where_clause_oneline_semi(&item.where_clause_after_eq); } else { self.where_clause_oneline_semi(&item.generics.where_clause); } self.end(); self.hardbreak(); } } }