use crate::util::*;
use proc_macro::TokenStream;
use proc_macro2::Span;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use quote::ToTokens;
use syn::meta::ParseNestedMeta;
use syn::parse::Parse;
use syn::punctuated::Punctuated;
use syn::{Ident, Token};
#[derive(Default)]
struct Attrs {
crate_name: Option<syn::Path>,
from: Option<(Ident, Vec<Ident>)>,
}
fn parse_attr_from(meta: &ParseNestedMeta) -> syn::Result<syn::Ident> {
let _token = meta.input.parse::<Token![=]>()?;
let lit: syn::LitStr = meta.input.parse()?;
Ok(syn::Ident::new(lit.value().as_str(), Span::call_site()))
}
fn parse_attr_field(meta: &ParseNestedMeta) -> syn::Result<Vec<Ident>> {
let _token = meta.input.parse::<Token![=]>()?;
let lit: syn::LitStr = meta.input.parse()?;
let segments = lit
.value()
.as_str()
.split('.')
.map(|s| Ident::new(s, Span::call_site()))
.collect();
Ok(segments)
}
fn fold_attrs(mut state: Attrs, attr: &syn::Attribute) -> syn::Result<Attrs> {
if attr.path().is_ident("lol") {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("crate") {
let value: syn::Path = meta.value().and_then(|value| value.parse())?;
state.crate_name = Some(value);
Ok(())
} else if meta.path.is_ident("from") {
let from = parse_attr_from(&meta)?;
let _comma = meta.input.parse::<Token![,]>()?;
let attr: syn::Ident = meta.input.parse()?;
if attr == "field" {
let field = parse_attr_field(&meta)?;
state.from = Some((from, field));
Ok(())
} else {
Err(meta.error("Expected \"field\" attribute"))
}
} else {
Err(meta.error("Unexpected \"lol-io\" attributes"))
}
})?;
Ok(state)
} else {
Ok(state)
}
}
enum ConstAssignmentValue {
Lit(syn::LitInt),
Path(syn::Path),
}
impl Parse for ConstAssignmentValue {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(syn::LitInt) {
input.parse().map(ConstAssignmentValue::Lit)
} else if lookahead.peek(syn::Ident) {
input.parse().map(ConstAssignmentValue::Path)
} else {
Err(lookahead.error())
}
}
}
struct ConstAssignment {
visibility: Option<syn::Visibility>,
const_token: Token![const],
name: syn::Ident,
eq: Token![=],
value: ConstAssignmentValue,
}
impl ToTokens for ConstAssignment {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let vis = &self.visibility;
let const_token = self.const_token;
let name = &self.name;
let eq = self.eq;
let value = match &self.value {
ConstAssignmentValue::Lit(l) => l.into_token_stream(),
ConstAssignmentValue::Path(p) => p.into_token_stream(),
};
quote! {#vis #const_token #name: Self #eq Self(#value);}.to_tokens(tokens);
}
}
impl Parse for ConstAssignment {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
Ok(ConstAssignment {
visibility: input.parse().map(Some).unwrap_or(None),
const_token: input.parse()?,
name: input.parse()?,
eq: input.parse()?,
value: input.parse()?,
})
}
}
struct Const {
attrs: Vec<syn::Attribute>,
visibility: Option<syn::Visibility>,
struct_token: Token![struct],
name: syn::Ident,
_colon_token: Token![:],
ty: syn::Type,
_brace_token: syn::token::Brace,
assignments: Punctuated<ConstAssignment, Token![;]>,
}
impl ToTokens for Const {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let attrs = &self.attrs;
let visibility = &self.visibility;
let struct_token = self.struct_token;
let name = &self.name;
let ty = &self.ty;
let assignments = &self.assignments;
let assignment_tokens = assignments
.into_iter()
.map(|assignment| quote! {#assignment});
quote! {
#(#attrs)*
#[repr(transparent)]
#[derive(Clone, Copy, Default, Eq, PartialEq, Hash)]
#visibility #struct_token #name(#ty);
impl #name {
#(#assignment_tokens)*
pub fn raw(&self) -> #ty {
self.0
}
pub const unsafe fn from_raw(raw: #ty) -> Self {
Self(raw)
}
}
impl AsRef<#ty> for #name {
fn as_ref(&self) -> &#ty {
&self.0
}
}
}
.to_tokens(tokens);
}
}
impl Parse for Const {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let content;
let attrs = input.call(syn::Attribute::parse_outer)?;
Ok(Const {
attrs,
visibility: input.parse().map(Some).unwrap_or(None),
struct_token: input.parse()?,
name: input.parse()?,
_colon_token: input.parse()?,
ty: input.parse()?,
_brace_token: syn::braced!(content in input),
assignments: content.parse_terminated(ConstAssignment::parse, Token![;])?,
})
}
}
pub struct Items(pub Vec<TokenStream2>);
impl Parse for Items {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let mut tokens = Vec::new();
while !input.is_empty() {
tokens.push(input.parse::<Const>()?.into_token_stream());
}
Ok(Items(tokens))
}
}
pub(crate) fn make_expanded(toks: TokenStream) -> syn::Result<TokenStream2> {
let items: Items = syn::parse(toks)?;
Ok(items.0.into_iter().collect())
}
pub(crate) fn derive_native_bit_flag(toks: TokenStream) -> syn::Result<TokenStream2> {
let input = syn::parse::<syn::DeriveInput>(toks)?;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let name = &input.ident;
let attrs = input.attrs.iter().try_fold(Attrs::default(), fold_attrs)?;
let crate_name = attrs.crate_name.unwrap_or_else(resolve_crate);
let from = attrs.from.map(|(from, member)| {
quote! {
impl #impl_generics #name #ty_generics #where_clause {
pub fn parse(other: &#from) -> Self {
unsafe { Self::from_raw(other.#(#member).*) }
}
}
}
});
let impl_bitand = quote! {
impl #impl_generics std::ops::BitAnd #ty_generics #where_clause for #name {
type Output = #name;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
};
let impl_bitand_assign = quote! {
impl #impl_generics std::ops::BitAndAssign #ty_generics #where_clause for #name {
fn bitand_assign(&mut self, rhs: Self) {
*self = Self(self.0 & rhs.0)
}
}
};
let impl_bitor = quote! {
impl #impl_generics std::ops::BitOr #ty_generics #where_clause for #name {
type Output = #name;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
};
let impl_bitor_assign = quote! {
impl #impl_generics std::ops::BitOrAssign #ty_generics #where_clause for #name {
fn bitor_assign(&mut self, rhs: Self) {
*self = Self(self.0 | rhs.0)
}
}
};
let impl_bitxor = quote! {
impl #impl_generics std::ops::BitXor #ty_generics #where_clause for #name {
type Output = #name;
fn bitxor(self, rhs: Self) -> Self::Output {
Self(self.0 ^ rhs.0)
}
}
};
let impl_bitxor_assign = quote! {
impl #impl_generics std::ops::BitXorAssign #ty_generics #where_clause for #name {
fn bitxor_assign(&mut self, rhs: Self) {
*self = Self(self.0 ^ rhs.0)
}
}
};
let impl_not = quote! {
impl #impl_generics std::ops::Not #ty_generics #where_clause for #name {
type Output = #name;
fn not(self) -> Self::Output {
Self(!self.0)
}
}
};
Ok(quote! {
impl #impl_generics #crate_name::kernel::co::NativeBitFlags for #name #ty_generics #where_clause {
}
#from
#impl_bitand
#impl_bitand_assign
#impl_bitor
#impl_bitor_assign
#impl_bitxor
#impl_bitxor_assign
#impl_not
})
}