pin-project-internal 0.4.6

An internal crate to support pin_project - do not use directly
Documentation
use proc_macro2::TokenStream;
use quote::{format_ident, quote_spanned};
use syn::{
    parse::{ParseBuffer, ParseStream},
    punctuated::Punctuated,
    token::{self, Comma},
    *,
};

pub(crate) const DEFAULT_LIFETIME_NAME: &str = "'pin";
pub(crate) const CURRENT_PRIVATE_MODULE: &str = "__private";

pub(crate) type Variants = Punctuated<Variant, token::Comma>;

pub(crate) use Mutability::{Immutable, Mutable};

macro_rules! error {
    ($span:expr, $msg:expr) => {
        syn::Error::new_spanned(&$span, $msg)
    };
    ($span:expr, $($tt:tt)*) => {
        error!($span, format!($($tt)*))
    };
}

#[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) enum Mutability {
    Mutable,
    Immutable,
}

/// Creates the ident of projected type from the ident of the original type.
pub(crate) fn proj_ident(ident: &Ident, mutability: Mutability) -> Ident {
    if mutability == Mutable {
        format_ident!("__{}Projection", ident)
    } else {
        format_ident!("__{}ProjectionRef", ident)
    }
}

/// Determines the lifetime names. Ensure it doesn't overlap with any existing lifetime names.
pub(crate) fn determine_lifetime_name(
    lifetime_name: &mut String,
    generics: &Punctuated<GenericParam, Comma>,
) {
    let existing_lifetimes: Vec<String> = generics
        .iter()
        .filter_map(|param| {
            if let GenericParam::Lifetime(LifetimeDef { lifetime, .. }) = param {
                Some(lifetime.to_string())
            } else {
                None
            }
        })
        .collect();
    while existing_lifetimes.iter().any(|name| name.starts_with(&**lifetime_name)) {
        lifetime_name.push('_');
    }
}

/// Inserts a `lifetime` at position `0` of `generics.params`.
pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) {
    if generics.lt_token.is_none() {
        generics.lt_token = Some(token::Lt::default())
    }
    if generics.gt_token.is_none() {
        generics.gt_token = Some(token::Gt::default())
    }

    generics.params.insert(
        0,
        GenericParam::Lifetime(LifetimeDef {
            attrs: Vec::new(),
            lifetime,
            colon_token: None,
            bounds: Punctuated::new(),
        }),
    );
}

/// Determines the visibility of the projected type and projection method.
pub(crate) fn determine_visibility(vis: &Visibility) -> Visibility {
    if let Visibility::Public(token) = vis {
        syn::parse2(quote_spanned! { token.pub_token.span =>
            pub(crate)
        })
        .unwrap()
    } else {
        vis.clone()
    }
}

/// Check if `tokens` is an empty `TokenStream`.
/// This is almost equivalent to `syn::parse2::<Nothing>()`,
/// but produces a better error message and does not require ownership of `tokens`.
pub(crate) fn parse_as_empty(tokens: &TokenStream) -> Result<()> {
    if tokens.is_empty() { Ok(()) } else { Err(error!(tokens, "unexpected token: {}", tokens)) }
}

pub(crate) trait SliceExt {
    fn position_exact(&self, ident: &str) -> Result<Option<usize>>;
    fn find(&self, ident: &str) -> Option<&Attribute>;
    fn find_exact(&self, ident: &str) -> Result<Option<&Attribute>>;
}

pub(crate) trait VecExt {
    fn find_remove(&mut self, ident: &str) -> Result<Option<Attribute>>;
}

impl SliceExt for [Attribute] {
    fn position_exact(&self, ident: &str) -> Result<Option<usize>> {
        self.iter()
            .try_fold((0, None), |(i, mut prev), attr| {
                if attr.path.is_ident(ident) {
                    if prev.is_some() {
                        return Err(error!(attr, "duplicate #[{}] attribute", ident));
                    }
                    parse_as_empty(&attr.tokens)?;
                    prev = Some(i);
                }
                Ok((i + 1, prev))
            })
            .map(|(_, pos)| pos)
    }
    fn find(&self, ident: &str) -> Option<&Attribute> {
        self.iter().position(|attr| attr.path.is_ident(ident)).and_then(|i| self.get(i))
    }
    fn find_exact(&self, ident: &str) -> Result<Option<&Attribute>> {
        self.position_exact(ident).map(|pos| pos.and_then(|i| self.get(i)))
    }
}

impl VecExt for Vec<Attribute> {
    fn find_remove(&mut self, ident: &str) -> Result<Option<Attribute>> {
        self.position_exact(ident).map(|pos| pos.map(|i| self.remove(i)))
    }
}

pub(crate) trait ParseBufferExt<'a> {
    fn parenthesized(self) -> Result<ParseBuffer<'a>>;
}

impl<'a> ParseBufferExt<'a> for ParseStream<'a> {
    fn parenthesized(self) -> Result<ParseBuffer<'a>> {
        let content;
        let _: token::Paren = syn::parenthesized!(content in self);
        Ok(content)
    }
}

impl<'a> ParseBufferExt<'a> for ParseBuffer<'a> {
    fn parenthesized(self) -> Result<ParseBuffer<'a>> {
        let content;
        let _: token::Paren = syn::parenthesized!(content in self);
        Ok(content)
    }
}