use prebindgen::SourceLocation;
use super::{origin::Origin, ty::TypeRef};
#[derive(Clone, Debug)]
pub enum Element {
Function(Function),
Type(Type),
Constant(Constant),
Guard(Guard),
Unsupported(Unsupported),
}
impl Element {
pub fn name(&self) -> Option<&syn::Ident> {
match self {
Element::Function(f) => Some(&f.name),
Element::Type(t) => Some(t.name()),
Element::Constant(c) => Some(&c.name),
Element::Guard(_) => None,
Element::Unsupported(u) => u.name.as_ref(),
}
}
pub fn location(&self) -> &SourceLocation {
match self {
Element::Function(f) => &f.origin.location,
Element::Type(t) => t.location(),
Element::Constant(c) => &c.origin.location,
Element::Guard(g) => &g.origin.location,
Element::Unsupported(u) => &u.origin.location,
}
}
pub(crate) fn as_syn(&self) -> syn::Item {
match self {
Element::Function(f) => syn::Item::Fn(f.origin.as_syn().clone()),
Element::Type(t) => t.as_syn(),
Element::Constant(c) => syn::Item::Const(c.origin.as_syn().clone()),
Element::Guard(g) => syn::Item::Const(g.origin.as_syn().clone()),
Element::Unsupported(u) => u.origin.as_syn().clone(),
}
}
}
#[derive(Clone, Debug)]
pub enum Type {
Struct(Struct),
Variant(Variant),
Enum(Enum),
Extern(Extern),
}
impl Type {
pub fn name(&self) -> &syn::Ident {
match self {
Type::Struct(s) => &s.name,
Type::Variant(v) => &v.name,
Type::Enum(e) => &e.name,
Type::Extern(e) => &e.name,
}
}
pub fn location(&self) -> &SourceLocation {
self.location_rc()
}
pub(super) fn location_rc(&self) -> &std::rc::Rc<SourceLocation> {
match self {
Type::Struct(s) => &s.origin.location,
Type::Variant(v) => &v.origin.location,
Type::Enum(e) => &e.origin.location,
Type::Extern(e) => &e.origin.location,
}
}
pub(crate) fn as_syn(&self) -> syn::Item {
match self {
Type::Struct(s) => syn::Item::Struct(s.origin.as_syn().clone()),
Type::Variant(v) => syn::Item::Enum(v.origin.as_syn().clone()),
Type::Enum(e) => syn::Item::Enum(e.origin.as_syn().clone()),
Type::Extern(e) => e.origin.as_syn().clone(),
}
}
}
#[derive(Clone, Debug)]
pub struct Extern {
pub name: syn::Ident,
pub target: Option<String>,
pub origin: Origin<syn::Item>,
}
#[derive(Clone, Debug)]
pub struct Function {
pub name: syn::Ident,
pub params: Vec<Param>,
pub ret: TypeRef,
pub origin: Origin<syn::ItemFn>,
}
impl Function {
pub fn synthetic_getter(ident: syn::Ident, ret: TypeRef) -> Self {
let ret_syntax = ret.spell();
let item: syn::ItemFn = syn::parse_quote! {
pub fn #ident() -> #ret_syntax {
unimplemented!()
}
};
Self {
name: ident,
params: Vec::new(),
origin: ret.origin_with(item),
ret,
}
}
}
#[derive(Clone, Debug)]
pub struct Param {
pub name: syn::Ident,
pub ty: TypeRef,
pub origin: Origin<syn::PatType>,
}
#[derive(Clone, Debug)]
pub struct Struct {
pub name: syn::Ident,
pub fields: Vec<Field>,
pub origin: Origin<syn::ItemStruct>,
pub(super) reading: TypeRef,
}
impl Struct {
pub fn type_ref(&self) -> &TypeRef {
&self.reading
}
}
#[derive(Clone, Debug)]
pub struct Variant {
pub name: syn::Ident,
pub alternatives: Vec<Alternative>,
pub origin: Origin<syn::ItemEnum>,
pub(super) reading: TypeRef,
}
impl Variant {
pub fn type_ref(&self) -> &TypeRef {
&self.reading
}
}
#[derive(Clone, Debug)]
pub struct Alternative {
pub name: syn::Ident,
pub index: usize,
pub fields: Vec<Field>,
pub origin: Origin<syn::Variant>,
}
impl Alternative {
pub fn is_empty(&self) -> bool {
self.fields.is_empty()
}
}
#[derive(Clone, Debug)]
pub struct Enum {
pub name: syn::Ident,
pub(super) reading: TypeRef,
pub values: Vec<EnumValue>,
pub origin: Origin<syn::ItemEnum>,
}
impl Enum {
pub fn discriminant_values(&self) -> Result<Vec<(&syn::Ident, i64)>, &syn::Ident> {
self.values
.iter()
.map(|v| match v.discriminant {
Some(n) => Ok((&v.name, n)),
None => Err(&v.name),
})
.collect()
}
}
impl Enum {
pub fn type_ref(&self) -> &TypeRef {
&self.reading
}
}
#[derive(Clone, Debug)]
pub struct EnumValue {
pub name: syn::Ident,
pub index: usize,
pub discriminant: Option<i64>,
pub origin: Origin<syn::Variant>,
}
#[derive(Clone, Debug)]
pub struct Field {
pub name: Option<syn::Ident>,
pub index: usize,
pub ty: TypeRef,
pub origin: Origin<syn::Field>,
}
#[derive(Clone, Debug)]
pub struct Constant {
pub name: syn::Ident,
pub ty: TypeRef,
pub origin: Origin<syn::ItemConst>,
}
#[derive(Clone, Debug)]
pub struct Guard {
pub origin: Origin<syn::ItemConst>,
}
#[derive(Clone, Debug)]
pub struct Unsupported {
pub name: Option<syn::Ident>,
pub error: Box<super::ItemError>,
pub origin: Origin<syn::Item>,
}
fn docs_from(attrs: &[syn::Attribute]) -> Option<String> {
let mut lines: Vec<String> = Vec::new();
for attr in attrs {
if !attr.path().is_ident("doc") {
continue;
}
let syn::Meta::NameValue(nv) = &attr.meta else {
continue;
};
let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(s),
..
}) = &nv.value
else {
continue;
};
let raw = s.value();
let line = raw.strip_prefix(' ').unwrap_or(&raw);
lines.push(line.replace("*/", "*\u{200B}/"));
}
(!lines.is_empty()).then(|| lines.join("\n"))
}
macro_rules! docs_accessor {
($($ty:ident),+ $(,)?) => {$(
impl $ty {
pub fn docs(&self) -> Option<String> {
docs_from(&self.origin.syntax.attrs)
}
}
)+};
}
docs_accessor!(
Function,
Struct,
Enum,
Variant,
Constant,
Field,
Alternative,
EnumValue
);