use serde::{Deserialize, Serialize};
use crate::traits::ICallRet;
pub type DataContentType = serde_json::Value;
const SUCCESS_CODE: &str = "0";
const FAIL_CODE: &str = "1";
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
pub struct CallReq<T>
where
T: Serialize,
{
method: String,
args: T,
}
impl<T> CallReq<T>
where
T: Serialize,
{
pub fn new(method: impl Into<String>, args: T) -> Self {
Self {
method: method.into(),
args,
}
}
pub fn method(&self) -> &str {
&self.method
}
pub fn args(&self) -> &T {
&self.args
}
pub fn into_args(self) -> T {
self.args
}
}
#[derive(Deserialize, Serialize, PartialEq, Eq, Debug)]
pub struct CallRet<T>
where
T: Serialize,
{
code: String,
msg: String,
data: T,
}
impl<T> CallRet<T>
where
T: Serialize,
{
pub fn new(code: impl Into<String>, msg: impl Into<String>, data: T) -> Self {
Self {
code: code.into(),
msg: msg.into(),
data,
}
}
pub fn suc(data: T) -> Self {
Self::new(SUCCESS_CODE, "", data)
}
pub fn suc_default() -> Self
where
T: Default,
{
Self::new(SUCCESS_CODE, "", T::default())
}
pub fn fail(msg: impl Into<String>, data: T) -> Self {
Self::new(FAIL_CODE, msg, data)
}
pub fn fail_default(msg: impl Into<String>) -> Self
where
T: Default,
{
Self::new(FAIL_CODE, msg, T::default())
}
pub fn code(&self) -> &str {
&self.code
}
pub fn msg(&self) -> &str {
&self.msg
}
pub fn data(&self) -> &T {
&self.data
}
pub fn ok_or_else<E, F>(self, err: F) -> std::result::Result<T, E>
where
F: FnOnce(String) -> E,
{
if self.code == SUCCESS_CODE {
Ok(self.data)
} else {
Err(err(self.msg))
}
}
}
impl<T> From<T> for CallRet<serde_json::Value>
where
T: ICallRet + Serialize,
{
fn from(value: T) -> Self {
let (code, msg, data) = value.split();
CallRet { code, msg, data }
}
}
impl<T, E> From<Result<T, E>> for CallRet<T>
where
T: Serialize + Default,
E: ToString,
E: std::fmt::Display,
{
fn from(value: Result<T, E>) -> Self {
match value {
Ok(data) => CallRet::suc(data),
Err(err) => CallRet::fail_default(format!("{:#}", err)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use anyhow::Error;
use serde_json;
use serde_json::json;
type CallReqAny = CallReq<serde_json::Value>;
type CallRetAny = CallRet<serde_json::Value>;
#[test]
fn test_callreq() {
{
let req = CallReq::new("test_method", 12);
assert_eq!(req.method(), "test_method");
assert_eq!(req.args(), &12);
let json_str = serde_json::to_string(&req).unwrap();
assert_eq!(json_str, r#"{"method":"test_method","args":12}"#);
let callreq_any: CallReqAny = serde_json::from_str(&json_str).unwrap();
assert_eq!(callreq_any.args().to_owned(), json!(12));
assert_eq!(callreq_any.into_args(), json!(12));
}
{
let req = CallReqAny::new("test_method", serde_json::Value::Null);
let json_str = serde_json::to_string(&req).unwrap();
assert_eq!(json_str, r#"{"method":"test_method","args":null}"#);
}
{
let req = CallReqAny::new("test_method", json!({}));
let json_str = serde_json::to_string(&req).unwrap();
assert_eq!(json_str, r#"{"method":"test_method","args":{}}"#);
}
}
#[test]
fn test_case_callret() {
assert_eq!(
serde_json::to_string(&CallRet::<()>::suc_default()).unwrap(),
r#"{"code":"0","msg":"","data":null}"#
);
assert_eq!(
serde_json::to_string(&CallRet::<()>::fail_default("unkown")).unwrap(),
r#"{"code":"1","msg":"unkown","data":null}"#
);
assert_eq!(
serde_json::to_string(&CallRet::<serde_json::Value>::suc(json!({}))).unwrap(),
r#"{"code":"0","msg":"","data":{}}"#
);
}
#[test]
fn test_callret_from_icallret() {
#[derive(Serialize)]
struct DummyRet {
code: String,
msg: String,
data: serde_json::Value,
}
impl ICallRet for DummyRet {
fn split(self) -> (String, String, serde_json::Value) {
(self.code, self.msg, self.data)
}
}
let dummy = DummyRet {
code: "0".to_string(),
msg: "ok".to_string(),
data: serde_json::json!({"foo": 42}),
};
let callret: CallRetAny = CallRet::from(dummy);
assert_eq!(callret.code(), "0");
assert_eq!(callret.msg(), "ok");
assert_eq!(callret.data().clone(), serde_json::json!({"foo": 42}));
}
#[test]
fn test_callret_deserialize() {
let json = r#"{
"code": "0",
"msg": "",
"data": "hello"
}"#;
let callret: CallRetAny = serde_json::from_str(json).unwrap();
assert_eq!(callret.code(), "0");
assert_eq!(callret.msg(), "");
assert_eq!(callret.data().clone(), serde_json::json!("hello"));
}
#[test]
fn test_callret_ok_or_else_anyhow() {
{
let ok_ret = CallRet::suc(json!(123));
let val: serde_json::Value = ok_ret.ok_or_else(Error::msg).unwrap();
assert_eq!(val, json!(123));
}
{
let fail_ret = CallRet::fail("fail reason", json!(null));
let err = fail_ret.ok_or_else(Error::msg).unwrap_err();
assert_eq!(err.to_string(), "fail reason");
}
}
#[test]
fn test_callret_from_result() {
let ok: Result<i32, &str> = Ok(42);
let ok_ret: CallRet<i32> = CallRet::from(ok);
assert_eq!(ok_ret.code(), "0");
assert_eq!(ok_ret.msg(), "");
assert_eq!(ok_ret.data(), &42);
let err: Result<i32, &str> = Err("bad request");
let err_ret: CallRet<i32> = CallRet::from(err);
assert_eq!(err_ret.code(), "1");
assert_eq!(err_ret.msg(), "bad request");
assert_eq!(err_ret.data(), &0);
}
#[test]
fn test_callret_from_anyhow_result() {
let ok: anyhow::Result<serde_json::Value> = Ok(json!({"n": 1}));
let ok_ret: CallRet<serde_json::Value> = CallRet::from(ok);
assert_eq!(ok_ret.code(), "0");
assert_eq!(ok_ret.msg(), "");
assert_eq!(ok_ret.data().clone(), json!({"n": 1}));
let err: anyhow::Result<serde_json::Value> = Err(Error::msg("boom"));
let err_ret: CallRet<serde_json::Value> = CallRet::from(err);
assert_eq!(err_ret.code(), "1");
assert_eq!(err_ret.msg(), "boom");
assert_eq!(err_ret.data().clone(), json!(null));
}
#[test]
fn test_partial_eq_for_callret_and_callreq() {
let req1 = CallReq::new("foo", json!(1));
let req2 = CallReq::new("foo", json!(1));
let req3 = CallReq::new("bar", json!(2));
assert_eq!(req1, req2);
assert_ne!(req1, req3);
let ret1 = CallRet::suc(json!({"a": 1}));
let ret2 = CallRet::suc(json!({"a": 1}));
let ret3 = CallRet::fail("fail", json!(null));
assert_eq!(ret1, ret2);
assert_ne!(ret1, ret3);
}
}