use crate::Error;
use crate::ffi::{
Macro as FfiMacro,
Expr as FfiExpr,
GlobalMacroExpander as FfiGlobalMacroExpander,
ReceiverMacroExpander as FfiReceiverMacroExpander,
};
mod expr;
mod factory;
mod expander;
pub use expr::*;
pub use factory::*;
pub use expander::*;
pub struct Macro(pub(crate) cxx::UniquePtr<FfiMacro>);
impl Macro {
pub fn new_global(
name: impl AsRef<str>,
argument_count: usize,
expander: impl GlobalMacroExpander + 'static,
) -> Result<Self, Error> {
let ffi_expander: cxx::UniquePtr<FfiGlobalMacroExpander> = FfiGlobalMacroExpander::new(
move |ffi_factory, ffi_expr| -> cxx::UniquePtr<FfiExpr> {
let factory = MacroExprFactory::new(ffi_factory);
let expr = ffi_expr.into_iter()
.map(|ffi_expr| Expr::from(&**ffi_expr))
.collect::<Vec<_>>();
if let Some(result) = expander(&factory, expr) {
result.into()
} else {
cxx::UniquePtr::null()
}
}
);
let ffi_macro = FfiMacro::new_global(name.as_ref().into(), argument_count, ffi_expander)?;
Ok(Macro(ffi_macro))
}
pub fn new_global_var_arg(
name: impl AsRef<str>,
expander: impl GlobalMacroExpander + 'static,
) -> Result<Self, Error> {
let ffi_expander: cxx::UniquePtr<FfiGlobalMacroExpander> = FfiGlobalMacroExpander::new(
move |ffi_factory, ffi_expr| -> cxx::UniquePtr<FfiExpr> {
let factory = MacroExprFactory::new(ffi_factory);
let expr = ffi_expr.into_iter()
.map(|ffi_expr| Expr::from(&**ffi_expr))
.collect::<Vec<_>>();
if let Some(result) = expander(&factory, expr) {
result.into()
} else {
cxx::UniquePtr::null()
}
}
);
let ffi_macro = FfiMacro::new_global_var_arg(name.as_ref().into(), ffi_expander)?;
Ok(Macro(ffi_macro))
}
pub fn new_receiver(
name: impl AsRef<str>,
argument_count: usize,
expander: impl ReceiverMacroExpander + 'static,
) -> Result<Self, Error> {
let ffi_expander: cxx::UniquePtr<FfiReceiverMacroExpander> = FfiReceiverMacroExpander::new(
move |ffi_factory, ffi_target, ffi_expr| -> cxx::UniquePtr<FfiExpr> {
let factory = MacroExprFactory::new(ffi_factory);
let target = Expr::from(&*ffi_target);
let expr = ffi_expr.into_iter()
.map(|ffi_expr| Expr::from(&**ffi_expr))
.collect::<Vec<_>>();
if let Some(result) = expander(&factory, target, expr) {
result.into()
} else {
cxx::UniquePtr::null()
}
}
);
let ffi_macro = FfiMacro::new_receiver(name.as_ref().into(), argument_count, ffi_expander)?;
Ok(Macro(ffi_macro))
}
pub fn new_receiver_var_arg(
name: impl AsRef<str>,
expander: impl ReceiverMacroExpander + 'static,
) -> Result<Self, Error> {
let ffi_expander: cxx::UniquePtr<FfiReceiverMacroExpander> = FfiReceiverMacroExpander::new(
move |ffi_factory, ffi_target, ffi_expr| -> cxx::UniquePtr<FfiExpr> {
let factory = MacroExprFactory::new(ffi_factory);
let target = Expr::from(&*ffi_target);
let expr = ffi_expr.into_iter()
.map(|ffi_expr| Expr::from(&**ffi_expr))
.collect::<Vec<_>>();
if let Some(result) = expander(&factory, target, expr) {
result.into()
} else {
cxx::UniquePtr::null()
}
}
);
let ffi_macro = FfiMacro::new_receiver_var_arg(name.as_ref().into(), ffi_expander)?;
Ok(Macro(ffi_macro))
}
pub fn name(&self) -> &[u8] {
self.0.function().as_bytes()
}
pub fn argument_count(&self) -> Option<usize> {
if self.0.is_variadic() {
None
} else {
Some(self.0.argument_count())
}
}
pub fn is_receiver_style(&self) -> bool {
self.0.is_receiver_style()
}
pub fn key(&self) -> &[u8] {
self.0.key().as_bytes()
}
}
impl From<Macro> for cxx::UniquePtr<crate::ffi::Macro> {
fn from(value: Macro) -> Self {
value.0
}
}
impl From<cxx::UniquePtr<crate::ffi::Macro>> for Macro {
fn from(value: cxx::UniquePtr<crate::ffi::Macro>) -> Self {
Macro(value)
}
}
impl std::fmt::Debug for Macro {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Macro({})", String::from_utf8_lossy(self.key()))
}
}
impl std::hash::Hash for Macro {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.key().hash(state);
}
}
impl std::cmp::PartialEq for Macro {
fn eq(&self, other: &Self) -> bool {
self.key() == other.key()
}
}
impl std::cmp::Eq for Macro {}