use parking_lot::RwLock;
use std::collections::HashMap;
use async::{AsyncResult, Ready};
use super::{Params, Value, Error, ErrorCode};
pub enum MethodResult {
Sync(Result<Value, Error>),
Async(AsyncResult),
}
pub trait SyncMethodCommand: Send + Sync {
fn execute(&self, params: Params) -> Result<Value, Error>;
}
impl<F> SyncMethodCommand for F where F: Fn(Params) -> Result<Value, Error>, F: Sync + Send {
fn execute(&self, params: Params) -> Result<Value, Error> {
self(params)
}
}
pub trait AsyncMethodCommand: Send + Sync {
fn execute(&self, params: Params, ready: Ready);
}
impl<F> AsyncMethodCommand for F where F: Fn(Params, Ready), F: Sync + Send {
fn execute(&self, params: Params, ready: Ready) {
self(params, ready)
}
}
pub struct AsyncMethod<F> where F: AsyncMethodCommand {
command: F,
}
impl<F> AsyncMethod<F> where F: AsyncMethodCommand {
pub fn new(command: F) -> Self {
AsyncMethod {
command: command,
}
}
}
pub trait MethodCommand: Send + Sync {
fn execute(&self, params: Params) -> MethodResult;
}
impl<F> MethodCommand for F where F: SyncMethodCommand {
fn execute(&self, params: Params) -> MethodResult {
MethodResult::Sync(self.execute(params))
}
}
impl<F> MethodCommand for AsyncMethod<F> where F: AsyncMethodCommand {
fn execute(&self, params: Params) -> MethodResult {
let (res, ready) = AsyncResult::new();
self.command.execute(params, ready);
res.into()
}
}
pub trait NotificationCommand: Send + Sync {
fn execute(&self, params: Params);
}
impl<F> NotificationCommand for F where F: Fn(Params), F: Sync + Send {
fn execute(&self, params: Params) {
self(params)
}
}
pub struct Commander {
methods: RwLock<HashMap<String, Box<MethodCommand>>>,
notifications: RwLock<HashMap<String, Box<NotificationCommand>>>
}
impl Commander {
pub fn new() -> Self {
Commander {
methods: RwLock::new(HashMap::new()),
notifications: RwLock::new(HashMap::new())
}
}
pub fn add_method<C>(&self, name: String, command: Box<C>) where C: MethodCommand + 'static {
self.methods.write().insert(name, command);
}
pub fn add_methods(&self, methods: HashMap<String, Box<MethodCommand>>) {
self.methods.write().extend(methods);
}
pub fn add_notification<C>(&self, name: String, command: Box<C>) where C: NotificationCommand + 'static {
self.notifications.write().insert(name, command);
}
pub fn add_notifications(&self, notifications: HashMap<String, Box<NotificationCommand>>) {
self.notifications.write().extend(notifications);
}
pub fn execute_method(&self, name: String, params: Params) -> MethodResult {
match self.methods.read().get(&name) {
Some(command) => command.execute(params),
None => MethodResult::Sync(Err(Error::new(ErrorCode::MethodNotFound)))
}
}
pub fn execute_notification(&self, name: String, params: Params) {
if let Some(command) = self.notifications.read().get(&name) {
command.execute(params)
}
}
}