#![deny(missing_docs)]
const SERIALZATION_ERROR: i64 = -32000;
pub use easy_jsonrpc_proc_macro::rpc;
#[doc(hidden)]
pub use jsonrpc_core::types::{
    self, Error, ErrorCode, Failure, Id, MethodCall, Notification, Output, Success, Version,
};
#[doc(hidden)]
use serde::de::Deserialize;
#[doc(hidden)]
pub use serde_json::{self, Value};
use rand;
use serde::ser::Serialize;
use serde_json::json;
use std::{collections::BTreeMap, marker::PhantomData};
pub trait Handler {
    
    
    fn handle(&self, method: &str, params: Params) -> Result<Value, jsonrpc_core::Error>;
    
    fn handle_request(&self, raw_request: Value) -> MaybeReply {
        let request: jsonrpc_core::Request = match serde_json::from_value(raw_request) {
            Ok(request) => request,
            Err(_) => {
                return MaybeReply::Reply(serde_json::json!({
                    "jsonrpc": "2.0",
                    "error": {
                        "code": -32700,
                        "message": "Parse error"
                    },
                    "id": null
                }));
            }
        };
        let response = match handle_parsed_request(self, request) {
            Some(ret) => ret,
            None => return MaybeReply::DontReply,
        };
        MaybeReply::Reply(serde_json::to_value(response).unwrap_or_else(|e| {
            serde_json::json!({
                "jsonrpc": "2.0",
                "error": {
                    "code": SERIALZATION_ERROR,
                    "message": "Serialization error",
                    "data": format!("{}", e),
                },
                "id": null
            })
        }))
    }
}
#[derive(Clone, PartialEq, Debug)]
pub enum MaybeReply {
    
    Reply(Value),
    
    DontReply,
}
impl MaybeReply {
    
    pub fn as_option(self) -> Option<Value> {
        match self {
            MaybeReply::Reply(val) => Some(val),
            MaybeReply::DontReply => None,
        }
    }
}
fn handle_call<S: ?Sized + Handler>(slef: &S, call: jsonrpc_core::Call) -> Option<Output> {
    let (method, params, maybe_id, version): (
        String,
        jsonrpc_core::Params,
        Option<Id>,
        Option<Version>,
    ) = match call {
        jsonrpc_core::Call::Invalid { id } => {
            return Some(Output::invalid_request(id, None));
        }
        jsonrpc_core::Call::MethodCall(MethodCall {
            method,
            params,
            id,
            jsonrpc,
        }) => (method, params, Some(id), jsonrpc),
        jsonrpc_core::Call::Notification(Notification {
            method,
            params,
            jsonrpc,
        }) => (method, params, None, jsonrpc),
    };
    let args = Params::from_rc_params(params);
    let ret = slef.handle(&method, args);
    let id = maybe_id?;
    Some(match ret {
        Ok(ok) => Output::Success(Success {
            jsonrpc: version,
            result: ok,
            id,
        }),
        Err(err) => Output::Failure(Failure {
            jsonrpc: version,
            error: err,
            id,
        }),
    })
}
fn handle_parsed_request<S: ?Sized + Handler>(
    slef: &S,
    request: jsonrpc_core::Request,
) -> Option<jsonrpc_core::Response> {
    match request {
        jsonrpc_core::Request::Single(call) => {
            handle_call(slef, call).map(jsonrpc_core::Response::Single)
        }
        jsonrpc_core::Request::Batch(mut calls) => {
            let outputs = calls
                .drain(..)
                .filter_map(|call| handle_call(slef, call))
                .collect::<Vec<_>>();
            if outputs.is_empty() {
                None
            } else {
                Some(jsonrpc_core::Response::Batch(outputs))
            }
        }
    }
}
#[doc(hidden)]
pub enum InvalidArgs {
    WrongNumberOfArgs { expected: usize, actual: usize },
    ExtraNamedParameter { name: String },
    MissingNamedParameter { name: &'static str },
    InvalidArgStructure { name: &'static str, index: usize },
}
impl Into<Error> for InvalidArgs {
    fn into(self) -> Error {
        match self {
            InvalidArgs::WrongNumberOfArgs { expected, actual } => Error::invalid_params(format!(
                "WrongNumberOfArgs. Expected {}. Actual {}",
                expected, actual
            )),
            InvalidArgs::ExtraNamedParameter { name } => {
                Error::invalid_params(format!("ExtraNamedParameter {}", name))
            }
            InvalidArgs::MissingNamedParameter { name } => {
                Error::invalid_params(format!("MissingNamedParameter {}", name))
            }
            InvalidArgs::InvalidArgStructure { name, index } => Error::invalid_params(format!(
                "InvalidArgStructure {} at position {}.",
                name, index
            )),
        }
    }
}
#[derive(Debug)]
pub enum Params {
    
    
    Positional(Vec<Value>),
    
    Named(serde_json::Map<String, Value>),
}
impl Params {
    fn from_rc_params(params: jsonrpc_core::Params) -> Self {
        match params {
            jsonrpc_core::Params::Array(arr) => Params::Positional(arr),
            jsonrpc_core::Params::Map(map) => Params::Named(map),
            jsonrpc_core::Params::None => Params::Positional(vec![]),
        }
    }
    
    
    
    
    
    
    
    pub fn get_rpc_args(self, names: &[&'static str]) -> Result<Vec<Value>, InvalidArgs> {
        debug_assert!(
            {
                fn contains_duplicates(list: &[&str]) -> bool {
                    (1..list.len()).any(|i| list[i..].contains(&list[i - 1]))
                }
                !contains_duplicates(names)
            },
            "get_rpc_args recieved duplicate argument names"
        );
        let ar: Vec<Value> = match self {
            Params::Positional(ar) => ar,
            Params::Named(mut ma) => {
                let mut ar: Vec<Value> = Vec::with_capacity(names.len());
                for name in names.iter() {
                    ar.push(
                        ma.remove(*name)
                            .ok_or(InvalidArgs::MissingNamedParameter { name })?,
                    );
                }
                debug_assert_eq!(ar.len(), names.len());
                match ma.keys().next() {
                    Some(key) => {
                        return Err(InvalidArgs::ExtraNamedParameter { name: key.clone() })
                    }
                    None => ar,
                }
            }
        };
        if ar.len() != names.len() {
            Err(InvalidArgs::WrongNumberOfArgs {
                expected: ar.len(),
                actual: names.len(),
            })
        } else {
            Ok(ar)
        }
    }
}
#[derive(Debug)]
pub struct BoundMethod<'a, T>
where
    T: Deserialize<'static>,
{
    method: &'a str,
    args: Vec<Value>,
    _spook: PhantomData<*const T>,
}
impl<'a, T> BoundMethod<'a, T>
where
    T: Deserialize<'static>,
{
    
    
    
    pub fn new(method: &'a str, args: Vec<Value>) -> BoundMethod<T> {
        BoundMethod {
            method,
            args,
            _spook: PhantomData,
        }
    }
    
    pub fn call(&'a self) -> (Call<'a>, Tracker<T>)
    where
        T: Deserialize<'static>,
    {
        let Self { method, args, .. } = self;
        let id = rand::random::<u64>();
        (
            Call {
                method,
                args,
                id: Some(id),
            },
            Tracker {
                id,
                _spook: PhantomData,
            },
        )
    }
    
    
    pub fn notification(&'a self) -> Call<'a> {
        let Self { method, args, .. } = self;
        Call {
            method,
            args,
            id: None,
        }
    }
}
pub struct Call<'a> {
    method: &'a str,
    args: &'a [Value],
    id: Option<u64>,
}
impl<'a> Call<'a> {
    
    pub fn as_request(&self) -> Value {
        let Self { method, id, args } = self;
        match id {
            Some(id) => json!({
                "jsonrpc": "2.0",
                "method": method,
                "params": args,
                "id": id,
            }),
            None => json!({
                "jsonrpc": "2.0",
                "method": method,
                "params": args,
            }),
        }
    }
    
    pub fn batch_request(calls: &[Self]) -> Value {
        debug_assert!({
            fn contains_duplicates(list: &[u64]) -> bool {
                (1..list.len()).any(|i| list[i..].contains(&list[i - 1]))
            }
            let ids = calls.iter().filter_map(|call| call.id).collect::<Vec<_>>();
            !contains_duplicates(ids.as_slice())
        });
        Value::Array(calls.iter().map(Call::as_request).collect())
    }
}
#[doc(hidden)]
pub fn try_serialize<T: Serialize>(t: &T) -> Result<Value, Error> {
    
    
    
    serde_json::to_value(t).map_err(|e| Error {
        code: ErrorCode::ServerError(SERIALZATION_ERROR),
        message: "Serialization error".to_owned(),
        data: Some(Value::String(format!("{}", e))),
    })
}
#[derive(Clone, PartialEq, Debug)]
pub enum ResponseFail {
    
    ResultNotFound,
    
    InvalidResponse,
    
    RpcError(Error),
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct ArgSerializeError;
#[derive(Clone, PartialEq, Debug)]
pub enum InvalidResponse {
    
    DeserailizeFailure,
    
    
    ContainsNonNumericId,
}
pub struct Response {
    
    pub outputs: BTreeMap<u64, Result<Value, Error>>,
}
impl Response {
    
    pub fn from_json_response(raw_jsonrpc_response: Value) -> Result<Self, InvalidResponse> {
        let response: jsonrpc_core::Response = serde_json::from_value(raw_jsonrpc_response)
            .map_err(|_| InvalidResponse::DeserailizeFailure)?;
        let mut calls: Vec<Output> = match response {
            jsonrpc_core::Response::Single(out) => vec![out],
            jsonrpc_core::Response::Batch(outs) => outs,
        };
        debug_assert!({
            fn contains_duplicates(list: &[u64]) -> bool {
                (1..list.len()).any(|i| list[i..].contains(&list[i - 1]))
            }
            let ids = calls
                .iter()
                .filter_map(|out| match out {
                    Output::Success(Success {
                        id: Id::Num(id), ..
                    })
                    | Output::Failure(Failure {
                        id: Id::Num(id), ..
                    }) => Some(*id),
                    _ => None,
                })
                .collect::<Vec<_>>();
            !contains_duplicates(ids.as_slice())
        });
        let outputs = calls
            .drain(..)
            .map(
                |out| -> Result<(u64, Result<Value, Error>), InvalidResponse> {
                    match out {
                        Output::Success(Success {
                            result,
                            id: Id::Num(id),
                            ..
                        }) => Ok((id, Ok(result))),
                        Output::Failure(Failure {
                            error,
                            id: Id::Num(id),
                            ..
                        }) => Ok((id, Err(error))),
                        _ => Err(InvalidResponse::ContainsNonNumericId),
                    }
                },
            )
            .collect::<Result<BTreeMap<u64, Result<Value, Error>>, InvalidResponse>>()?;
        Ok(Self { outputs })
    }
    
    pub fn remove(&mut self, id: u64) -> Option<Result<Value, Error>> {
        self.outputs.remove(&id)
    }
}
pub struct Tracker<T>
where
    T: Deserialize<'static>,
{
    id: u64,
    _spook: PhantomData<*const T>,
}
impl<T> Tracker<T>
where
    T: Deserialize<'static>,
{
    
    
    
    pub fn get_return(&self, response: &mut Response) -> Result<T, ResponseFail> {
        let result = response
            .remove(self.id)
            .ok_or(ResponseFail::ResultNotFound)?;
        let raw_return = result.map_err(ResponseFail::RpcError)?;
        <T>::deserialize(raw_return).map_err(|_| ResponseFail::InvalidResponse)
    }
}
#[cfg(test)]
mod test {
    mod easy_jsonrpc {
        pub use crate::*;
    }
    use super::{Handler, MaybeReply};
    use jsonrpc_core;
    use serde_json::{json, Value};
    #[easy_jsonrpc::rpc]
    pub trait Adder {
        fn checked_add(&self, a: isize, b: isize) -> Option<isize>;
        fn wrapping_add(&self, a: isize, b: isize) -> isize;
        fn greet(&self) -> String;
        fn swallow(&self);
        fn repeat_list(&self, lst: Vec<usize>) -> Vec<usize>;
        fn fail(&self) -> Result<isize, String>;
        fn succeed(&self) -> Result<isize, String>;
        fn echo_ref(&self, a: &isize) -> isize;
    }
    struct AdderImpl;
    impl Adder for AdderImpl {
        fn checked_add(&self, a: isize, b: isize) -> Option<isize> {
            a.checked_add(b)
        }
        fn wrapping_add(&self, a: isize, b: isize) -> isize {
            a.wrapping_add(b)
        }
        fn greet(&self) -> String {
            "hello".into()
        }
        fn swallow(&self) {}
        fn repeat_list(&self, lst: Vec<usize>) -> Vec<usize> {
            let mut ret = lst.clone();
            ret.extend(lst);
            ret
        }
        fn fail(&self) -> Result<isize, String> {
            Err("tada!".into())
        }
        fn succeed(&self) -> Result<isize, String> {
            Ok(1)
        }
        fn echo_ref(&self, a: &isize) -> isize {
            *a
        }
    }
    fn assert_adder_response(request: Value, response: Value) {
        assert_eq!(
            (&AdderImpl {} as &dyn Adder)
                .handle_request(request)
                .as_option()
                .unwrap(),
            response
        );
    }
    fn error_code(request: Value) -> jsonrpc_core::ErrorCode {
        let raw_response = (&AdderImpl {} as &dyn Adder)
            .handle_request(request)
            .as_option()
            .unwrap();
        let response: jsonrpc_core::Response = serde_json::from_value(raw_response).unwrap();
        match response {
            jsonrpc_core::Response::Single(jsonrpc_core::Output::Failure(
                jsonrpc_core::Failure { error, .. },
            )) => error.code,
            _ => panic!(),
        }
    }
    #[test]
    fn batch() {
        assert_adder_response(
            json!([
                {
                    "jsonrpc": "2.0",
                    "method": "wrapping_add",
                    "params": [1, 1],
                    "id": 1
                },
                {
                    "jsonrpc": "2.0",
                    "method": "wrapping_add",
                    "params": [1, 2],
                    "id": 2
                },
                {
                    "jsonrpc": "2.0",
                    "method": "wrapping_add",
                    "params": [1, 3],
                    "id": null
                },
                {
                    "jsonrpc": "2.0",
                    "method": "wrapping_add",
                    "params": [1, 4],
                },
            ]),
            json!([
                {
                    "jsonrpc": "2.0",
                    "result": 2,
                    "id": 1
                },
                {
                    "jsonrpc": "2.0",
                    "result": 3,
                    "id": 2
                },
                {
                    "jsonrpc": "2.0",
                    "result": 4,
                    "id": null
                }
            ]),
        );
    }
    #[test]
    fn positional_args() {
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "wrapping_add",
                "params": [1, 1],
                "id": 1
            }),
            json!({
                "jsonrpc": "2.0",
                "result": 2,
                "id": 1
            }),
        );
    }
    #[test]
    fn string_id() {
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "wrapping_add",
                "params": [1, 1],
                "id": "jfjfks sasdfk"
            }),
            json!({
                "jsonrpc": "2.0",
                "result": 2,
                "id": "jfjfks sasdfk"
            }),
        );
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "wrapping_add",
                "params": [1, 1],
                "id": ""
            }),
            json!({
                "jsonrpc": "2.0",
                "result": 2,
                "id": ""
            }),
        );
    }
    #[test]
    fn named_args() {
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "wrapping_add",
                "params": {
                    "a": 1,
                    "b": 1
                },
                "id": 1
            }),
            json!({
                "jsonrpc": "2.0",
                "result": 2,
                "id": 1
            }),
        );
    }
    #[test]
    fn null_args() {
        let response = json!({
            "jsonrpc": "2.0",
            "result": "hello",
            "id": 1
        });
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "greet",
                "params": {},
                "id": 1
            }),
            response.clone(),
        );
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "greet",
                "params": [],
                "id": 1
            }),
            response.clone(),
        );
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "greet",
                "params": null,
                "id": 1
            }),
            response.clone(),
        );
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "greet",
                "id": 1
            }),
            response.clone(),
        );
    }
    #[test]
    fn null_return() {
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "swallow",
                "params": [],
                "id": 1
            }),
            json!({
                "jsonrpc": "2.0",
                "result": null,
                "id": 1
            }),
        );
    }
    #[test]
    fn incorrect_method_name() {
        assert_eq!(
            error_code(json!({
                "jsonrpc": "2.0",
                "method": "nonexist",
                "params": [],
                "id": 1
            })),
            jsonrpc_core::ErrorCode::MethodNotFound,
        );
    }
    #[test]
    fn incorrect_args() {
        assert_eq!(
            error_code(json!({
                "jsonrpc": "2.0",
                "method": "wrapping_add",
                "params": [],
                "id": 1
            })),
            jsonrpc_core::ErrorCode::InvalidParams,
        );
        assert_eq!(
            error_code(json!({
                "jsonrpc": "2.0",
                "method": "wrapping_add",
                "params": {
                    "notanarg": 1,
                    "notarg": 1
                },
                "id": 1
            })),
            jsonrpc_core::ErrorCode::InvalidParams,
        );
        assert_eq!(
            error_code(json!({
                "jsonrpc": "2.0",
                "method": "wrapping_add",
                "params": [[], []],
                "id": 1
            })),
            jsonrpc_core::ErrorCode::InvalidParams,
        );
    }
    #[test]
    fn complex_type() {
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "repeat_list",
                "params": [[1, 2, 3]],
                "id": 1
            }),
            json!({
                "jsonrpc": "2.0",
                "result": [1, 2, 3, 1, 2, 3],
                "id": 1
            }),
        );
        assert_eq!(
            error_code(json!({
                "jsonrpc": "2.0",
                "method": "repeat_list",
                "params": [[1], [12]],
                "id": 1
            }),),
            jsonrpc_core::ErrorCode::InvalidParams,
        );
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "fail",
                "params": [],
                "id": 1
            }),
            json!({
                "jsonrpc": "2.0",
                "result": {
                    "Err": "tada!"
                },
                "id": 1
            }),
        );
        assert_adder_response(
            json!({
                "jsonrpc": "2.0",
                "method": "succeed",
                "params": [],
                "id": 1
            }),
            json!({
                "jsonrpc": "2.0",
                "result": {
                    "Ok": 1
                },
                "id": 1
            }),
        );
    }
    #[test]
    fn notification() {
        let request = json!({
            "jsonrpc": "2.0",
            "method": "succeed",
            "params": []
        });
        assert_eq!(
            (&AdderImpl {} as &dyn Adder).handle_request(request),
            MaybeReply::DontReply
        );
    }
    #[test]
    fn adder_client_non_macro() {
        #[easy_jsonrpc::rpc]
        trait Adder {
            fn checked_add(&self, a: usize, b: usize) -> Option<usize> {
                a.checked_add(b)
            }
        }
        #[allow(non_camel_case_types)]
        pub enum adder_client {}
        impl adder_client {
            fn checked_add(
                arg0: usize,
                arg1: usize,
            ) -> Result<
                easy_jsonrpc::BoundMethod<'static, Option<usize>>,
                easy_jsonrpc::ArgSerializeError,
            > {
                Ok(easy_jsonrpc::BoundMethod::new(
                    "checked_add",
                    vec![
                        serde_json::to_value(arg0).map_err(|_| easy_jsonrpc::ArgSerializeError)?,
                        serde_json::to_value(arg1).map_err(|_| easy_jsonrpc::ArgSerializeError)?,
                    ],
                ))
            }
        }
        impl Adder for () {}
        let handler = &() as &dyn Adder;
        let bind = adder_client::checked_add(1, 2).unwrap();
        let (call, tracker) = bind.call();
        let raw_response = handler
            .handle_request(call.as_request())
            .as_option()
            .unwrap();
        let mut response = easy_jsonrpc::Response::from_json_response(raw_response).unwrap();
        let result: Option<usize> = tracker.get_return(&mut response).unwrap();
        assert_eq!(result, Some(3));
        assert_eq!(
            handler.handle_request(
                adder_client::checked_add(1, 2)
                    .unwrap()
                    .notification()
                    .as_request()
            ),
            MaybeReply::DontReply
        );
    }
    #[test]
    fn adder_client_with_macro() {
        #[easy_jsonrpc::rpc]
        trait Adder {
            fn checked_add(&self, a: usize, b: usize) -> Option<usize> {
                a.checked_add(b)
            }
        }
        impl Adder for () {}
        let handler = &() as &dyn Adder;
        let bind = adder::checked_add(1, 2).unwrap();
        let (call, tracker) = bind.call();
        let raw_response = handler
            .handle_request(call.as_request())
            .as_option()
            .unwrap();
        let mut response = easy_jsonrpc::Response::from_json_response(raw_response).unwrap();
        let result: Option<usize> = tracker.get_return(&mut response).unwrap();
        assert_eq!(result, Some(3));
        let call = adder::checked_add(1, 2).unwrap();
        assert_eq!(
            handler.handle_request(call.notification().as_request()),
            MaybeReply::DontReply
        );
    }
    #[test]
    fn client_with_reference_args() {
        let handler = &AdderImpl {} as &dyn Adder;
        let bind = adder::echo_ref(&2).unwrap();
        let (call, tracker) = bind.call();
        let raw_response = handler
            .handle_request(call.as_request())
            .as_option()
            .unwrap();
        let mut response = easy_jsonrpc::Response::from_json_response(raw_response).unwrap();
        assert_eq!(tracker.get_return(&mut response).unwrap(), 2);
        let call = adder::echo_ref(&2).unwrap();
        assert_eq!(
            handler.handle_request(call.notification().as_request()),
            MaybeReply::DontReply
        );
    }
    #[test]
    fn response_double_get() {
        let handler = &AdderImpl as &dyn Adder;
        use easy_jsonrpc::Call;
        let bind0 = adder::checked_add(0, 0).unwrap();
        let (call0, tracker0) = bind0.call();
        let bind1 = adder::checked_add(1, 0).unwrap();
        let (call1, tracker1) = bind1.call();
        let bind2 = adder::wrapping_add(1, 1).unwrap();
        let (call2, tracker2) = bind2.call();
        let json_request = Call::batch_request(&[call0, call1, call2]);
        let json_response = handler.handle_request(json_request).as_option().unwrap();
        let mut response = easy_jsonrpc::Response::from_json_response(json_response).unwrap();
        assert_eq!(tracker0.get_return(&mut response).unwrap(), Some(0));
        assert_eq!(tracker2.get_return(&mut response).unwrap(), 2);
        
        assert_eq!(tracker1.get_return(&mut response), Ok(Some(1)));
        assert_eq!(
            tracker1.get_return(&mut response),
            Err(easy_jsonrpc::ResponseFail::ResultNotFound)
        );
    }
    #[test]
    fn local_types() {
        #[derive(serde::Serialize, serde::Deserialize)]
        pub struct Foo;
        #[easy_jsonrpc::rpc]
        trait Bar {
            fn frob(&self) -> Foo;
            fn borf(&self, foo: Foo);
        }
    }
}