1use anyhow::{Result, anyhow};
5use serde::Serialize;
6use serde_json::{Value, to_value};
7
8use crate::formats::base64::standard_base64_to_bytes;
9use crate::json;
10
11pub fn insert_key<T: Serialize>(input: T, key: &str, value: Value) -> Value {
15 let mut val = to_value(input).expect("Could not serialize input");
16 if let Value::Object(map) = &mut val {
17 map.insert(key.to_string(), value);
18 val
19 } else {
20 let mut map = serde_json::Map::new();
22 map.insert(key.to_string(), value);
23 map.insert("original".to_string(), val);
24 Value::Object(map)
25 }
26}
27
28pub fn get_bytes(val: &Value) -> Option<Vec<u8>> {
33 let value_bytes: Vec<u8> = match val {
34 Value::Array(arr) => arr
35 .iter()
36 .map(|v| {
37 u8::try_from(v.as_u64().expect("Invalid u64 value"))
38 .expect("Invalid u8 value")
39 })
40 .collect(),
41 Value::String(s) => {
42 standard_base64_to_bytes(s.to_string()).unwrap_or_default()
43 }
44 _ => return None,
45 };
46 Some(value_bytes)
47}
48
49pub fn get_key(val: &Value, key: &str) -> Option<Value> {
53 if let Value::Object(map) = val {
54 map.get(key).cloned()
55 } else {
56 None
57 }
58}
59
60pub fn get_string(val: &Value, key: &str) -> Option<String> {
63 let val = get_key(val, key)?;
64 val.as_str().map(std::string::ToString::to_string)
65}
66
67pub fn get_as_json_string(val: &Value, key: &str) -> Option<String> {
70 let val = get_key(val, key)?;
71 Some(json!(val))
72}
73
74pub fn to_plain_string(val: &Value) -> Result<String> {
79 match &val {
80 serde_json::Value::String(s) => Ok(s.clone()),
81 serde_json::Value::Number(n) => Ok(n.to_string()),
82 serde_json::Value::Bool(b) => Ok(b.to_string()),
83 serde_json::Value::Null => Ok(String::new()),
84 _ => Err(anyhow!("Unsupported value type for {val:?}")),
85 }
86}
87
88pub fn to_html_form_string(val: &Value) -> Result<Option<String>> {
93 match &val {
94 serde_json::Value::String(s) => Ok(Some(s.clone())),
95 serde_json::Value::Number(n) => Ok(Some(n.to_string())),
96 serde_json::Value::Bool(b) => {
97 if *b {
98 Ok(Some("on".to_string()))
99 } else {
100 Ok(None)
101 }
102 }
103 serde_json::Value::Null => Ok(Some(String::new())),
104 _ => Err(anyhow!("Unsupported value type for {val:?}")),
105 }
106}
107
108pub fn get_as_bytes(val: &Value, key: &str) -> Option<Vec<u8>> {
112 if let Value::Object(map) = val {
113 if let Some(v) = map.get(key) {
114 get_bytes(v)
115 } else {
116 None
117 }
118 } else {
119 None
120 }
121}
122
123pub fn get_as_u64(val: &Value, key: &str) -> Option<u64> {
127 if let Value::Object(map) = val {
128 map.get(key).and_then(serde_json::Value::as_u64)
129 } else {
130 None
131 }
132}
133
134pub fn from_json_string(s: &str) -> Result<Value> {
138 let v: Value = serde_json::from_str(s)?;
139 Ok(v)
140}
141
142pub fn get_key_from_json_string(s: &str, key: &str) -> Result<Option<Value>> {
146 let v: Value = from_json_string(s)?;
147 Ok(get_key(&v, key))
148}
149
150pub fn get_as_json_string_from_json_string(
154 s: &str,
155 key: &str,
156) -> Result<Option<String>> {
157 let v: Value = from_json_string(s)?;
158 if let Some(val) = get_as_json_string(&v, key) {
159 Ok(Some(val.to_string()))
160 } else {
161 Ok(None)
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use crate::formats::base64::bytes_to_standard_base64;
170 use crate::json_value;
171
172 use super::*;
173 use serde::{Deserialize, Serialize};
174
175 #[derive(Serialize, Deserialize, Debug, PartialEq)]
177 struct TestStruct {
178 id: u32,
179 name: String,
180 }
181
182 #[crate::ctb_test]
184 fn test_insert_key_primitive() {
185 let val = 42u64;
186 let v = json_value!(val);
187 let v2 = insert_key(v, "extra", Value::String("hello".to_string()));
188 assert!(get_key(&v2, "extra").is_some());
189 assert_eq!(get_as_u64(&v2, "val"), None); }
191
192 #[crate::ctb_test]
194 fn test_struct_value_and_getters() {
195 let s = TestStruct {
196 id: 7,
197 name: "abc".to_string(),
198 };
199 let v = json_value!(s);
200 assert_eq!(get_as_u64(&v, "id"), Some(7));
201 assert_eq!(get_string(&v, "name"), Some("abc".to_string()));
202 }
203
204 #[crate::ctb_test]
206 fn test_insert_key_struct() {
207 let s = TestStruct {
208 id: 1,
209 name: "xyz".to_string(),
210 };
211 let v = json_value!(s);
212 let v2 = insert_key(v, "extra", Value::Bool(true));
213 assert_eq!(get_key(&v2, "extra"), Some(Value::Bool(true)));
214 assert_eq!(get_string(&v2, "name"), Some("xyz".to_string()));
215 }
216
217 #[crate::ctb_test]
219 fn test_get_bytes_array_and_base64() {
220 let arr = vec![1u8, 2, 3, 4];
221 let v = json_value!(arr);
222 let bytes = get_bytes(&v).unwrap();
223 assert_eq!(bytes, vec![1, 2, 3, 4]);
224
225 let base64_str = bytes_to_standard_base64(&[5u8, 6, 7]);
226 let v2 = Value::String(base64_str.clone());
227 let bytes2 = get_bytes(&v2).unwrap();
228 assert_eq!(bytes2, vec![5, 6, 7]);
229 }
230
231 #[crate::ctb_test]
233 fn test_get_as_bytes_from_object() {
234 let mut obj = serde_json::Map::new();
235 obj.insert("data".to_string(), json_value!(vec![9u8, 8]));
236 let v = Value::Object(obj);
237 let bytes = get_as_bytes(&v, "data").unwrap();
238 assert_eq!(bytes, vec![9, 8]);
239 }
240
241 #[crate::ctb_test]
243 fn test_get_key() {
244 let mut obj = serde_json::Map::new();
245 obj.insert("key1".to_string(), Value::String("value".to_string()));
246 let v = Value::Object(obj);
247 assert_eq!(
248 get_key(&v, "key1"),
249 Some(Value::String("value".to_string()))
250 );
251 assert_eq!(get_key(&v, "missing"), None);
252 assert_eq!(get_key(&Value::Null, "key1"), None);
253 }
254
255 #[crate::ctb_test]
257 fn test_to_plain_string() {
258 assert_eq!(
259 to_plain_string(&Value::String("test".to_string())).unwrap(),
260 "test"
261 );
262 assert_eq!(to_plain_string(&Value::Number(42.into())).unwrap(), "42");
263 assert_eq!(to_plain_string(&Value::Bool(true)).unwrap(), "true");
264 assert_eq!(to_plain_string(&Value::Null).unwrap(), "");
265 assert!(to_plain_string(&Value::Array(vec![])).is_err());
266 }
267
268 #[crate::ctb_test]
270 fn test_to_html_form_string() {
271 assert_eq!(
272 to_html_form_string(&Value::String("test".to_string())).unwrap(),
273 Some("test".to_string())
274 );
275 assert_eq!(
276 to_html_form_string(&Value::Number(42.into())).unwrap(),
277 Some("42".to_string())
278 );
279 assert_eq!(
280 to_html_form_string(&Value::Bool(true)).unwrap(),
281 Some("on".to_string())
282 );
283 assert_eq!(to_html_form_string(&Value::Bool(false)).unwrap(), None);
284 assert_eq!(
285 to_html_form_string(&Value::Null).unwrap(),
286 Some("".to_string())
287 );
288 assert!(to_html_form_string(&Value::Array(vec![])).is_err());
289 }
290
291 #[crate::ctb_test]
293 fn test_get_as_u64() {
294 let mut obj = serde_json::Map::new();
295 obj.insert("num".to_string(), Value::Number(123.into()));
296 let v = Value::Object(obj);
297 assert_eq!(get_as_u64(&v, "num"), Some(123));
298 assert_eq!(get_as_u64(&v, "missing"), None);
299 assert_eq!(get_as_u64(&Value::Null, "num"), None);
300 }
301
302 #[crate::ctb_test]
303 fn test_from_json_string() {
304 let json = r#"{"num": 123}"#;
305 let v = from_json_string(json).unwrap();
306 assert_eq!(get_as_u64(&v, "num"), Some(123));
307 assert_eq!(get_as_u64(&v, "missing"), None);
308 assert_eq!(get_as_u64(&Value::Null, "num"), None);
309 }
310}