Add your own json serializer

This commit is contained in:
Fabrice Reix 2020-11-05 20:25:47 +01:00
parent 92db6e505d
commit 6a16e68900

View File

@ -0,0 +1,134 @@
/*
* hurl (https://hurl.dev)
* Copyright (C) 2020 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/**
* Serde json son can not be easily used for serialization here because of the orphan rule.
* It seems easier just to reimplement it from scratch (around 50 lines of code)
*/
#[allow(dead_code)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum JValue {
Number(String),
String(String),
Boolean(bool),
List(Vec<JValue>),
Object(Vec<(String, JValue)>),
Null,
}
impl JValue {
pub fn format(self) -> String {
match self {
JValue::Null => "null".to_string(),
JValue::Number(n) => n,
JValue::String(s) => format!("\"{}\"", s.chars().map(format_char).collect::<String>()),
JValue::Boolean(b) => b.to_string(),
JValue::List(elem) => {
let s = elem
.iter()
.map(|e| e.clone().format())
.collect::<Vec<String>>()
.join(",");
format!("[{}]", s)
}
JValue::Object(key_values) => {
let s = key_values
.iter()
.map(|(k, v)| format!("\"{}\":{}", k, v.clone().format()))
.collect::<Vec<String>>()
.join(",");
format!("{{{}}}", s)
}
}
}
}
fn format_char(c: char) -> String {
if c == '"' {
"\\\"".to_string()
} else if c == '\\' {
"\\\\".to_string()
} else if c == '\x08' {
"\\b".to_string()
} else if c == '\x0c' {
"\\f".to_string()
} else if c == '\n' {
"\\n".to_string()
} else if c == '\r' {
"\\r".to_string()
} else if c == '\t' {
"\\t".to_string()
} else if c.is_control() {
format!("\\u{:04x}", c as u32)
} else {
c.to_string()
}
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
pub fn test_format_char() {
assert_eq!(format_char('a'), "a");
assert_eq!(format_char('"'), "\\\""); // \"
assert_eq!(format_char('\n'), "\\n");
assert_eq!(format_char('\x07'), "\\u0007")
}
#[test]
pub fn format_scalars() {
assert_eq!(JValue::Null {}.format(), "null");
assert_eq!(JValue::Number("1.0".to_string()).format(), "1.0");
assert_eq!(JValue::String("hello".to_string()).format(), "\"hello\"");
assert_eq!(JValue::Boolean(true).format(), "true");
}
#[test]
pub fn format_string() {
assert_eq!(JValue::String("hello".to_string()).format(), "\"hello\"");
assert_eq!(JValue::String("\"".to_string()).format(), r#""\"""#);
}
#[test]
pub fn format_list() {
assert_eq!(
JValue::List(vec![
JValue::Number("1".to_string()),
JValue::Number("2".to_string()),
JValue::Number("3".to_string())
])
.format(),
"[1,2,3]"
);
}
#[test]
pub fn format_object() {
assert_eq!(
JValue::Object(vec![
("name".to_string(), JValue::String("Bob".to_string())),
("age".to_string(), JValue::Number("20".to_string())),
])
.format(),
r#"{"name":"Bob","age":20}"#
);
}
}