use indexmap to preserve array order, implement serialize for Value

This commit is contained in:
Robin Appelman 2025-08-17 19:38:16 +02:00
commit 3bea91855b
5 changed files with 160 additions and 38 deletions

View file

@ -1,5 +1,6 @@
use indexmap::indexmap;
use miette::Report;
use php_literal_parser::from_str;
use php_literal_parser::{from_str, Key, Value};
use serde_derive::Deserialize;
#[test]
@ -92,3 +93,42 @@ pub struct Route {
name: String,
verb: String,
}
#[test]
fn test_value_serde_roundtrip() {
fn test_roundtrip(val: Value) {
let json = serde_json::to_string(&val).unwrap();
let parsed: Value = serde_json::from_str(&json).unwrap();
assert_eq!(val, parsed);
}
test_roundtrip(Value::Bool(false));
test_roundtrip(Value::Bool(true));
test_roundtrip(Value::Int(12));
test_roundtrip(Value::Float(12.12));
test_roundtrip(Value::String("foo".into()));
test_roundtrip(Value::Null);
test_roundtrip(Value::Array(indexmap! {
Key::Int(0) => Value::Bool(true),
Key::Int(1) => Value::Int(12),
Key::Int(2) => Value::Int(-12),
}));
test_roundtrip(Value::Array(indexmap! {
Key::Int(1) => Value::Bool(true),
Key::Int(2) => Value::Int(12),
Key::Int(5) => Value::Int(-12),
}));
test_roundtrip(Value::Array(indexmap! {
Key::String("foo".into()) => Value::Bool(true),
Key::String("var".into()) => Value::Array(indexmap! {
Key::String("bar".into()) => Value::Bool(true),
Key::String("asd".into()) => Value::Int(12),
Key::Int(2) => Value::Array(indexmap! {
Key::Int(0) => Value::Bool(true),
Key::Int(1) => Value::Int(12),
Key::Int(2) => Value::Int(-12),
}),
}),
}));
}

View file

@ -1,4 +1,4 @@
use maplit::hashmap;
use indexmap::indexmap;
use php_literal_parser::{from_str, Key, ParseError, Value};
fn parse(source: &str) -> Result<Value, ParseError> {
@ -22,9 +22,9 @@ fn test_parse_value() {
Value::String("test".to_string()),
parse(r#""test""#).unwrap()
);
assert_eq!(Value::Array(hashmap! {}), parse(r#"array()"#).unwrap());
assert_eq!(Value::Array(indexmap! {}), parse(r#"array()"#).unwrap());
assert_eq!(
Value::Array(hashmap! {
Value::Array(indexmap! {
Key::Int(0) => Value::Int(3),
Key::Int(1) => Value::Int(4),
Key::Int(2) => Value::Int(5),
@ -32,7 +32,7 @@ fn test_parse_value() {
parse(r#"array(3,4,5)"#).unwrap()
);
assert_eq!(
Value::Array(hashmap! {
Value::Array(indexmap! {
Key::Int(0) => Value::Int(3),
Key::Int(1) => Value::Int(4),
Key::Int(2) => Value::Int(5),
@ -40,7 +40,7 @@ fn test_parse_value() {
parse(r#"array(3,4,5,)"#).unwrap()
);
assert_eq!(
Value::Array(hashmap! {
Value::Array(indexmap! {
Key::Int(1) => Value::Int(3),
Key::Int(3) => Value::Int(4),
Key::Int(5) => Value::Int(5),
@ -48,7 +48,7 @@ fn test_parse_value() {
parse(r#"array(1=>3,3=>4,5=>5)"#).unwrap()
);
assert_eq!(
Value::Array(hashmap! {
Value::Array(indexmap! {
Key::Int(1) => Value::Int(3),
Key::Int(2) => Value::Int(4),
Key::Int(3) => Value::Int(5),
@ -56,7 +56,7 @@ fn test_parse_value() {
parse(r#"array(1=>3,4,5)"#).unwrap()
);
assert_eq!(
Value::Array(hashmap! {
Value::Array(indexmap! {
Key::Int(1) => Value::Int(3),
Key::Int(2) => Value::Int(4),
Key::Int(3) => Value::Int(5),
@ -64,7 +64,7 @@ fn test_parse_value() {
parse(r#"array("1"=>3,4,5)"#).unwrap()
);
assert_eq!(
Value::Array(hashmap! {
Value::Array(indexmap! {
Key::Int(1) => Value::Int(3),
Key::Int(2) => Value::Int(4),
Key::Int(3) => Value::Int(5),
@ -72,7 +72,7 @@ fn test_parse_value() {
parse(r#"array(1.5=>3,4,5)"#).unwrap()
);
assert_eq!(
Value::Array(hashmap! {
Value::Array(indexmap! {
Key::Int(1) => Value::Int(3),
Key::Int(2) => Value::Int(4),
Key::Int(3) => Value::Int(5),
@ -80,7 +80,7 @@ fn test_parse_value() {
parse(r#"array(true=>3,4,5)"#).unwrap()
);
assert_eq!(
Value::Array(hashmap! {
Value::Array(indexmap! {
Key::Int(1) => Value::Int(3),
Key::String("foo".into()) => Value::Int(4),
Key::Int(2) => Value::Int(5),
@ -88,18 +88,18 @@ fn test_parse_value() {
parse(r#"array(1=>3,"foo" => 4,5)"#).unwrap()
);
assert_eq!(
Value::Array(hashmap! {
Value::Array(indexmap! {
Key::String("foo".into()) => Value::Bool(true),
Key::String("nested".into()) => Value::Array(hashmap! {
Key::String("nested".into()) => Value::Array(indexmap! {
Key::String("foo".into()) => Value::Bool(false),
}),
}),
parse(r#"array("foo" => true, "nested" => array ('foo' => false))"#).unwrap()
);
assert_eq!(
Value::Array(hashmap! {
Value::Array(indexmap! {
Key::String("foo".into()) => Value::Bool(true),
Key::String("nested".into()) => Value::Array(hashmap! {
Key::String("nested".into()) => Value::Array(indexmap! {
Key::String("foo".into()) => Value::Null,
}),
}),
@ -120,7 +120,7 @@ fn test_parse_value() {
assert_eq!(Value::Float(1234.5), parse(r#"12_34.5"#).unwrap());
assert_eq!(
Value::Array(hashmap! {
Value::Array(indexmap! {
Key::Int(2) => Value::Int(3),
Key::String("foo".into()) => Value::Int(4),
Key::String("".into()) => Value::Int(5),
@ -131,11 +131,11 @@ fn test_parse_value() {
);
assert_eq!(
Value::Array(hashmap! {
Key::Int(0) => hashmap! {
Value::Array(indexmap! {
Key::Int(0) => indexmap! {
Key::String("a".into()) => Value::Int(2),
}.into(),
Key::Int(1) => hashmap! {
Key::Int(1) => indexmap! {
Key::String("b".into()) => Value::Int(3),
}.into()
}),
@ -143,11 +143,11 @@ fn test_parse_value() {
);
assert_eq!(
Value::Array(hashmap! {
Key::Int(0) => hashmap! {
Value::Array(indexmap! {
Key::Int(0) => indexmap! {
Key::String("a".into()) => Value::Int(2),
}.into(),
Key::Int(1) => hashmap! {
Key::Int(1) => indexmap! {
Key::String("b".into()) => Value::Int(3),
}.into()
}),