use super::{kw, Modifier, Mutability, Override, Visibility};
use proc_macro2::Span;
use std::{
collections::HashSet,
fmt,
hash::{Hash, Hasher},
mem,
ops::{Deref, DerefMut},
};
use syn::{
ext::IdentExt,
parse::{Parse, ParseStream},
token::Brace,
Error, Ident, Result, Token,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FunctionAttributes(pub HashSet<FunctionAttribute>);
impl Deref for FunctionAttributes {
type Target = HashSet<FunctionAttribute>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for FunctionAttributes {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Parse for FunctionAttributes {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let mut attributes = HashSet::<FunctionAttribute>::new();
while !(input.is_empty()
|| input.peek(kw::returns)
|| input.peek(Token![;])
|| input.peek(Brace))
{
let attr = input.parse()?;
if let Some(prev) = attributes.get(&attr) {
let mut e = Error::new(attr.span(), "duplicate attribute");
e.combine(Error::new(prev.span(), "previous declaration is here"));
return Err(e)
}
attributes.insert(attr);
}
Ok(Self(attributes))
}
}
#[derive(Clone)]
pub enum FunctionAttribute {
Visibility(Visibility),
Mutability(Mutability),
Virtual(kw::Virtual),
Immutable(kw::immutable),
Override(Override),
Modifier(Modifier),
}
impl fmt::Display for FunctionAttribute {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Visibility(visibility) => visibility.fmt(f),
Self::Mutability(mutability) => mutability.fmt(f),
Self::Virtual(_) => f.write_str("virtual"),
Self::Immutable(_) => f.write_str("immutable"),
Self::Override(o) => o.fmt(f),
Self::Modifier(modifier) => modifier.fmt(f),
}
}
}
impl fmt::Debug for FunctionAttribute {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Visibility(visibility) => f.debug_tuple("Visibility").field(visibility).finish(),
Self::Mutability(mutability) => f.debug_tuple("Mutability").field(mutability).finish(),
Self::Virtual(_) => f.write_str("Virtual"),
Self::Immutable(_) => f.write_str("immutable"),
Self::Override(o) => o.fmt(f),
Self::Modifier(modifier) => modifier.fmt(f),
}
}
}
impl PartialEq for FunctionAttribute {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Modifier(a), Self::Modifier(b)) => a == b,
_ => mem::discriminant(self) == mem::discriminant(other),
}
}
}
impl Eq for FunctionAttribute {}
impl Hash for FunctionAttribute {
fn hash<H: Hasher>(&self, state: &mut H) {
mem::discriminant(self).hash(state);
if let Self::Modifier(m) = self {
m.hash(state);
}
}
}
impl Parse for FunctionAttribute {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let lookahead = input.lookahead1();
if Visibility::peek(&lookahead) {
input.parse().map(Self::Visibility)
} else if Mutability::peek(&lookahead) {
input.parse().map(Self::Mutability)
} else if lookahead.peek(kw::Virtual) {
input.parse().map(Self::Virtual)
} else if lookahead.peek(kw::Override) {
input.parse().map(Self::Override)
} else if lookahead.peek(kw::immutable) {
input.parse().map(Self::Immutable)
} else if !input.peek(kw::returns) && lookahead.peek(Ident::peek_any) {
input.parse().map(Self::Modifier)
} else if input.peek(Brace) {
Err(input.error("functions cannot have an implementation"))
} else {
Err(lookahead.error())
}
}
}
impl FunctionAttribute {
pub fn span(&self) -> Span {
match self {
Self::Visibility(v) => v.span(),
Self::Mutability(m) => m.span(),
Self::Virtual(v) => v.span,
Self::Override(o) => o.span(),
Self::Immutable(i) => i.span,
Self::Modifier(m) => m.span(),
}
}
pub fn set_span(&mut self, span: Span) {
match self {
Self::Visibility(v) => v.set_span(span),
Self::Mutability(m) => m.set_span(span),
Self::Virtual(v) => v.span = span,
Self::Override(o) => o.set_span(span),
Self::Immutable(i) => i.span = span,
Self::Modifier(m) => m.set_span(span),
}
}
}