Switch to HashMap for the internal representation of object fields (#872)
* Resolves #818. Updates Object key_value_list to use HashMap<String, Value<S>>. Updates test cases. * Updates to use IndexMap. Reverts changes to test cases. Co-authored-by: Christian Legnitto <LegNeato@users.noreply.github.com>
This commit is contained in:
parent
f6523c9d29
commit
f5ce9f2d79
6 changed files with 28 additions and 112 deletions
|
@ -96,8 +96,7 @@ async fn async_simple() {
|
||||||
|
|
||||||
assert!(errs.is_empty());
|
assert!(errs.is_empty());
|
||||||
|
|
||||||
let mut obj = res.into_object().unwrap();
|
let obj = res.into_object().unwrap();
|
||||||
obj.sort_by_field();
|
|
||||||
let value = Value::Object(obj);
|
let value = Value::Object(obj);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -91,8 +91,7 @@ async fn async_simple() {
|
||||||
|
|
||||||
assert!(errs.is_empty());
|
assert!(errs.is_empty());
|
||||||
|
|
||||||
let mut obj = res.into_object().unwrap();
|
let obj = res.into_object().unwrap();
|
||||||
obj.sort_by_field();
|
|
||||||
let value = Value::Object(obj);
|
let value = Value::Object(obj);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -381,7 +381,7 @@ where
|
||||||
{
|
{
|
||||||
let mut map = serializer.serialize_map(Some(self.field_count()))?;
|
let mut map = serializer.serialize_map(Some(self.field_count()))?;
|
||||||
|
|
||||||
for &(ref f, ref v) in self.iter() {
|
for (ref f, ref v) in self.iter() {
|
||||||
map.serialize_key(f)?;
|
map.serialize_key(f)?;
|
||||||
map.serialize_value(v)?;
|
map.serialize_value(v)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -599,44 +599,5 @@ where
|
||||||
|
|
||||||
/// Merges `response_name`/`value` pair into `result`
|
/// Merges `response_name`/`value` pair into `result`
|
||||||
pub(crate) fn merge_key_into<S>(result: &mut Object<S>, response_name: &str, value: Value<S>) {
|
pub(crate) fn merge_key_into<S>(result: &mut Object<S>, response_name: &str, value: Value<S>) {
|
||||||
if let Some(&mut (_, ref mut e)) = result
|
|
||||||
.iter_mut()
|
|
||||||
.find(|&&mut (ref key, _)| key == response_name)
|
|
||||||
{
|
|
||||||
match *e {
|
|
||||||
Value::Object(ref mut dest_obj) => {
|
|
||||||
if let Value::Object(src_obj) = value {
|
|
||||||
merge_maps(dest_obj, src_obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Value::List(ref mut dest_list) => {
|
|
||||||
if let Value::List(src_list) = value {
|
|
||||||
dest_list
|
|
||||||
.iter_mut()
|
|
||||||
.zip(src_list.into_iter())
|
|
||||||
.for_each(|(d, s)| {
|
|
||||||
if let Value::Object(ref mut d_obj) = *d {
|
|
||||||
if let Value::Object(s_obj) = s {
|
|
||||||
merge_maps(d_obj, s_obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
result.add_field(response_name, value);
|
result.add_field(response_name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merges `src` object's fields into `dest`
|
|
||||||
fn merge_maps<S>(dest: &mut Object<S>, src: Object<S>) {
|
|
||||||
for (key, value) in src {
|
|
||||||
if dest.contains_field(&key) {
|
|
||||||
merge_key_into(dest, &key, value);
|
|
||||||
} else {
|
|
||||||
dest.add_field(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -195,7 +195,7 @@ impl<S: ScalarValue> ToInputValue<S> for Value<S> {
|
||||||
),
|
),
|
||||||
Value::Object(ref o) => InputValue::Object(
|
Value::Object(ref o) => InputValue::Object(
|
||||||
o.iter()
|
o.iter()
|
||||||
.map(|&(ref k, ref v)| {
|
.map(|(k, v)| {
|
||||||
(
|
(
|
||||||
Spanning::unlocated(k.clone()),
|
Spanning::unlocated(k.clone()),
|
||||||
Spanning::unlocated(v.to_input_value()),
|
Spanning::unlocated(v.to_input_value()),
|
||||||
|
|
|
@ -1,11 +1,20 @@
|
||||||
use std::{iter::FromIterator, vec::IntoIter};
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
|
use indexmap::map::{IndexMap, IntoIter};
|
||||||
|
|
||||||
/// A Object value
|
/// A Object value
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Object<S> {
|
pub struct Object<S> {
|
||||||
key_value_list: Vec<(String, Value<S>)>,
|
key_value_list: IndexMap<String, Value<S>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: PartialEq> PartialEq for Object<S> {
|
||||||
|
fn eq(&self, _: &Object<S>) -> bool {
|
||||||
|
match self {
|
||||||
|
Object { key_value_list } => self.key_value_list == *key_value_list,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Object<S> {
|
impl<S> Object<S> {
|
||||||
|
@ -13,7 +22,7 @@ impl<S> Object<S> {
|
||||||
/// preallocated slots for field-value pairs
|
/// preallocated slots for field-value pairs
|
||||||
pub fn with_capacity(size: usize) -> Self {
|
pub fn with_capacity(size: usize) -> Self {
|
||||||
Object {
|
Object {
|
||||||
key_value_list: Vec::with_capacity(size),
|
key_value_list: IndexMap::with_capacity(size),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,39 +35,26 @@ impl<S> Object<S> {
|
||||||
K: Into<String>,
|
K: Into<String>,
|
||||||
for<'a> &'a str: PartialEq<K>,
|
for<'a> &'a str: PartialEq<K>,
|
||||||
{
|
{
|
||||||
if let Some(item) = self
|
self.key_value_list.insert(k.into(), value)
|
||||||
.key_value_list
|
|
||||||
.iter_mut()
|
|
||||||
.find(|&&mut (ref key, _)| (key as &str) == k)
|
|
||||||
{
|
|
||||||
return Some(::std::mem::replace(&mut item.1, value));
|
|
||||||
}
|
|
||||||
self.key_value_list.push((k.into(), value));
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the object already contains a field with the given name
|
/// Check if the object already contains a field with the given name
|
||||||
pub fn contains_field<K>(&self, f: K) -> bool
|
pub fn contains_field<K>(&self, f: K) -> bool
|
||||||
where
|
where
|
||||||
|
K: Into<String>,
|
||||||
for<'a> &'a str: PartialEq<K>,
|
for<'a> &'a str: PartialEq<K>,
|
||||||
{
|
{
|
||||||
self.key_value_list
|
self.key_value_list.contains_key(&f.into())
|
||||||
.iter()
|
|
||||||
.any(|&(ref key, _)| (key as &str) == f)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a iterator over all field value pairs
|
/// Get a iterator over all field value pairs
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &(String, Value<S>)> {
|
pub fn iter(&self) -> impl Iterator<Item = (&String, &Value<S>)> {
|
||||||
FieldIter {
|
self.key_value_list.iter()
|
||||||
inner: self.key_value_list.iter(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a iterator over all mutable field value pairs
|
/// Get a iterator over all mutable field value pairs
|
||||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (String, Value<S>)> {
|
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&String, &mut Value<S>)> {
|
||||||
FieldIterMut {
|
self.key_value_list.iter_mut()
|
||||||
inner: self.key_value_list.iter_mut(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current number of fields
|
/// Get the current number of fields
|
||||||
|
@ -69,29 +65,16 @@ impl<S> Object<S> {
|
||||||
/// Get the value for a given field
|
/// Get the value for a given field
|
||||||
pub fn get_field_value<K>(&self, key: K) -> Option<&Value<S>>
|
pub fn get_field_value<K>(&self, key: K) -> Option<&Value<S>>
|
||||||
where
|
where
|
||||||
|
K: Into<String>,
|
||||||
for<'a> &'a str: PartialEq<K>,
|
for<'a> &'a str: PartialEq<K>,
|
||||||
{
|
{
|
||||||
self.key_value_list
|
self.key_value_list.get(&key.into())
|
||||||
.iter()
|
|
||||||
.find(|&&(ref k, _)| (k as &str) == key)
|
|
||||||
.map(|&(_, ref value)| value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Recursively sort all keys by field.
|
|
||||||
pub fn sort_by_field(&mut self) {
|
|
||||||
self.key_value_list
|
|
||||||
.sort_by(|(key1, _), (key2, _)| key1.cmp(key2));
|
|
||||||
for (_, ref mut value) in &mut self.key_value_list {
|
|
||||||
if let Value::Object(ref mut o) = value {
|
|
||||||
o.sort_by_field();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> IntoIterator for Object<S> {
|
impl<S> IntoIterator for Object<S> {
|
||||||
type Item = (String, Value<S>);
|
type Item = (String, Value<S>);
|
||||||
type IntoIter = IntoIter<Self::Item>;
|
type IntoIter = IntoIter<String, Value<S>>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.key_value_list.into_iter()
|
self.key_value_list.into_iter()
|
||||||
|
@ -115,7 +98,7 @@ where
|
||||||
{
|
{
|
||||||
let iter = iter.into_iter();
|
let iter = iter.into_iter();
|
||||||
let mut ret = Self {
|
let mut ret = Self {
|
||||||
key_value_list: Vec::with_capacity(iter.size_hint().0),
|
key_value_list: IndexMap::with_capacity(iter.size_hint().0),
|
||||||
};
|
};
|
||||||
for (k, v) in iter {
|
for (k, v) in iter {
|
||||||
ret.add_field(k, v);
|
ret.add_field(k, v);
|
||||||
|
@ -123,29 +106,3 @@ where
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct FieldIter<'a, S: 'a> {
|
|
||||||
inner: ::std::slice::Iter<'a, (String, Value<S>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, S> Iterator for FieldIter<'a, S> {
|
|
||||||
type Item = &'a (String, Value<S>);
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.inner.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct FieldIterMut<'a, S: 'a> {
|
|
||||||
inner: ::std::slice::IterMut<'a, (String, Value<S>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, S> Iterator for FieldIterMut<'a, S> {
|
|
||||||
type Item = &'a mut (String, Value<S>);
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.inner.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue