use candid::CandidType;
use serde::{Deserialize, Serialize};
pub trait IcarusParam: CandidType + for<'de> Deserialize<'de> + Send + Sync + 'static {
fn validate() -> Result<(), String> {
Ok(())
}
}
pub trait IcarusReturn: CandidType + Serialize + Send + Sync + 'static {
fn validate() -> Result<(), String> {
Ok(())
}
}
pub trait IcarusTool {
type Input: IcarusParam;
type Output: IcarusReturn;
const IS_QUERY: bool;
const IS_ASYNC: bool;
fn validate_signature() -> Result<(), String> {
if Self::IS_QUERY && Self::IS_ASYNC {
return Err("Query functions cannot be async in ICP canisters".to_string());
}
Ok(())
}
}
impl IcarusParam for String {}
impl IcarusParam for bool {}
impl IcarusParam for i8 {}
impl IcarusParam for i16 {}
impl IcarusParam for i32 {}
impl IcarusParam for i64 {}
impl IcarusParam for i128 {}
impl IcarusParam for u8 {}
impl IcarusParam for u16 {}
impl IcarusParam for u32 {}
impl IcarusParam for u64 {}
impl IcarusParam for u128 {}
impl IcarusParam for f32 {}
impl IcarusParam for f64 {}
impl<T> IcarusParam for Option<T> where T: IcarusParam {}
impl<T> IcarusParam for Vec<T> where T: IcarusParam {}
impl IcarusParam for () {}
impl<T1: IcarusParam> IcarusParam for (T1,) {}
impl<T1: IcarusParam, T2: IcarusParam> IcarusParam for (T1, T2) {}
impl<T1: IcarusParam, T2: IcarusParam, T3: IcarusParam> IcarusParam for (T1, T2, T3) {}
impl<T1: IcarusParam, T2: IcarusParam, T3: IcarusParam, T4: IcarusParam> IcarusParam
for (T1, T2, T3, T4)
{
}
impl<T1: IcarusParam, T2: IcarusParam, T3: IcarusParam, T4: IcarusParam, T5: IcarusParam>
IcarusParam for (T1, T2, T3, T4, T5)
{
}
impl IcarusReturn for String {}
impl IcarusReturn for bool {}
impl IcarusReturn for i8 {}
impl IcarusReturn for i16 {}
impl IcarusReturn for i32 {}
impl IcarusReturn for i64 {}
impl IcarusReturn for i128 {}
impl IcarusReturn for u8 {}
impl IcarusReturn for u16 {}
impl IcarusReturn for u32 {}
impl IcarusReturn for u64 {}
impl IcarusReturn for u128 {}
impl IcarusReturn for f32 {}
impl IcarusReturn for f64 {}
impl IcarusReturn for () {}
impl<T> IcarusReturn for Option<T>
where
T: IcarusReturn,
{
fn validate() -> Result<(), String> {
T::validate()
}
}
impl<T> IcarusReturn for Vec<T>
where
T: CandidType + Serialize + Send + Sync + 'static,
{
fn validate() -> Result<(), String> {
Ok(())
}
}
impl<T, E> IcarusReturn for Result<T, E>
where
T: CandidType + Serialize + Send + Sync + 'static,
E: CandidType + Serialize + Send + Sync + 'static,
{
fn validate() -> Result<(), String> {
Ok(())
}
}
pub type ToolResult<T> = Result<T, String>;
pub const fn validate_tool_type<T>() -> bool {
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_types_implement_traits() {
assert!(<String as IcarusParam>::validate().is_ok());
assert!(<u64 as IcarusParam>::validate().is_ok());
assert!(<bool as IcarusParam>::validate().is_ok());
assert!(<Option<String> as IcarusParam>::validate().is_ok());
assert!(<Vec<u64> as IcarusParam>::validate().is_ok());
assert!(<String as IcarusReturn>::validate().is_ok());
assert!(<u64 as IcarusReturn>::validate().is_ok());
assert!(<bool as IcarusReturn>::validate().is_ok());
}
#[test]
fn test_result_implements_return() {
assert!(<Result<String, String> as IcarusReturn>::validate().is_ok());
assert!(<Result<Vec<u64>, String> as IcarusReturn>::validate().is_ok());
}
}