mirror of
https://codeberg.org/icewind/php-literal-parser.git
synced 2026-06-03 18:44:07 +02:00
use indexmap to preserve array order, implement serialize for Value
This commit is contained in:
parent
5d9cf6de77
commit
3bea91855b
5 changed files with 160 additions and 38 deletions
80
src/lib.rs
80
src/lib.rs
|
|
@ -55,14 +55,16 @@ mod string;
|
|||
|
||||
use crate::string::is_array_key_numeric;
|
||||
pub use error::ParseError;
|
||||
use indexmap::IndexMap;
|
||||
use serde::de::{self, MapAccess, SeqAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use serde::ser::{SerializeMap, SerializeSeq};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
pub use serde_impl::from_str;
|
||||
use std::borrow::Borrow;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Index;
|
||||
|
||||
|
|
@ -78,11 +80,11 @@ use std::ops::Index;
|
|||
/// or the key is not found
|
||||
///
|
||||
/// ```rust
|
||||
/// # use maplit::hashmap;
|
||||
/// # use indexmap::indexmap;
|
||||
/// # use php_literal_parser::Value;
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// let value = Value::Array(hashmap!{
|
||||
/// let value = Value::Array(indexmap!{
|
||||
/// "key".into() => "value".into(),
|
||||
/// 10.into() => false.into()
|
||||
/// });
|
||||
|
|
@ -97,7 +99,7 @@ pub enum Value {
|
|||
Int(i64),
|
||||
Float(f64),
|
||||
String(String),
|
||||
Array(HashMap<Key, Value>),
|
||||
Array(IndexMap<Key, Value>),
|
||||
Null,
|
||||
}
|
||||
|
||||
|
|
@ -164,8 +166,8 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert the value into a hashmap if it is one
|
||||
pub fn into_hashmap(self) -> Option<HashMap<Key, Value>> {
|
||||
/// Convert the value into a map if it is one
|
||||
pub fn into_map(self) -> Option<IndexMap<Key, Value>> {
|
||||
match self {
|
||||
Value::Array(map) => Some(map),
|
||||
_ => None,
|
||||
|
|
@ -291,9 +293,15 @@ impl From<&str> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<IndexMap<Key, Value>> for Value {
|
||||
fn from(value: IndexMap<Key, Value>) -> Self {
|
||||
Value::Array(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HashMap<Key, Value>> for Value {
|
||||
fn from(value: HashMap<Key, Value>) -> Self {
|
||||
Value::Array(value)
|
||||
Value::Array(value.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -324,6 +332,8 @@ pub enum Key {
|
|||
}
|
||||
|
||||
impl Hash for Key {
|
||||
// a hash implementation which doesn't include the enum discriminant
|
||||
// that hash hash("foo") == hash(Key::String("foo"))
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
match self {
|
||||
Key::Int(int) => int.hash(state),
|
||||
|
|
@ -350,6 +360,18 @@ impl From<&str> for Key {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for Key {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
Key::Int(i) => serializer.serialize_i64(*i),
|
||||
Key::String(s) => serializer.serialize_str(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Key {
|
||||
/// Check if the key is an integer
|
||||
pub fn is_int(&self) -> bool {
|
||||
|
|
@ -487,8 +509,8 @@ impl Display for Key {
|
|||
|
||||
#[test]
|
||||
fn test_index() {
|
||||
use maplit::hashmap;
|
||||
let map = Value::Array(hashmap! {
|
||||
use indexmap::indexmap;
|
||||
let map = Value::Array(indexmap! {
|
||||
Key::String("key".to_string()) => Value::String("value".to_string()),
|
||||
Key::Int(1) => Value::Bool(true),
|
||||
});
|
||||
|
|
@ -624,7 +646,7 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
let mut result = HashMap::new();
|
||||
let mut result = IndexMap::new();
|
||||
let mut next_key = 0;
|
||||
while let Some(value) = seq.next_element::<Value>()? {
|
||||
let key = Key::Int(next_key);
|
||||
|
|
@ -638,7 +660,7 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||
where
|
||||
A: MapAccess<'de>,
|
||||
{
|
||||
let mut result = HashMap::new();
|
||||
let mut result = IndexMap::new();
|
||||
while let Some((key, value)) = map.next_entry()? {
|
||||
result.insert(key, value);
|
||||
}
|
||||
|
|
@ -655,6 +677,40 @@ impl<'de> Deserialize<'de> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for Value {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
Value::Bool(b) => serializer.serialize_bool(*b),
|
||||
Value::Int(i) => serializer.serialize_i64(*i),
|
||||
Value::Float(f) => serializer.serialize_f64(*f),
|
||||
Value::String(s) => serializer.serialize_str(s),
|
||||
Value::Array(a) => {
|
||||
if a.keys()
|
||||
.enumerate()
|
||||
.all(|(i, k)| k.as_int() == Some(i as i64))
|
||||
{
|
||||
let mut seq = serializer.serialize_seq(Some(a.len()))?;
|
||||
for value in a.values() {
|
||||
seq.serialize_element(value)?;
|
||||
}
|
||||
seq.end()
|
||||
} else {
|
||||
let mut map = serializer.serialize_map(Some(a.len()))?;
|
||||
for (key, value) in a {
|
||||
map.serialize_key(key)?;
|
||||
map.serialize_value(value)?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
Value::Null => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct KeyVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for KeyVisitor {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue