1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*!
# JSON Response for Rocket Framework

This is a crate which provides `JSONResponse` and `JSONResponseWithoutData` structs to response JSON format data with an additional **code** integer value.

Typically, the code **0** means **OK**. You can define other codes by yourself by implementing `JSONResponseCode` trait for your struct.

See `examples`.
*/

pub extern crate json_gettext;
#[macro_use]
extern crate debug_helper;
extern crate rocket;

mod json_response_code;
mod to_json;

use std::fmt::{self, Debug, Formatter};
use std::io::Cursor;
use std::marker::PhantomData;

pub use json_response_code::JSONResponseCode;
pub use to_json::ToJSON;

use json_gettext::JSONGetTextValue;

use rocket::request::Request;
use rocket::response::{self, Responder, Response};

/// To respond JSON data.
///
/// The format of JSON data looks like,
///
/// ```json
/// {
///    code: <integer>,
///    data: <json value>
/// }
/// ```
pub struct JSONResponse<'a, T: ToJSON = JSONGetTextValue<'a>> {
    code: Box<dyn JSONResponseCode>,
    data: T,
    phantom: PhantomData<&'a T>,
}

impl<'a, T: ToJSON> Debug for JSONResponse<'a, T> {
    #[inline]
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        impl_debug_for_struct!(JSONResponse, f, self, let .code = self.code.get_code(), let .data = self.data.to_json());
    }
}

impl<'a, T: ToJSON> JSONResponse<'a, T> {
    #[inline]
    pub fn ok(data: T) -> Self {
        JSONResponse {
            code: Box::new(0),
            data,
            phantom: PhantomData,
        }
    }

    #[inline]
    pub fn err<K: JSONResponseCode + 'static>(code: K, data: T) -> Self {
        JSONResponse {
            code: Box::new(code),
            data,
            phantom: PhantomData,
        }
    }
}

impl<'a, T: ToJSON> Responder<'a> for JSONResponse<'a, T> {
    fn respond_to(self, _: &Request) -> response::Result<'a> {
        let json =
            format!("{{\"code\":{},\"data\":{}}}", self.code.get_code(), self.data.to_json());

        let mut response = Response::build();

        response.raw_header("Content-Type", "application/json").sized_body(Cursor::new(json));

        response.ok()
    }
}

/// To respond JSON data.
///
/// The format of JSON data looks like,
///
/// ```json
/// {
///    code: <integer>
/// }
/// ```
pub struct JSONResponseWithoutData {
    code: Box<dyn JSONResponseCode>,
}

impl Debug for JSONResponseWithoutData {
    #[inline]
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        impl_debug_for_struct!(JSONResponseWithoutData, f, self, let .code = self.code.get_code());
    }
}

impl JSONResponseWithoutData {
    #[inline]
    pub fn ok() -> Self {
        JSONResponseWithoutData {
            code: Box::new(0),
        }
    }

    #[inline]
    pub fn err<K: JSONResponseCode + 'static>(code: K) -> Self {
        JSONResponseWithoutData {
            code: Box::new(code),
        }
    }
}

impl<'a> Responder<'a> for JSONResponseWithoutData {
    fn respond_to(self, _: &Request) -> response::Result<'a> {
        let json = format!("{{\"code\":{}}}", self.code.get_code());

        let mut response = Response::build();

        response.raw_header("Content-Type", "application/json").sized_body(Cursor::new(json));

        response.ok()
    }
}