| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968 |
- // SPDX-License-Identifier: Apache-2.0 OR MIT
- #[cfg(feature = "parsing")]
- use crate::error::Result;
- use crate::expr::Expr;
- use crate::generics::TypeParamBound;
- use crate::ident::Ident;
- use crate::lifetime::Lifetime;
- use crate::punctuated::Punctuated;
- use crate::token;
- use crate::ty::{ReturnType, Type};
- ast_struct! {
- /// A path at which a named item is exported (e.g. `std::collections::HashMap`).
- #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
- pub struct Path {
- pub leading_colon: Option<Token![::]>,
- pub segments: Punctuated<PathSegment, Token![::]>,
- }
- }
- impl<T> From<T> for Path
- where
- T: Into<PathSegment>,
- {
- fn from(segment: T) -> Self {
- let mut path = Path {
- leading_colon: None,
- segments: Punctuated::new(),
- };
- path.segments.push_value(segment.into());
- path
- }
- }
- impl Path {
- /// Determines whether this is a path of length 1 equal to the given
- /// ident.
- ///
- /// For them to compare equal, it must be the case that:
- ///
- /// - the path has no leading colon,
- /// - the number of path segments is 1,
- /// - the first path segment has no angle bracketed or parenthesized
- /// path arguments, and
- /// - the ident of the first path segment is equal to the given one.
- ///
- /// # Example
- ///
- /// ```
- /// use proc_macro2::TokenStream;
- /// use syn::{Attribute, Error, Meta, Result};
- ///
- /// fn get_serde_meta_item(attr: &Attribute) -> Result<Option<&TokenStream>> {
- /// if attr.path().is_ident("serde") {
- /// match &attr.meta {
- /// Meta::List(meta) => Ok(Some(&meta.tokens)),
- /// bad => Err(Error::new_spanned(bad, "unrecognized attribute")),
- /// }
- /// } else {
- /// Ok(None)
- /// }
- /// }
- /// ```
- pub fn is_ident<I>(&self, ident: &I) -> bool
- where
- I: ?Sized,
- Ident: PartialEq<I>,
- {
- match self.get_ident() {
- Some(id) => id == ident,
- None => false,
- }
- }
- /// If this path consists of a single ident, returns the ident.
- ///
- /// A path is considered an ident if:
- ///
- /// - the path has no leading colon,
- /// - the number of path segments is 1, and
- /// - the first path segment has no angle bracketed or parenthesized
- /// path arguments.
- pub fn get_ident(&self) -> Option<&Ident> {
- if self.leading_colon.is_none()
- && self.segments.len() == 1
- && self.segments[0].arguments.is_none()
- {
- Some(&self.segments[0].ident)
- } else {
- None
- }
- }
- /// An error if this path is not a single ident, as defined in `get_ident`.
- #[cfg(feature = "parsing")]
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- pub fn require_ident(&self) -> Result<&Ident> {
- self.get_ident().ok_or_else(|| {
- crate::error::new2(
- self.segments.first().unwrap().ident.span(),
- self.segments.last().unwrap().ident.span(),
- "expected this path to be an identifier",
- )
- })
- }
- }
- ast_struct! {
- /// A segment of a path together with any path arguments on that segment.
- #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
- pub struct PathSegment {
- pub ident: Ident,
- pub arguments: PathArguments,
- }
- }
- impl<T> From<T> for PathSegment
- where
- T: Into<Ident>,
- {
- fn from(ident: T) -> Self {
- PathSegment {
- ident: ident.into(),
- arguments: PathArguments::None,
- }
- }
- }
- ast_enum! {
- /// Angle bracketed or parenthesized arguments of a path segment.
- ///
- /// ## Angle bracketed
- ///
- /// The `<'a, T>` in `std::slice::iter<'a, T>`.
- ///
- /// ## Parenthesized
- ///
- /// The `(A, B) -> C` in `Fn(A, B) -> C`.
- #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
- pub enum PathArguments {
- None,
- /// The `<'a, T>` in `std::slice::iter<'a, T>`.
- AngleBracketed(AngleBracketedGenericArguments),
- /// The `(A, B) -> C` in `Fn(A, B) -> C`.
- Parenthesized(ParenthesizedGenericArguments),
- }
- }
- impl Default for PathArguments {
- fn default() -> Self {
- PathArguments::None
- }
- }
- impl PathArguments {
- pub fn is_empty(&self) -> bool {
- match self {
- PathArguments::None => true,
- PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(),
- PathArguments::Parenthesized(_) => false,
- }
- }
- pub fn is_none(&self) -> bool {
- match self {
- PathArguments::None => true,
- PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
- }
- }
- }
- ast_enum! {
- /// An individual generic argument, like `'a`, `T`, or `Item = T`.
- #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
- #[non_exhaustive]
- pub enum GenericArgument {
- /// A lifetime argument.
- Lifetime(Lifetime),
- /// A type argument.
- Type(Type),
- /// A const expression. Must be inside of a block.
- ///
- /// NOTE: Identity expressions are represented as Type arguments, as
- /// they are indistinguishable syntactically.
- Const(Expr),
- /// A binding (equality constraint) on an associated type: the `Item =
- /// u8` in `Iterator<Item = u8>`.
- AssocType(AssocType),
- /// An equality constraint on an associated constant: the `PANIC =
- /// false` in `Trait<PANIC = false>`.
- AssocConst(AssocConst),
- /// An associated type bound: `Iterator<Item: Display>`.
- Constraint(Constraint),
- }
- }
- ast_struct! {
- /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
- /// V>`.
- #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
- pub struct AngleBracketedGenericArguments {
- pub colon2_token: Option<Token![::]>,
- pub lt_token: Token![<],
- pub args: Punctuated<GenericArgument, Token![,]>,
- pub gt_token: Token![>],
- }
- }
- ast_struct! {
- /// A binding (equality constraint) on an associated type: the `Item = u8`
- /// in `Iterator<Item = u8>`.
- #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
- pub struct AssocType {
- pub ident: Ident,
- pub generics: Option<AngleBracketedGenericArguments>,
- pub eq_token: Token![=],
- pub ty: Type,
- }
- }
- ast_struct! {
- /// An equality constraint on an associated constant: the `PANIC = false` in
- /// `Trait<PANIC = false>`.
- #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
- pub struct AssocConst {
- pub ident: Ident,
- pub generics: Option<AngleBracketedGenericArguments>,
- pub eq_token: Token![=],
- pub value: Expr,
- }
- }
- ast_struct! {
- /// An associated type bound: `Iterator<Item: Display>`.
- #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
- pub struct Constraint {
- pub ident: Ident,
- pub generics: Option<AngleBracketedGenericArguments>,
- pub colon_token: Token![:],
- pub bounds: Punctuated<TypeParamBound, Token![+]>,
- }
- }
- ast_struct! {
- /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
- /// C`.
- #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
- pub struct ParenthesizedGenericArguments {
- pub paren_token: token::Paren,
- /// `(A, B)`
- pub inputs: Punctuated<Type, Token![,]>,
- /// `C`
- pub output: ReturnType,
- }
- }
- ast_struct! {
- /// The explicit Self type in a qualified path: the `T` in `<T as
- /// Display>::fmt`.
- ///
- /// The actual path, including the trait and the associated item, is stored
- /// separately. The `position` field represents the index of the associated
- /// item qualified with this Self type.
- ///
- /// ```text
- /// <Vec<T> as a::b::Trait>::AssociatedItem
- /// ^~~~~~ ~~~~~~~~~~~~~~^
- /// ty position = 3
- ///
- /// <Vec<T>>::AssociatedItem
- /// ^~~~~~ ^
- /// ty position = 0
- /// ```
- #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
- pub struct QSelf {
- pub lt_token: Token![<],
- pub ty: Box<Type>,
- pub position: usize,
- pub as_token: Option<Token![as]>,
- pub gt_token: Token![>],
- }
- }
- #[cfg(feature = "parsing")]
- pub(crate) mod parsing {
- use crate::error::Result;
- #[cfg(feature = "full")]
- use crate::expr::ExprBlock;
- use crate::expr::{Expr, ExprPath};
- use crate::ext::IdentExt as _;
- #[cfg(feature = "full")]
- use crate::generics::TypeParamBound;
- use crate::ident::Ident;
- use crate::lifetime::Lifetime;
- use crate::lit::Lit;
- use crate::parse::{Parse, ParseStream};
- #[cfg(feature = "full")]
- use crate::path::Constraint;
- use crate::path::{
- AngleBracketedGenericArguments, AssocConst, AssocType, GenericArgument,
- ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
- };
- use crate::punctuated::Punctuated;
- use crate::token;
- use crate::ty::{ReturnType, Type};
- #[cfg(not(feature = "full"))]
- use crate::verbatim;
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for Path {
- fn parse(input: ParseStream) -> Result<Self> {
- Self::parse_helper(input, false)
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for GenericArgument {
- fn parse(input: ParseStream) -> Result<Self> {
- if input.peek(Lifetime) && !input.peek2(Token![+]) {
- return Ok(GenericArgument::Lifetime(input.parse()?));
- }
- if input.peek(Lit) || input.peek(token::Brace) {
- return const_argument(input).map(GenericArgument::Const);
- }
- let mut argument: Type = input.parse()?;
- match argument {
- Type::Path(mut ty)
- if ty.qself.is_none()
- && ty.path.leading_colon.is_none()
- && ty.path.segments.len() == 1
- && match &ty.path.segments[0].arguments {
- PathArguments::None | PathArguments::AngleBracketed(_) => true,
- PathArguments::Parenthesized(_) => false,
- } =>
- {
- if let Some(eq_token) = input.parse::<Option<Token![=]>>()? {
- let segment = ty.path.segments.pop().unwrap().into_value();
- let ident = segment.ident;
- let generics = match segment.arguments {
- PathArguments::None => None,
- PathArguments::AngleBracketed(arguments) => Some(arguments),
- PathArguments::Parenthesized(_) => unreachable!(),
- };
- return if input.peek(Lit) || input.peek(token::Brace) {
- Ok(GenericArgument::AssocConst(AssocConst {
- ident,
- generics,
- eq_token,
- value: const_argument(input)?,
- }))
- } else {
- Ok(GenericArgument::AssocType(AssocType {
- ident,
- generics,
- eq_token,
- ty: input.parse()?,
- }))
- };
- }
- #[cfg(feature = "full")]
- if let Some(colon_token) = input.parse::<Option<Token![:]>>()? {
- let segment = ty.path.segments.pop().unwrap().into_value();
- return Ok(GenericArgument::Constraint(Constraint {
- ident: segment.ident,
- generics: match segment.arguments {
- PathArguments::None => None,
- PathArguments::AngleBracketed(arguments) => Some(arguments),
- PathArguments::Parenthesized(_) => unreachable!(),
- },
- colon_token,
- bounds: {
- let mut bounds = Punctuated::new();
- loop {
- if input.peek(Token![,]) || input.peek(Token![>]) {
- break;
- }
- bounds.push_value({
- let allow_precise_capture = false;
- let allow_const = true;
- TypeParamBound::parse_single(
- input,
- allow_precise_capture,
- allow_const,
- )?
- });
- if !input.peek(Token![+]) {
- break;
- }
- let punct: Token![+] = input.parse()?;
- bounds.push_punct(punct);
- }
- bounds
- },
- }));
- }
- argument = Type::Path(ty);
- }
- _ => {}
- }
- Ok(GenericArgument::Type(argument))
- }
- }
- pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> {
- let lookahead = input.lookahead1();
- if input.peek(Lit) {
- let lit = input.parse()?;
- return Ok(Expr::Lit(lit));
- }
- if input.peek(Ident) {
- let ident: Ident = input.parse()?;
- return Ok(Expr::Path(ExprPath {
- attrs: Vec::new(),
- qself: None,
- path: Path::from(ident),
- }));
- }
- if input.peek(token::Brace) {
- #[cfg(feature = "full")]
- {
- let block: ExprBlock = input.parse()?;
- return Ok(Expr::Block(block));
- }
- #[cfg(not(feature = "full"))]
- {
- let begin = input.fork();
- let content;
- braced!(content in input);
- content.parse::<Expr>()?;
- let verbatim = verbatim::between(&begin, input);
- return Ok(Expr::Verbatim(verbatim));
- }
- }
- Err(lookahead.error())
- }
- impl AngleBracketedGenericArguments {
- /// Parse `::<…>` with mandatory leading `::`.
- ///
- /// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments`
- /// parses optional leading `::`.
- #[cfg(feature = "full")]
- #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))]
- pub fn parse_turbofish(input: ParseStream) -> Result<Self> {
- let colon2_token: Token![::] = input.parse()?;
- Self::do_parse(Some(colon2_token), input)
- }
- pub(crate) fn do_parse(
- colon2_token: Option<Token![::]>,
- input: ParseStream,
- ) -> Result<Self> {
- Ok(AngleBracketedGenericArguments {
- colon2_token,
- lt_token: input.parse()?,
- args: {
- let mut args = Punctuated::new();
- loop {
- if input.peek(Token![>]) {
- break;
- }
- let value: GenericArgument = input.parse()?;
- args.push_value(value);
- if input.peek(Token![>]) {
- break;
- }
- let punct: Token![,] = input.parse()?;
- args.push_punct(punct);
- }
- args
- },
- gt_token: input.parse()?,
- })
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for AngleBracketedGenericArguments {
- fn parse(input: ParseStream) -> Result<Self> {
- let colon2_token: Option<Token![::]> = input.parse()?;
- Self::do_parse(colon2_token, input)
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for ParenthesizedGenericArguments {
- fn parse(input: ParseStream) -> Result<Self> {
- let content;
- Ok(ParenthesizedGenericArguments {
- paren_token: parenthesized!(content in input),
- inputs: content.parse_terminated(Type::parse, Token![,])?,
- output: input.call(ReturnType::without_plus)?,
- })
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- impl Parse for PathSegment {
- fn parse(input: ParseStream) -> Result<Self> {
- Self::parse_helper(input, false)
- }
- }
- impl PathSegment {
- fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
- if input.peek(Token![super])
- || input.peek(Token![self])
- || input.peek(Token![crate])
- || cfg!(feature = "full") && input.peek(Token![try])
- {
- let ident = input.call(Ident::parse_any)?;
- return Ok(PathSegment::from(ident));
- }
- let ident = if input.peek(Token![Self]) {
- input.call(Ident::parse_any)?
- } else {
- input.parse()?
- };
- if !expr_style
- && input.peek(Token![<])
- && !input.peek(Token![<=])
- && !input.peek(Token![<<=])
- || input.peek(Token![::]) && input.peek3(Token![<])
- {
- Ok(PathSegment {
- ident,
- arguments: PathArguments::AngleBracketed(input.parse()?),
- })
- } else {
- Ok(PathSegment::from(ident))
- }
- }
- }
- impl Path {
- /// Parse a `Path` containing no path arguments on any of its segments.
- ///
- /// # Example
- ///
- /// ```
- /// use syn::{Path, Result, Token};
- /// use syn::parse::{Parse, ParseStream};
- ///
- /// // A simplified single `use` statement like:
- /// //
- /// // use std::collections::HashMap;
- /// //
- /// // Note that generic parameters are not allowed in a `use` statement
- /// // so the following must not be accepted.
- /// //
- /// // use a::<b>::c;
- /// struct SingleUse {
- /// use_token: Token![use],
- /// path: Path,
- /// }
- ///
- /// impl Parse for SingleUse {
- /// fn parse(input: ParseStream) -> Result<Self> {
- /// Ok(SingleUse {
- /// use_token: input.parse()?,
- /// path: input.call(Path::parse_mod_style)?,
- /// })
- /// }
- /// }
- /// ```
- #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
- pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
- Ok(Path {
- leading_colon: input.parse()?,
- segments: {
- let mut segments = Punctuated::new();
- loop {
- if !input.peek(Ident)
- && !input.peek(Token![super])
- && !input.peek(Token![self])
- && !input.peek(Token![Self])
- && !input.peek(Token![crate])
- {
- break;
- }
- let ident = Ident::parse_any(input)?;
- segments.push_value(PathSegment::from(ident));
- if !input.peek(Token![::]) {
- break;
- }
- let punct = input.parse()?;
- segments.push_punct(punct);
- }
- if segments.is_empty() {
- return Err(input.parse::<Ident>().unwrap_err());
- } else if segments.trailing_punct() {
- return Err(input.error("expected path segment after `::`"));
- }
- segments
- },
- })
- }
- pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
- let mut path = Path {
- leading_colon: input.parse()?,
- segments: {
- let mut segments = Punctuated::new();
- let value = PathSegment::parse_helper(input, expr_style)?;
- segments.push_value(value);
- segments
- },
- };
- Path::parse_rest(input, &mut path, expr_style)?;
- Ok(path)
- }
- pub(crate) fn parse_rest(
- input: ParseStream,
- path: &mut Self,
- expr_style: bool,
- ) -> Result<()> {
- while input.peek(Token![::]) && !input.peek3(token::Paren) {
- let punct: Token![::] = input.parse()?;
- path.segments.push_punct(punct);
- let value = PathSegment::parse_helper(input, expr_style)?;
- path.segments.push_value(value);
- }
- Ok(())
- }
- pub(crate) fn is_mod_style(&self) -> bool {
- self.segments
- .iter()
- .all(|segment| segment.arguments.is_none())
- }
- }
- pub(crate) fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
- if input.peek(Token![<]) {
- let lt_token: Token![<] = input.parse()?;
- let this: Type = input.parse()?;
- let path = if input.peek(Token![as]) {
- let as_token: Token![as] = input.parse()?;
- let path: Path = input.parse()?;
- Some((as_token, path))
- } else {
- None
- };
- let gt_token: Token![>] = input.parse()?;
- let colon2_token: Token![::] = input.parse()?;
- let mut rest = Punctuated::new();
- loop {
- let path = PathSegment::parse_helper(input, expr_style)?;
- rest.push_value(path);
- if !input.peek(Token![::]) {
- break;
- }
- let punct: Token![::] = input.parse()?;
- rest.push_punct(punct);
- }
- let (position, as_token, path) = match path {
- Some((as_token, mut path)) => {
- let pos = path.segments.len();
- path.segments.push_punct(colon2_token);
- path.segments.extend(rest.into_pairs());
- (pos, Some(as_token), path)
- }
- None => {
- let path = Path {
- leading_colon: Some(colon2_token),
- segments: rest,
- };
- (0, None, path)
- }
- };
- let qself = QSelf {
- lt_token,
- ty: Box::new(this),
- position,
- as_token,
- gt_token,
- };
- Ok((Some(qself), path))
- } else {
- let path = Path::parse_helper(input, expr_style)?;
- Ok((None, path))
- }
- }
- }
- #[cfg(feature = "printing")]
- pub(crate) mod printing {
- use crate::generics;
- use crate::path::{
- AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
- ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
- };
- use crate::print::TokensOrDefault;
- #[cfg(feature = "parsing")]
- use crate::spanned::Spanned;
- #[cfg(feature = "parsing")]
- use proc_macro2::Span;
- use proc_macro2::TokenStream;
- use quote::ToTokens;
- use std::cmp;
- pub(crate) enum PathStyle {
- Expr,
- Mod,
- AsWritten,
- }
- impl Copy for PathStyle {}
- impl Clone for PathStyle {
- fn clone(&self) -> Self {
- *self
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for Path {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- print_path(tokens, self, PathStyle::AsWritten);
- }
- }
- pub(crate) fn print_path(tokens: &mut TokenStream, path: &Path, style: PathStyle) {
- path.leading_colon.to_tokens(tokens);
- for segment in path.segments.pairs() {
- print_path_segment(tokens, segment.value(), style);
- segment.punct().to_tokens(tokens);
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for PathSegment {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- print_path_segment(tokens, self, PathStyle::AsWritten);
- }
- }
- fn print_path_segment(tokens: &mut TokenStream, segment: &PathSegment, style: PathStyle) {
- segment.ident.to_tokens(tokens);
- print_path_arguments(tokens, &segment.arguments, style);
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for PathArguments {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- print_path_arguments(tokens, self, PathStyle::AsWritten);
- }
- }
- fn print_path_arguments(tokens: &mut TokenStream, arguments: &PathArguments, style: PathStyle) {
- match arguments {
- PathArguments::None => {}
- PathArguments::AngleBracketed(arguments) => {
- print_angle_bracketed_generic_arguments(tokens, arguments, style);
- }
- PathArguments::Parenthesized(arguments) => {
- print_parenthesized_generic_arguments(tokens, arguments, style);
- }
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for GenericArgument {
- #[allow(clippy::match_same_arms)]
- fn to_tokens(&self, tokens: &mut TokenStream) {
- match self {
- GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
- GenericArgument::Type(ty) => ty.to_tokens(tokens),
- GenericArgument::Const(expr) => {
- generics::printing::print_const_argument(expr, tokens);
- }
- GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens),
- GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens),
- GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens),
- }
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for AngleBracketedGenericArguments {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- print_angle_bracketed_generic_arguments(tokens, self, PathStyle::AsWritten);
- }
- }
- pub(crate) fn print_angle_bracketed_generic_arguments(
- tokens: &mut TokenStream,
- arguments: &AngleBracketedGenericArguments,
- style: PathStyle,
- ) {
- if let PathStyle::Mod = style {
- return;
- }
- conditionally_print_turbofish(tokens, &arguments.colon2_token, style);
- arguments.lt_token.to_tokens(tokens);
- // Print lifetimes before types/consts/bindings, regardless of their
- // order in args.
- let mut trailing_or_empty = true;
- for param in arguments.args.pairs() {
- match param.value() {
- GenericArgument::Lifetime(_) => {
- param.to_tokens(tokens);
- trailing_or_empty = param.punct().is_some();
- }
- GenericArgument::Type(_)
- | GenericArgument::Const(_)
- | GenericArgument::AssocType(_)
- | GenericArgument::AssocConst(_)
- | GenericArgument::Constraint(_) => {}
- }
- }
- for param in arguments.args.pairs() {
- match param.value() {
- GenericArgument::Type(_)
- | GenericArgument::Const(_)
- | GenericArgument::AssocType(_)
- | GenericArgument::AssocConst(_)
- | GenericArgument::Constraint(_) => {
- if !trailing_or_empty {
- <Token![,]>::default().to_tokens(tokens);
- }
- param.to_tokens(tokens);
- trailing_or_empty = param.punct().is_some();
- }
- GenericArgument::Lifetime(_) => {}
- }
- }
- arguments.gt_token.to_tokens(tokens);
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for AssocType {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.ident.to_tokens(tokens);
- self.generics.to_tokens(tokens);
- self.eq_token.to_tokens(tokens);
- self.ty.to_tokens(tokens);
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for AssocConst {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.ident.to_tokens(tokens);
- self.generics.to_tokens(tokens);
- self.eq_token.to_tokens(tokens);
- generics::printing::print_const_argument(&self.value, tokens);
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for Constraint {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.ident.to_tokens(tokens);
- self.generics.to_tokens(tokens);
- self.colon_token.to_tokens(tokens);
- self.bounds.to_tokens(tokens);
- }
- }
- #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
- impl ToTokens for ParenthesizedGenericArguments {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- print_parenthesized_generic_arguments(tokens, self, PathStyle::AsWritten);
- }
- }
- fn print_parenthesized_generic_arguments(
- tokens: &mut TokenStream,
- arguments: &ParenthesizedGenericArguments,
- style: PathStyle,
- ) {
- if let PathStyle::Mod = style {
- return;
- }
- conditionally_print_turbofish(tokens, &None, style);
- arguments.paren_token.surround(tokens, |tokens| {
- arguments.inputs.to_tokens(tokens);
- });
- arguments.output.to_tokens(tokens);
- }
- pub(crate) fn print_qpath(
- tokens: &mut TokenStream,
- qself: &Option<QSelf>,
- path: &Path,
- style: PathStyle,
- ) {
- let qself = match qself {
- Some(qself) => qself,
- None => {
- print_path(tokens, path, style);
- return;
- }
- };
- qself.lt_token.to_tokens(tokens);
- qself.ty.to_tokens(tokens);
- let pos = cmp::min(qself.position, path.segments.len());
- let mut segments = path.segments.pairs();
- if pos > 0 {
- TokensOrDefault(&qself.as_token).to_tokens(tokens);
- path.leading_colon.to_tokens(tokens);
- for (i, segment) in segments.by_ref().take(pos).enumerate() {
- print_path_segment(tokens, segment.value(), PathStyle::AsWritten);
- if i + 1 == pos {
- qself.gt_token.to_tokens(tokens);
- }
- segment.punct().to_tokens(tokens);
- }
- } else {
- qself.gt_token.to_tokens(tokens);
- path.leading_colon.to_tokens(tokens);
- }
- for segment in segments {
- print_path_segment(tokens, segment.value(), style);
- segment.punct().to_tokens(tokens);
- }
- }
- fn conditionally_print_turbofish(
- tokens: &mut TokenStream,
- colon2_token: &Option<Token![::]>,
- style: PathStyle,
- ) {
- match style {
- PathStyle::Expr => TokensOrDefault(colon2_token).to_tokens(tokens),
- PathStyle::Mod => unreachable!(),
- PathStyle::AsWritten => colon2_token.to_tokens(tokens),
- }
- }
- #[cfg(feature = "parsing")]
- #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
- impl Spanned for QSelf {
- fn span(&self) -> Span {
- struct QSelfDelimiters<'a>(&'a QSelf);
- impl<'a> ToTokens for QSelfDelimiters<'a> {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.0.lt_token.to_tokens(tokens);
- self.0.gt_token.to_tokens(tokens);
- }
- }
- QSelfDelimiters(self).span()
- }
- }
- }
|