ya_client_model/market/
reason.rs1use derive_more::Display;
2use serde::de::DeserializeOwned;
3use serde::{Deserialize, Serialize};
4use std::fmt::Debug;
5
6#[derive(Clone, Display, Debug, PartialEq, Serialize, Deserialize)]
8#[display(fmt = "'{}'", message)]
9pub struct Reason {
10 pub message: String,
11 #[serde(flatten)]
12 pub extra: serde_json::Value,
13}
14
15impl Reason {
16 pub fn new(message: impl ToString) -> Reason {
18 Reason {
19 message: message.to_string(),
20 extra: serde_json::json!({}),
21 }
22 }
23}
24
25impl<T: Into<String>> From<T> for Reason {
26 fn from(m: T) -> Self {
27 Reason::new(m.into())
28 }
29}
30
31#[derive(thiserror::Error, Clone, Debug, PartialEq)]
32#[error("Error converting `{0}` to Reason: {1}")]
33pub struct ReasonConversionError(String, String);
34
35impl Reason {
36 pub fn from_value<T: Serialize + Debug>(value: &T) -> Result<Self, ReasonConversionError> {
37 serde_json::to_value(value)
38 .and_then(serde_json::from_value)
39 .map_err(|e| ReasonConversionError(format!("{:?}", value), e.to_string()))
40 }
41
42 pub fn to_value<T: DeserializeOwned>(&self) -> Result<T, ReasonConversionError> {
43 serde_json::to_value(self)
44 .and_then(serde_json::from_value)
45 .map_err(|e| ReasonConversionError(format!("{:?}", self), e.to_string()))
46 }
47}
48
49#[cfg(test)]
50mod test {
51 use super::*;
52
53 #[test]
54 fn test_try_convert_self() {
55 let reason = Reason::new("coś");
56 assert_eq!(reason, Reason::from_value(&reason).unwrap());
57 }
58
59 #[test]
60 fn test_try_convert_self_with_extra_message() {
62 let reason = Reason {
63 message: "coś".to_string(),
64 extra: serde_json::json!({"ala":"ma kota","message": "coś innego"}),
65 };
66 assert_eq!(
67 Reason {
68 message: "coś innego".to_string(),
69 extra: serde_json::json!({"ala":"ma kota"}),
70 },
71 Reason::from_value(&reason).unwrap()
72 );
73
74 assert_ne!(
75 reason,
76 Reason::from_value(&reason).unwrap().to_value().unwrap()
77 )
78 }
79
80 #[test]
81 fn test_try_convert_custom_reason_wo_message_field() {
82 #[derive(Serialize, Deserialize, Debug)]
83 struct CustomReason {}
84 let custom = CustomReason {};
85
86 assert_eq!(
87 "Error converting `CustomReason` to Reason: missing field `message`",
88 &Reason::from_value(&custom).unwrap_err().to_string()
89 )
90 }
91
92 #[test]
93 fn test_try_convert_custom_reason_with_message_field() {
94 #[derive(Serialize, Deserialize, Debug, PartialEq)]
95 struct CustomReason {
96 message: String,
97 other: bool,
98 }
99 let custom = CustomReason {
100 message: "coś".to_string(),
101 other: false,
102 };
103
104 assert_eq!(
105 Reason {
106 message: "coś".to_string(),
107 extra: serde_json::json!({ "other": false }),
108 },
109 Reason::from_value(&custom).unwrap()
110 );
111
112 assert_eq!(
113 custom,
114 Reason::from_value(&custom).unwrap().to_value().unwrap()
115 )
116 }
117
118 #[test]
119 fn test_try_convert_custom_reason_wrong_message_type() {
120 #[derive(Serialize, Deserialize, Debug)]
121 struct CustomReason {
122 message: u8,
123 }
124 let custom = CustomReason { message: 37 };
125
126 assert_eq!(
127 "Error converting `CustomReason { message: 37 }` to Reason: invalid \
128 type: integer `37`, expected a string",
129 &Reason::from_value(&custom).unwrap_err().to_string()
130 )
131 }
132
133 #[test]
134 fn test_try_convert_custom_reason_wrong_fancy_message_type() {
135 #[derive(Serialize, Deserialize, Debug)]
136 struct CustomReason {
137 i: u8,
138 b: bool,
139 s: String,
140 #[serde(flatten)]
141 extra: serde_json::Value,
142 }
143
144 let custom = CustomReason {
145 i: 0,
146 b: false,
147 s: "".to_string(),
148 extra: serde_json::json!({"message": true}),
149 };
150
151 assert_eq!(
152 format!(
153 "Error converting `{:?}` to Reason: invalid type: \
154 boolean `true`, expected a string",
155 custom
156 ),
157 Reason::from_value(&custom).unwrap_err().to_string()
158 )
159 }
160
161 #[test]
162 fn test_try_convert_custom_reason_with_fancy_message() {
163 #[derive(Serialize, Deserialize, Debug)]
164 struct CustomReason {
165 i: u8,
166 b: bool,
167 s: String,
168 #[serde(flatten)]
169 extra: serde_json::Value,
170 }
171
172 let custom = CustomReason {
173 i: 0,
174 b: false,
175 s: "".to_string(),
176 extra: serde_json::json!({"message": "coś"}),
177 };
178
179 assert_eq!(
180 Reason {
181 message: "coś".to_string(),
182 extra: serde_json::json!({ "i": 0, "b": false, "s": "" }),
183 },
184 Reason::from_value(&custom).unwrap()
185 )
186 }
187
188 #[test]
189 fn test_try_convert_json_reason_with_message() {
190 let json_reason = serde_json::json!({"message": "coś"});
191
192 assert_eq!(
193 Reason::new("coś"),
194 Reason::from_value(&json_reason).unwrap()
195 )
196 }
197}