use std::fmt;
use std::pin::Pin;
use async_trait::async_trait;
use futures::Future;
use tc_error::*;
use tc_value::{Number, Value};
use tcgeneric::{Instance, Map, PathSegment, TCPath, ThreadSafe, Tuple};
use super::{RPCClient, Transaction};
pub mod generic;
pub mod helpers;
pub mod number;
pub mod string;
pub mod value;
pub type GetFuture<'a, State> = Pin<Box<dyn Future<Output = TCResult<State>> + Send + 'a>>;
pub type GetHandler<'a, 'b, Txn, State> =
Box<dyn FnOnce(&'b Txn, Value) -> GetFuture<'a, State> + Send + 'a>;
pub type PutFuture<'a> = Pin<Box<dyn Future<Output = TCResult<()>> + Send + 'a>>;
pub type PutHandler<'a, 'b, Txn, State> =
Box<dyn FnOnce(&'b Txn, Value, State) -> PutFuture<'a> + Send + 'a>;
pub type PostFuture<'a, State> = Pin<Box<dyn Future<Output = TCResult<State>> + Send + 'a>>;
pub type PostHandler<'a, 'b, Txn, State> =
Box<dyn FnOnce(&'b Txn, Map<State>) -> PostFuture<'a, State> + Send + 'a>;
pub type DeleteFuture<'a> = Pin<Box<dyn Future<Output = TCResult<()>> + Send + 'a>>;
pub type DeleteHandler<'a, 'b, Txn> =
Box<dyn FnOnce(&'b Txn, Value) -> DeleteFuture<'a> + Send + 'a>;
#[derive(Debug)]
pub enum HandlerType {
Get,
Put,
Post,
Delete,
}
#[async_trait]
pub trait ClosureInstance<State: StateInstance>: Send + Sync {
async fn call(self: Box<Self>, txn: State::Txn, args: State) -> TCResult<State>;
}
pub trait StateInstance:
Default
+ Instance
+ Route<Self>
+ ToState<Self>
+ From<bool>
+ From<Number>
+ From<Value>
+ From<Map<Self>>
+ From<Tuple<Self>>
+ From<Self::Class>
+ From<Self::Closure>
+ Clone
+ fmt::Debug
+ 'static
{
type FE: ThreadSafe + Clone;
type Txn: Transaction<Self::FE> + RPCClient<Self>;
type Closure: ClosureInstance<Self>;
fn is_map(&self) -> bool;
fn is_tuple(&self) -> bool;
}
pub trait ToState<State: StateInstance> {
fn to_state(&self) -> State;
}
impl<State: StateInstance, T: Clone + Into<State>> ToState<State> for T {
fn to_state(&self) -> State {
self.clone().into()
}
}
#[async_trait]
pub trait Handler<'a, State: StateInstance>: Send {
fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
where
'b: 'a,
{
None
}
fn put<'b>(self: Box<Self>) -> Option<PutHandler<'a, 'b, State::Txn, State>>
where
'b: 'a,
{
None
}
fn post<'b>(self: Box<Self>) -> Option<PostHandler<'a, 'b, State::Txn, State>>
where
'b: 'a,
{
None
}
fn delete<'b>(self: Box<Self>) -> Option<DeleteHandler<'a, 'b, State::Txn>>
where
'b: 'a,
{
None
}
}
pub trait Route<State>: Send + Sync {
fn route<'a>(&'a self, path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a, State> + 'a>>;
}
#[async_trait]
pub trait Public<State: StateInstance> {
async fn get(&self, txn: &State::Txn, path: &[PathSegment], key: Value) -> TCResult<State>;
async fn put(
&self,
txn: &State::Txn,
path: &[PathSegment],
key: Value,
value: State,
) -> TCResult<()>;
async fn post(
&self,
txn: &State::Txn,
path: &[PathSegment],
params: Map<State>,
) -> TCResult<State>;
async fn delete(&self, txn: &State::Txn, path: &[PathSegment], key: Value) -> TCResult<()>;
}
#[async_trait]
impl<State: StateInstance, T: Route<State> + fmt::Debug> Public<State> for T {
async fn get(&self, txn: &State::Txn, path: &[PathSegment], key: Value) -> TCResult<State> {
let handler = self
.route(path)
.ok_or_else(|| TCError::not_found(TCPath::from(path)))?;
if let Some(get_handler) = handler.get() {
get_handler(txn, key).await
} else {
Err(TCError::method_not_allowed(
HandlerType::Get,
self,
TCPath::from(path),
))
}
}
async fn put(
&self,
txn: &State::Txn,
path: &[PathSegment],
key: Value,
value: State,
) -> TCResult<()> {
let handler = self
.route(path)
.ok_or_else(|| TCError::not_found(TCPath::from(path)))?;
if let Some(put_handler) = handler.put() {
put_handler(txn, key, value).await
} else {
Err(TCError::method_not_allowed(
HandlerType::Put,
self,
TCPath::from(path),
))
}
}
async fn post(
&self,
txn: &State::Txn,
path: &[PathSegment],
params: Map<State>,
) -> TCResult<State> {
let handler = self
.route(path)
.ok_or_else(|| TCError::not_found(TCPath::from(path)))?;
if let Some(post_handler) = handler.post() {
post_handler(txn, params).await
} else {
Err(TCError::method_not_allowed(
HandlerType::Post,
self,
TCPath::from(path),
))
}
}
async fn delete(&self, txn: &State::Txn, path: &[PathSegment], key: Value) -> TCResult<()> {
let handler = self
.route(path)
.ok_or_else(|| TCError::not_found(TCPath::from(path)))?;
if let Some(delete_handler) = handler.delete() {
delete_handler(txn, key).await
} else {
Err(TCError::method_not_allowed(
HandlerType::Delete,
self,
TCPath::from(path),
))
}
}
}