xml_rpc/xmlfmt/
value.rs

1use base64::{engine::general_purpose::STANDARD, Engine as _};
2use serde::de::Unexpected;
3use std;
4use std::collections::HashMap;
5use xml::escape::escape_str_pcdata;
6
7#[derive(Clone, Debug, PartialEq)]
8pub enum Value {
9    Int(i32),
10    Bool(bool),
11    String(String),
12    Double(f64),
13    DateTime(String),
14    Base64(Vec<u8>),
15    Array(Vec<Value>),
16    Struct(HashMap<String, Value>),
17}
18
19impl Value {
20    pub fn unexpected(&self) -> Unexpected {
21        match *self {
22            Value::Int(v) => Unexpected::Signed(i64::from(v)),
23            Value::Bool(v) => Unexpected::Bool(v),
24            Value::String(ref v) => Unexpected::Str(v),
25            Value::Double(v) => Unexpected::Float(v),
26            Value::DateTime(_) => Unexpected::Other("dateTime.iso8601"),
27            Value::Base64(ref v) => Unexpected::Bytes(v),
28            Value::Array(_) => Unexpected::Seq,
29            Value::Struct(_) => Unexpected::Map,
30        }
31    }
32}
33
34pub type Params = Vec<Value>;
35
36#[derive(Clone, Debug, PartialEq, Deserialize)]
37pub struct Fault {
38    #[serde(rename = "faultCode")]
39    pub code: i32,
40    #[serde(rename = "faultString")]
41    pub message: String,
42}
43
44impl Fault {
45    pub fn new<T>(code: i32, message: T) -> Fault
46    where
47        T: Into<String>,
48    {
49        Fault {
50            code,
51            message: message.into(),
52        }
53    }
54}
55
56pub type Response = std::result::Result<Params, Fault>;
57
58#[derive(Clone, Debug, PartialEq)]
59pub struct Call {
60    pub name: String,
61    pub params: Params,
62}
63
64pub trait ToXml {
65    fn to_xml(&self) -> String;
66}
67
68impl ToXml for Call {
69    fn to_xml(&self) -> String {
70        use std::fmt::Write;
71        format!(
72            include_str!("templates/call.xml"),
73            name = self.name,
74            params = self.params.iter().fold(String::new(), |mut output, param| {
75                let _ = write!(output, "<param>{}</param>", param.to_xml());
76                output
77            }),
78        )
79    }
80}
81
82impl ToXml for Response {
83    fn to_xml(&self) -> String {
84        use std::fmt::Write;
85        match *self {
86            Ok(ref params) => format!(
87                include_str!("templates/response_success.xml"),
88                params = params.iter().fold(String::new(), |mut output, param| {
89                    let _ = write!(output, "<param>{}</param>", param.to_xml());
90                    output
91                })
92            ),
93            Err(Fault { code, ref message }) => format!(
94                include_str!("templates/response_fault.xml"),
95                code = code,
96                message = message
97            ),
98        }
99    }
100}
101
102impl ToXml for Value {
103    fn to_xml(&self) -> String {
104        match *self {
105            Value::Int(v) => format!("<value><i4>{}</i4></value>", v),
106            Value::Bool(v) => format!(
107                "<value><boolean>{}</boolean></value>",
108                if v { 1 } else { 0 }
109            ),
110            Value::String(ref v) => {
111                format!("<value><string>{}</string></value>", escape_str_pcdata(v))
112            }
113            Value::Double(v) => format!("<value><double>{}</double></value>", v),
114            Value::DateTime(ref v) => {
115                format!("<value><dateTime.iso8601>{}</dateTime.iso8601></value>", v)
116            }
117            Value::Base64(ref v) => {
118                format!("<value><base64>{}</base64></value>", STANDARD.encode(v))
119            }
120            Value::Array(ref v) => format!(
121                "<value><array><data>{}</data></array></value>",
122                v.iter().map(Value::to_xml).collect::<String>()
123            ),
124            Value::Struct(ref v) => format!(
125                "<value><struct>{}</struct></value>",
126                v.iter().fold(String::new(), |mut output, (key, value)| {
127                    use std::fmt::Write;
128                    let _ = write!(
129                        output,
130                        "<member><name>{}</name>{}</member>",
131                        key,
132                        value.to_xml()
133                    );
134                    output
135                })
136            ),
137        }
138    }
139}