#![doc = include_str!("../README.md")]
#![no_std]
#[macro_export]
macro_rules! def_interface {
($(#[$attr:meta])* $vis:vis trait $name:ident {$(
$(#[$fn_attr:meta])*
fn $fn_name:ident($($arg_name:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;
)*}) => {
$(#[$attr])*
$vis trait $name {
#[doc(hidden)]
#[allow(non_upper_case_globals)]
const $name: $crate::r#priv::MustNotAnAlias = $crate::r#priv::MustNotAnAlias;
$($(#[$fn_attr])*
fn $fn_name($($arg_name: $arg_ty,)*) $(-> $ret_ty)?;)*
}
impl $name for $crate::r#priv::DefaultImpl {$(
$(#[$fn_attr])*
fn $fn_name($($arg_name: $arg_ty,)*) $(-> $ret_ty)? {
extern "Rust" {
#[link_name = concat!("__", stringify!($name), "__", stringify!($fn_name))]
fn $fn_name($($arg_name: $arg_ty,)*) $(-> $ret_ty)?;
}
unsafe { $fn_name($($arg_name,)*) }
}
)*}
};
}
#[macro_export]
macro_rules! impl_interface {
($(#[$attr:meta])* impl $interface:ident for $target:ident {$(
$(#[$fn_attr:meta])*
fn $fn_name:ident($($arg_name:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)? { $($body:tt)* }
)*}) => {
$(#[$attr])*
impl $interface for $target {
const $interface: $crate::r#priv::MustNotAnAlias = $crate::r#priv::MustNotAnAlias;
$($(#[$fn_attr])*
fn $fn_name($($arg_name: $arg_ty,)*) $(-> $ret_ty)? {
#[export_name = concat!("__", stringify!($interface), "__", stringify!($fn_name))]
extern "Rust" fn $fn_name($($arg_name: $arg_ty,)*) $(-> $ret_ty)? {
$($body)*
}
$fn_name($($arg_name,)*)
})*
}
};
}
#[macro_export]
macro_rules! call_interface {
($($path:ident)::+ $(, $args:expr)* $(,)?) => {
($crate::__interface_fn!([] $($path)::*))($($args,)*)
};
($($path:ident)::+ ($($args:tt)*) $(,)?) => {
($crate::__interface_fn!([] $($path)::*))($($args)*)
};
(::$($path:ident)::+ $(, $args:expr)* $(,)?) => {
($crate::__interface_fn!([::] $($path)::*))($($args,)*)
};
(::$($path:ident)::+ ($($args:tt)*) $(,)?) => {
($crate::__interface_fn!([::] $($path)::*))($($args)*)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __interface_fn {
([$($path:tt)*] $interface:ident::$fn_name:ident) => {
<$crate::r#priv::DefaultImpl as $($path)*$interface>::$fn_name
};
([$($path:tt)*] $head:ident::$($rest:tt)+) => {
$crate::__interface_fn!([$($path)* $head::] $($rest)*)
};
}
#[doc(hidden)]
pub mod r#priv {
pub struct DefaultImpl;
pub struct MustNotAnAlias;
}