pub(crate) use prebindgen_registry::decl::{
declared_origin, local_path_prefix, ConvertSpec, LocalField, LocalVariant,
};
pub use prebindgen_registry::decl::{
ConvertDecl, ConvertSourceDecl, ExpandDecl, ExpandParamDecl, ExpandReturnDecl, FieldsDecl,
FunctionDecl,
};
use super::*;
#[macro_export]
macro_rules! ptr_class {
($t:ty) => {
$crate::PtrClassDecl::new(prebindgen_registry::__macro_support::parse_type(
stringify!($t),
))
};
}
#[macro_export]
macro_rules! enum_class {
($t:ty) => {
$crate::EnumClassDecl::new(prebindgen_registry::__macro_support::parse_type(
stringify!($t),
))
};
}
#[macro_export]
macro_rules! sealed_class {
($t:ty) => {
$crate::SealedClassDecl::new(prebindgen_registry::__macro_support::parse_type(
stringify!($t),
))
};
}
#[macro_export]
macro_rules! variant {
($name:ident) => {
$crate::VariantDecl::new(stringify!($name))
};
}
#[macro_export]
macro_rules! data_class {
($t:ty) => {
$crate::DataClassDecl::new(prebindgen_registry::__macro_support::parse_type(
stringify!($t),
))
};
}
#[macro_export]
macro_rules! constant {
($name:ident) => {
$crate::ConstDecl::new(prebindgen_registry::ident!($name))
};
}
#[macro_export]
macro_rules! package {
() => {
$crate::PackageDecl::new("")
};
($name:expr) => {
$crate::PackageDecl::new($name)
};
}
pub struct PtrClassDecl {
pub(crate) key: TypeKey,
pub(crate) rust_type: Origin<syn::Type>,
pub(crate) name_override: Option<String>,
pub(crate) members: Vec<(FunctionDecl, MemberKind)>,
pub(crate) iface: IfaceOpts,
pub(crate) gc_managed: bool,
}
#[derive(Clone, Default)]
pub(crate) struct IfaceOpts {
pub(crate) enabled: bool,
pub(crate) name_override: Option<String>,
pub(crate) implements: Vec<String>,
}
macro_rules! class_interface_methods {
($decl_macro:literal) => {
pub fn interface(mut self) -> Self {
self.iface.enabled = true;
self
}
pub fn interface_name(mut self, name: impl Into<String>) -> Self {
let name = name.into();
assert!(
!name.trim().is_empty(),
concat!($decl_macro, "!({}).interface_name(...): the name is empty"),
self.key.as_str()
);
self.iface.enabled = true;
self.iface.name_override = Some(name);
self
}
pub fn implements(mut self, iface: impl Into<String>) -> Self {
let iface = iface.into();
assert!(
!iface.trim().is_empty(),
concat!(
$decl_macro,
"!({}).implements(...): the interface name is empty"
),
self.key.as_str()
);
assert!(
!self.iface.implements.contains(&iface),
concat!(
$decl_macro,
"!({}).implements(\"{}\"): the interface is already declared"
),
self.key.as_str(),
iface
);
self.iface.implements.push(iface);
self
}
};
}
impl PtrClassDecl {
pub fn new(rust_type: syn::Type) -> Self {
Self {
key: TypeKey::from_type(&rust_type),
rust_type: declared_origin(rust_type),
name_override: None,
members: Vec::new(),
iface: IfaceOpts::default(),
gc_managed: false,
}
}
pub fn gc_managed(mut self) -> Self {
self.gc_managed = true;
self
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name_override = Some(name.into());
self
}
class_interface_methods!("ptr_class");
pub fn method(mut self, rust_fun: FunctionDecl) -> Self {
self.members.push((rust_fun, MemberKind::Method));
self
}
pub fn constructor(mut self, rust_fun: FunctionDecl) -> Self {
self.members.push((rust_fun, MemberKind::Constructor));
self
}
}
impl From<syn::Type> for PtrClassDecl {
fn from(rust_type: syn::Type) -> Self {
Self::new(rust_type)
}
}
pub struct EnumClassDecl {
pub(crate) key: TypeKey,
pub(crate) rust_type: Origin<syn::Type>,
pub(crate) name_override: Option<String>,
pub(crate) iface: IfaceOpts,
}
impl EnumClassDecl {
pub fn new(rust_type: syn::Type) -> Self {
Self {
key: TypeKey::from_type(&rust_type),
rust_type: declared_origin(rust_type),
name_override: None,
iface: IfaceOpts::default(),
}
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name_override = Some(name.into());
self
}
class_interface_methods!("enum_class");
}
impl From<syn::Type> for EnumClassDecl {
fn from(rust_type: syn::Type) -> Self {
Self::new(rust_type)
}
}
pub struct SealedClassDecl {
pub(crate) key: TypeKey,
pub(crate) rust_type: Origin<syn::Type>,
pub(crate) name_override: Option<String>,
pub(crate) variants: Vec<VariantDecl>,
pub(crate) iface: IfaceOpts,
}
impl SealedClassDecl {
pub fn new(rust_type: syn::Type) -> Self {
Self {
key: TypeKey::from_type(&rust_type),
rust_type: declared_origin(rust_type),
name_override: None,
variants: Vec::new(),
iface: IfaceOpts::default(),
}
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name_override = Some(name.into());
self
}
pub fn variant(mut self, decl: VariantDecl) -> Self {
self.variants.push(decl);
self
}
class_interface_methods!("sealed_class");
}
impl From<syn::Type> for SealedClassDecl {
fn from(rust_type: syn::Type) -> Self {
Self::new(rust_type)
}
}
pub struct VariantDecl {
pub(crate) rust_ident: String,
pub(crate) name_override: Option<String>,
}
impl VariantDecl {
pub fn new(rust_ident: impl Into<String>) -> Self {
Self {
rust_ident: rust_ident.into(),
name_override: None,
}
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name_override = Some(name.into());
self
}
}
pub struct DataClassDecl {
pub(crate) key: TypeKey,
pub(crate) rust_type: Origin<syn::Type>,
pub(crate) name_override: Option<String>,
pub(crate) jobject_input: bool,
pub(crate) iface: IfaceOpts,
pub(crate) members: Vec<(FunctionDecl, MemberKind)>,
}
impl DataClassDecl {
pub fn new(rust_type: syn::Type) -> Self {
Self {
key: TypeKey::from_type(&rust_type),
rust_type: declared_origin(rust_type),
name_override: None,
jobject_input: false,
iface: IfaceOpts::default(),
members: Vec::new(),
}
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name_override = Some(name.into());
self
}
pub fn jobject_input(mut self) -> Self {
self.jobject_input = true;
self
}
class_interface_methods!("data_class");
pub fn method(mut self, rust_fun: FunctionDecl) -> Self {
self.members.push((rust_fun, MemberKind::Method));
self
}
pub fn constructor(mut self, rust_fun: FunctionDecl) -> Self {
self.members.push((rust_fun, MemberKind::Constructor));
self
}
}
impl From<syn::Type> for DataClassDecl {
fn from(rust_type: syn::Type) -> Self {
Self::new(rust_type)
}
}
pub enum ClassDecl {
Ptr(PtrClassDecl),
Enum(EnumClassDecl),
Sealed(SealedClassDecl),
Data(DataClassDecl),
}
impl From<PtrClassDecl> for ClassDecl {
fn from(d: PtrClassDecl) -> Self {
Self::Ptr(d)
}
}
impl From<EnumClassDecl> for ClassDecl {
fn from(d: EnumClassDecl) -> Self {
Self::Enum(d)
}
}
impl From<SealedClassDecl> for ClassDecl {
fn from(d: SealedClassDecl) -> Self {
Self::Sealed(d)
}
}
impl From<DataClassDecl> for ClassDecl {
fn from(d: DataClassDecl) -> Self {
Self::Data(d)
}
}
#[allow(clippy::large_enum_variant)]
pub(crate) enum ConstSource {
Item,
Fun(syn::Ident),
Expr { ty: syn::Type, expr: syn::Expr },
}
pub struct ConstDecl {
pub(crate) rust_ident: syn::Ident,
pub(crate) kotlin_name_override: Option<String>,
pub(crate) source: ConstSource,
}
impl ConstDecl {
pub fn new(rust_ident: syn::Ident) -> Self {
Self {
rust_ident,
kotlin_name_override: None,
source: ConstSource::Item,
}
}
pub fn named(name: impl AsRef<str>) -> Self {
let name = name.as_ref();
let ident: syn::Ident = syn::parse_str(name)
.unwrap_or_else(|e| panic!("constant name `{name}` is not a valid identifier: {e}"));
Self::new(ident)
}
pub fn name(mut self, kotlin_name: impl Into<String>) -> Self {
self.kotlin_name_override = Some(kotlin_name.into());
self
}
pub(crate) fn val_name(&self) -> String {
self.kotlin_name_override
.clone()
.unwrap_or_else(|| self.rust_ident.to_string())
}
fn set_source(mut self, source: ConstSource) -> Self {
assert!(
matches!(self.source, ConstSource::Item),
"constant `{}`: value source already set — a constant has exactly one source \
(.fun / .with / .expr)",
self.rust_ident
);
self.source = source;
self
}
pub fn fun(self, decl: FunctionDecl) -> Self {
assert!(
decl.param_expands().is_empty() && decl.return_expand().is_none(),
"constant `{}`: expand overrides don't apply to a constant source fn `{}`",
self.rust_ident,
decl.rust_ident()
);
assert!(
decl.kotlin_name_override().is_none(),
"constant `{}`: the val name belongs on `constant!(…)` (or its `.name(…)`), \
not on the source fn `{}`",
self.rust_ident,
decl.rust_ident()
);
self.set_source(ConstSource::Fun(decl.rust_ident().clone()))
}
pub fn with(self, ty: syn::Type, path: syn::Path) -> Self {
let expr: syn::Expr = syn::parse_quote!(#path());
self.set_source(ConstSource::Expr { ty, expr })
}
pub fn expr(self, ty: syn::Type, expr: syn::Expr) -> Self {
self.set_source(ConstSource::Expr { ty, expr })
}
}
#[derive(Clone)]
pub(crate) struct ConstExprDecl {
pub(crate) kotlin_name: String,
pub(crate) ty: syn::Type,
pub(crate) expr: syn::Expr,
}
pub struct IgnoreDecl(pub(crate) IgnoreKind);
pub(crate) enum IgnoreKind {
Fun(syn::Ident),
Type(TypeKey),
Const(syn::Ident),
Matching(prebindgen_registry::NamePredicate),
}
impl From<FunctionDecl> for IgnoreDecl {
fn from(decl: FunctionDecl) -> Self {
assert!(
decl.kotlin_name_override().is_none()
&& decl.param_expands().is_empty()
&& decl.return_expand().is_none(),
"ignore(fun!({})): an ignored fn is never surfaced — \
.name()/expand overrides don't apply",
decl.rust_ident()
);
IgnoreDecl(IgnoreKind::Fun(decl.rust_ident().clone()))
}
}
impl From<syn::Type> for IgnoreDecl {
fn from(ty: syn::Type) -> Self {
IgnoreDecl(IgnoreKind::Type(TypeKey::from_type(&ty)))
}
}
impl From<ConstDecl> for IgnoreDecl {
fn from(decl: ConstDecl) -> Self {
assert!(
matches!(decl.source, ConstSource::Item) && decl.kotlin_name_override.is_none(),
"ignore(constant!({})): an ignore names a `#[prebindgen]` const — \
value sources/.name() don't apply",
decl.rust_ident
);
IgnoreDecl(IgnoreKind::Const(decl.rust_ident))
}
}
pub fn matching<F>(f: F) -> IgnoreDecl
where
F: Fn(&str) -> bool + Send + Sync + 'static,
{
IgnoreDecl(IgnoreKind::Matching(std::sync::Arc::new(f)))
}
pub struct PackageDecl {
pub(crate) name: String,
pub(crate) classes: Vec<ClassDecl>,
pub(crate) functions: Vec<FunctionDecl>,
pub(crate) constants: Vec<ConstDecl>,
}
impl PackageDecl {
pub fn new(name: impl Into<String>) -> Self {
let name = name.into();
let trimmed = name.trim_matches('.').trim_matches('/').to_string();
let name = crate::jni::mangle_kotlin_package(&trimmed);
if name != trimmed {
println!(
"cargo:warning=prebindgen: subpackage `{trimmed}` sanitized to `{name}` \
(invalid Kotlin package identifier)"
);
}
Self {
name,
classes: Vec::new(),
functions: Vec::new(),
constants: Vec::new(),
}
}
pub fn class(mut self, decl: impl Into<ClassDecl>) -> Self {
self.classes.push(decl.into());
self
}
pub fn fun(mut self, decl: FunctionDecl) -> Self {
self.functions.push(decl);
self
}
pub fn constant(mut self, decl: ConstDecl) -> Self {
self.constants.push(decl);
self
}
}