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}