proc-bitfield-macros 0.5.3

The supporting proc-macro library for the proc-bitfield crate
Documentation
use std::cell::Cell;

#[cfg(feature = "gce")]
use proc_macro2::Span;
#[cfg(feature = "gce")]
use quote::quote_spanned;
use quote::{format_ident, quote};
use syn::{
    braced, bracketed, parenthesized,
    parse::{Parse, ParseBuffer, ParseStream},
    punctuated::Punctuated,
    Ident, Result,
};
#[cfg(feature = "gce")]
use syn::{
    AttrStyle, Attribute, ConstParam, Expr, MacroDelimiter, MetaList, Type, TypeParam,
    TypeParamBound, WhereClause, WherePredicate,
};

pub fn for_all_int_types(mut f: impl FnMut(u8, bool, Ident)) {
    #[allow(clippy::unnecessary_lazy_evaluations)]
    for bits in core::iter::successors(Some(8_u8), |bits| (*bits < 128).then(|| *bits << 1)) {
        for signed in [true, false] {
            let ty_ident = format_ident!("{}{}", if signed { 'i' } else { 'u' }, bits);
            f(bits, signed, ty_ident)
        }
    }
}

pub fn parse_parens(input: ParseStream<'_>) -> Result<ParseBuffer<'_>> {
    let content;
    parenthesized!(content in input);
    Ok(content)
}

pub fn parse_brackets(input: ParseStream<'_>) -> Result<ParseBuffer<'_>> {
    let content;
    bracketed!(content in input);
    Ok(content)
}

pub fn parse_braces(input: ParseStream<'_>) -> Result<ParseBuffer<'_>> {
    let content;
    braced!(content in input);
    Ok(content)
}

pub fn maybe_const_assert(is_const: bool) -> proc_macro2::TokenStream {
    if is_const {
        quote! { ::proc_bitfield::__private::static_assertions::const_assert! }
    } else {
        quote! { ::core::assert! }
    }
}

#[cfg(feature = "gce")]
pub fn type_param(
    ident: Ident,
    bounds: impl IntoIterator<Item = TypeParamBound>,
    default: Option<Type>,
) -> TypeParam {
    TypeParam {
        attrs: Vec::new(),
        ident,
        colon_token: Default::default(),
        bounds: bounds.into_iter().collect(),
        eq_token: Default::default(),
        default,
    }
}

#[cfg(feature = "gce")]
pub fn const_param(ident: Ident, ty: Type, default: Option<Expr>) -> ConstParam {
    ConstParam {
        attrs: Vec::new(),
        const_token: Default::default(),
        ident,
        colon_token: Default::default(),
        ty,
        eq_token: Default::default(),
        default,
    }
}

pub struct MaybeRepeat {
    content: proc_macro2::TokenStream,
    was_consumed: Cell<bool>,
    after_first: Option<proc_macro2::TokenStream>,
}

impl MaybeRepeat {
    pub fn new(content: proc_macro2::TokenStream, should_repeat: bool) -> Self {
        MaybeRepeat {
            content,
            was_consumed: Cell::new(false),
            after_first: should_repeat.then(Default::default),
        }
    }

    pub fn get(&self) -> &proc_macro2::TokenStream {
        if let Some(after_first) = &self.after_first {
            if self.was_consumed.replace(true) {
                return after_first;
            }
        }
        &self.content
    }
}

pub fn parse_terminated<T, P: Parse>(
    input: ParseStream,
    mut parser: impl FnMut(ParseStream) -> syn::Result<T>,
) -> syn::Result<Punctuated<T, P>> {
    let mut punctuated = Punctuated::new();
    loop {
        if input.is_empty() {
            break;
        }
        let value = parser(input)?;
        punctuated.push_value(value);
        if input.is_empty() {
            break;
        }
        let punct = input.parse()?;
        punctuated.push_punct(punct);
    }
    Ok(punctuated)
}

#[cfg(feature = "gce")]
pub fn doc_hidden() -> Attribute {
    Attribute {
        pound_token: Default::default(),
        style: AttrStyle::Outer,
        bracket_token: Default::default(),
        meta: MetaList {
            path: Ident::new("doc", Span::call_site()).into(),
            delimiter: MacroDelimiter::Paren(Default::default()),
            tokens: quote! { hidden },
        }
        .into(),
    }
}

#[cfg(feature = "gce")]
pub fn min(a: &proc_macro2::TokenStream, b: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
    quote! {
        ::proc_bitfield::__private::min((#a), (#b))
    }
}

#[cfg(feature = "gce")]
pub fn sized_pred(value: &proc_macro2::TokenStream) -> WherePredicate {
    syn::parse2(quote! { [(); {#value}]: Sized }).unwrap()
}

#[cfg(feature = "gce")]
pub fn add_const_bounds(
    span: Span,
    where_clause: &mut WhereClause,
    ty: &Type,
    traits: &[proc_macro2::TokenStream],
) {
    where_clause.predicates.push(
        syn::parse2(quote_spanned! {
            span =>
            #(#ty: [const] #traits),*
        })
        .unwrap(),
    );
}