use super::*;
use std::collections::HashMap;
#[derive(Debug, Default)]
pub struct FunctionRegistry<'f> {
entries: HashMap<String, FunctionOverloads<FunctionDeclOrImpl<'f>>>,
}
impl<'f> FunctionRegistry<'f> {
pub fn new() -> Self {
Self {
entries: HashMap::new(),
}
}
}
impl<'f> FunctionRegistry<'f> {
pub fn register<F, Fm, Args>(
&mut self,
name: impl Into<String>,
member: bool,
f: F,
) -> Result<&mut Self, Error>
where
F: IntoFunction<'f, Fm, Args>,
Fm: FnMarker,
Args: Arguments,
{
let name = name.into();
let entry = self
.entries
.entry(name)
.or_insert_with(FunctionOverloads::new);
entry.add_impl(member, f.into_function())?;
Ok(self)
}
pub fn register_member<F, Fm, Args>(
&mut self,
name: impl Into<String>,
f: F,
) -> Result<&mut Self, Error>
where
F: IntoFunction<'f, Fm, Args>,
Fm: FnMarker,
Args: Arguments + NonEmptyArguments,
{
self.register(name, true, f)
}
pub fn register_global<F, Fm, Args>(
&mut self,
name: impl Into<String>,
f: F,
) -> Result<&mut Self, Error>
where
F: IntoFunction<'f, Fm, Args>,
Fm: FnMarker,
Args: Arguments,
{
self.register(name, false, f)
}
pub fn declare<D>(&mut self, name: impl Into<String>, member: bool) -> Result<&mut Self, Error>
where
D: FunctionDecl,
{
let name = name.into();
if member && D::ARGUMENTS_LEN == 0 {
return Err(Error::invalid_argument("Member functions cannot have zero arguments"));
}
let entry = self
.entries
.entry(name)
.or_insert_with(FunctionOverloads::new);
entry.add_decl(member, D::function_type())?;
Ok(self)
}
pub fn declare_member<D>(&mut self, name: impl Into<String>) -> Result<&mut Self, Error>
where
D: FunctionDecl + FunctionDeclWithNonEmptyArguments,
{
self.declare::<D>(name, true)
}
pub fn declare_global<D>(&mut self, name: impl Into<String>) -> Result<&mut Self, Error>
where
D: FunctionDecl,
{
self.declare::<D>(name, false)
}
pub fn find(&self, name: &str) -> Option<&FunctionOverloads<FunctionDeclOrImpl<'f>>> {
self.entries.get(name)
}
pub fn find_mut(
&mut self,
name: &str,
) -> Option<&mut FunctionOverloads<FunctionDeclOrImpl<'f>>> {
self.entries.get_mut(name)
}
pub fn entries(
&self,
) -> impl Iterator<Item = (&str, &FunctionOverloads<FunctionDeclOrImpl<'f>>)> {
self.entries.iter().map(|(k, v)| (k.as_str(), v))
}
pub fn entries_mut(
&mut self,
) -> impl Iterator<Item = (&str, &mut FunctionOverloads<FunctionDeclOrImpl<'f>>)> {
self.entries.iter_mut().map(|(k, v)| (k.as_str(), v))
}
pub fn remove(&mut self, name: &str) -> Result<(), Error> {
self.entries
.remove(name)
.ok_or_else(|| Error::not_found(format!("Function '{name}' not found")))?;
Ok(())
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
#[allow(dead_code)]
#[allow(unused_variables)]
#[allow(unused_imports)]
#[cfg(test)]
mod test {
use crate::{
types::{OpaqueType, ValueType},
values::OpaqueValue,
values::Optional,
values::{TypedOpaque, Value},
Error, Opaque,
};
use std::{
collections::{BTreeMap, HashMap},
sync::Arc,
};
use super::*;
fn f1(v: i64) -> Result<i64, Error> {
Ok(5)
}
fn f11(a1: i64, a2: i64) -> Result<i64, Error> {
Ok(5)
}
fn f2(a1: HashMap<i64, i64>) -> Result<i64, Error> {
Ok(5)
}
fn f3(a1: String) -> Result<i64, Error> {
Ok(5)
}
fn f4(a1: String, a2: String) -> Result<i64, Error> {
Ok(5)
}
fn f5(a1: String, a2: String, a3: HashMap<u64, Vec<Vec<i64>>>) -> Result<i64, Error> {
Ok(5)
}
#[cfg(feature = "derive")]
#[derive(Opaque, Debug, Clone, PartialEq)]
#[cel_cxx(type = "MyOpaque", crate = crate)]
#[cel_cxx(display)]
struct MyOpaque(pub i64);
#[cfg(feature = "derive")]
fn f6(a1: String, a2: MyOpaque, a3: HashMap<u64, Vec<Vec<i64>>>) -> Result<i64, Error> {
Ok(5)
}
fn f7(a1: &str) -> Result<(), Error> {
Ok(())
}
#[cfg(feature = "derive")]
fn f8(a1: &MyOpaque) -> &MyOpaque {
a1
}
#[cfg(feature = "derive")]
fn f9(a1: Optional<&MyOpaque>) -> Result<Option<&MyOpaque>, Error> {
Ok(a1.into_option())
}
async fn async_f1(a1: String, a2: i64, a3: Option<String>) -> Result<i64, Error> {
Ok(5)
}
fn f_map1(a1: HashMap<String, Vec<u8>>) -> Result<(), Error> {
Ok(())
}
fn f_map2(a1: HashMap<&str, &[u8]>) -> Result<(), Error> {
Ok(())
}
fn f_map3<'a>(a1: HashMap<&'a str, &'a str>) -> Result<BTreeMap<&'a str, &'a str>, Error> {
Ok(BTreeMap::from_iter(a1))
}
#[test]
fn test_register() -> Result<(), Error> {
let n = 100;
let lifetime_closure = |a: i64, b: i64| Ok::<_, Error>(a + b + n);
let mut registry = FunctionRegistry::new();
registry
.register_member("f1", f1)?
.register_member("f11", f11)?
.register_member("f2", f2)?
.register_member("f3", f3)?
.register_member("f4", f4)?
.register_member("f5", f5)?
.register_global("lifetime_closure", lifetime_closure)?
.register_global("f7", f7)?
.register_global("f_map1", f_map1)?
.register_global("f_map2", f_map2)?
.register_global("f_map3", f_map3)?;
#[cfg(feature = "derive")]
registry
.register_global("f6", f6)?
.register_global("f8", f8)?
.register_global("f9", f9)?;
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
let registry = registry.register_global("async_f1", async_f1)?;
#[cfg(feature = "derive")]
{
let x = MyOpaque(1);
let y: Box<dyn Opaque> = Box::new(x);
let value: OpaqueValue = Box::new(MyOpaque(1));
assert!(value.is::<MyOpaque>());
assert!(value.downcast_ref::<MyOpaque>().is_some());
let value2 = value.clone().downcast::<MyOpaque>();
assert!(value2.is_ok());
let value3 = value.clone();
assert!(value3.is::<MyOpaque>());
let value4: OpaqueValue = Box::new(MyOpaque(1));
assert!(value4.is::<MyOpaque>());
assert!(value4.clone().downcast::<MyOpaque>().is_ok());
let value5 = value4.downcast::<MyOpaque>();
assert!(value5.is_ok());
}
Ok(())
}
}