#![allow(non_snake_case)]
use crate::{Adapter, DefaultModel, Model, NullAdapter, Result};
#[cfg(not(target_arch = "wasm32"))]
use crate::FileAdapter;
use async_trait::async_trait;
use rhai::{serde::to_dynamic, Dynamic};
use serde::Serialize;
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};
#[async_trait]
pub trait TryIntoModel: Send + Sync {
async fn try_into_model(self) -> Result<Box<dyn Model>>;
}
#[async_trait]
pub trait TryIntoAdapter: Send + Sync {
async fn try_into_adapter(self) -> Result<Box<dyn Adapter>>;
}
#[async_trait]
impl TryIntoModel for &'static str {
async fn try_into_model(self) -> Result<Box<dyn Model>> {
#[cfg(not(target_arch = "wasm32"))]
{
Ok(Box::new(DefaultModel::from_file(self).await?))
}
#[cfg(target_arch = "wasm32")]
{
Ok(Box::new(DefaultModel::from_str(self).await?))
}
}
}
#[async_trait]
impl<T> TryIntoModel for Option<T>
where
T: TryIntoModel,
{
#[allow(clippy::box_default)]
async fn try_into_model(self) -> Result<Box<dyn Model>> {
if let Some(m) = self {
m.try_into_model().await
} else {
Ok(Box::new(DefaultModel::default()))
}
}
}
#[async_trait]
impl TryIntoAdapter for &'static str {
async fn try_into_adapter(self) -> Result<Box<dyn Adapter>> {
#[cfg(not(target_arch = "wasm32"))]
{
Ok(Box::new(FileAdapter::new(self)))
}
#[cfg(target_arch = "wasm32")]
{
Ok(Box::new(NullAdapter))
}
}
}
#[async_trait]
impl<T> TryIntoAdapter for Option<T>
where
T: TryIntoAdapter,
{
async fn try_into_adapter(self) -> Result<Box<dyn Adapter>> {
if let Some(a) = self {
a.try_into_adapter().await
} else {
Ok(Box::new(NullAdapter))
}
}
}
#[allow(clippy::unit_arg)]
#[async_trait]
impl TryIntoAdapter for () {
async fn try_into_adapter(self) -> Result<Box<dyn Adapter>> {
Ok(Box::new(NullAdapter))
}
}
#[async_trait]
impl<T> TryIntoModel for T
where
T: Model + 'static,
{
async fn try_into_model(self) -> Result<Box<dyn Model>> {
Ok(Box::new(self))
}
}
#[async_trait]
impl<T> TryIntoAdapter for T
where
T: Adapter + 'static,
{
async fn try_into_adapter(self) -> Result<Box<dyn Adapter>> {
Ok(Box::new(self))
}
}
pub trait EnforceArgs {
fn try_into_vec(self) -> Result<Vec<Dynamic>>;
fn cache_key(&self) -> u64;
}
impl<T> EnforceArgs for Vec<T>
where
T: Into<Dynamic> + Hash + Clone,
{
fn try_into_vec(self) -> Result<Vec<Dynamic>> {
Ok(self.into_iter().map(|x| x.into()).collect())
}
fn cache_key(&self) -> u64 {
let mut hasher = DefaultHasher::new();
self.hash(&mut hasher);
hasher.finish()
}
}
macro_rules! impl_args {
($($p:ident),*) => {
impl<$($p: Serialize + Hash),*> EnforceArgs for ($($p,)*)
{
fn try_into_vec(self) -> Result<Vec<Dynamic>> {
let ($($p,)*) = self;
let _v = vec![$(to_dynamic($p)?,)*];
Ok(_v)
}
fn cache_key(&self) -> u64 {
let ($($p,)*) = self;
let mut _hasher = DefaultHasher::new();
$($p.hash(&mut _hasher);)*
_hasher.finish()
}
}
impl_args!(@pop $($p),*);
};
(@pop) => {
};
(@pop $head:ident) => {
impl_args!();
};
(@pop $head:ident $(, $tail:ident)+) => {
impl_args!($($tail),*);
};
}
impl_args!(A, B, C, D, E, F, G, H, J, K, L, M, N, P, Q, R, S, T, U, V);