use crate::api_def::Generic;
use crate::api_def::NamedType;
use crate::api_def::Type;
use crate::api_def::expression_def::Expression;
pub struct Function {
pub name: &'static str,
pub generics: &'static [Generic],
pub args: &'static [NamedType],
pub ret: Option<fn() -> Type>,
pub async_fn: bool,
pub expressions: &'static [Expression],
}
#[cfg(test)]
mod tests {
use crate::api_def::TypeDefinition;
#[test]
fn simple_function() {
#[derive(agdb::TypeDef)]
struct StructWithFunction;
#[agdb::impl_def()]
#[allow(dead_code)]
impl StructWithFunction {
fn example_function() {}
}
let functions = StructWithFunction::type_def().functions();
assert_eq!(functions.len(), 1);
assert_eq!(functions[0].name, "example_function");
assert!(functions[0].generics.is_empty());
assert!(functions[0].args.is_empty());
assert!(functions[0].ret.is_none());
assert!(functions[0].expressions.is_empty());
}
#[test]
fn function_with_args_and_return() {
#[derive(agdb::TypeDef)]
struct StructWithFunctionArgs;
#[agdb::impl_def()]
#[allow(dead_code)]
impl StructWithFunctionArgs {
fn add(a: i32, b: i32) -> i32 {
a + b
}
}
let functions = StructWithFunctionArgs::type_def().functions();
assert_eq!(functions.len(), 1);
let func = &functions[0];
assert_eq!(func.name, "add");
assert_eq!(func.args.len(), 2);
assert_eq!(func.args[0].name, "a");
assert_eq!((func.args[0].ty.unwrap())().name(), "i32");
assert_eq!(func.args[1].name, "b");
assert_eq!((func.args[1].ty.unwrap())().name(), "i32");
assert!(func.ret.is_some());
}
#[test]
fn function_with_generics() {
#[derive(agdb::TypeDef)]
struct StructWithGenericFunction;
#[agdb::impl_def()]
#[allow(dead_code)]
impl StructWithGenericFunction {
fn identity<T>(value: T) -> T {
value
}
}
let functions = StructWithGenericFunction::type_def().functions();
assert_eq!(functions.len(), 1);
let func = &functions[0];
assert_eq!(func.name, "identity");
assert_eq!(func.generics.len(), 1);
assert_eq!(func.generics[0].name, "T");
assert_eq!(func.args.len(), 1);
assert_eq!(func.args[0].name, "value");
assert_eq!((func.args[0].ty.unwrap())().name(), "T");
assert!(func.ret.is_some());
}
#[test]
fn impl_with_generics() {
#[derive(agdb::TypeDef)]
#[allow(dead_code)]
struct StructWithGenericImpl<T> {
value: T,
}
#[agdb::impl_def()]
#[allow(dead_code)]
impl<T> StructWithGenericImpl<T> {
fn generic_method(value: T) -> T {
value
}
}
let functions = StructWithGenericImpl::<i32>::type_def().functions();
assert_eq!(functions.len(), 1);
let func = &functions[0];
assert_eq!(func.name, "generic_method");
assert_eq!(func.generics.len(), 0);
assert_eq!(func.args.len(), 1);
assert_eq!(func.args[0].name, "value");
assert_eq!((func.args[0].ty.unwrap())().name(), "T");
assert!(func.ret.is_some());
}
#[test]
fn impl_with_generics_and_bounds() {
trait Debuggable {}
impl Debuggable for i32 {}
#[derive(agdb::TypeDef)]
#[allow(dead_code)]
struct StructWithBoundedGenericImpl<T: Debuggable> {
value: T,
}
#[agdb::impl_def()]
#[allow(dead_code)]
impl<T> StructWithBoundedGenericImpl<T>
where
T: Debuggable,
{
fn debug_value(value: T) -> T {
value
}
}
let functions = StructWithBoundedGenericImpl::<i32>::type_def().functions();
assert_eq!(functions.len(), 1);
let func = &functions[0];
assert_eq!(func.name, "debug_value");
assert_eq!(func.generics.len(), 0);
assert_eq!(func.args.len(), 1);
assert_eq!(func.args[0].name, "value");
assert_eq!((func.args[0].ty.unwrap())().name(), "T");
assert!(func.ret.is_some());
}
#[test]
fn async_function() {
#[derive(agdb::TypeDef)]
struct StructWithAsync;
#[agdb::impl_def()]
#[allow(dead_code)]
impl StructWithAsync {
async fn async_function() {}
}
let functions = StructWithAsync::type_def().functions();
assert_eq!(functions.len(), 1);
assert_eq!(functions[0].name, "async_function");
assert!(functions[0].generics.is_empty());
assert!(functions[0].args.is_empty());
assert!(functions[0].ret.is_none());
assert!(functions[0].async_fn);
assert!(functions[0].expressions.is_empty());
}
}