Skip to content

Commit 0519b48

Browse files
authored
Optimize use of serde (#9)
* simplified parsing * simplified json parser
1 parent 9f06714 commit 0519b48

File tree

4 files changed

+108
-66
lines changed

4 files changed

+108
-66
lines changed

Cargo.lock

Lines changed: 42 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ name = "fast_query_parsers"
1313
crate-type = ["cdylib"]
1414

1515
[dependencies]
16+
lazy_static = "1.4.0"
1617
pyo3 = { version = "0.17.3", features = ["extension-module", "abi3-py38"] }
1718
pythonize = "0.17.0"
19+
regex = { version = "1.7.0", features = ["perf"] }
1820
rustc-hash = "1.1.0"
1921
serde_json = "1.0.90"
2022
urlencoding = "2.1.2"

poetry.lock

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/query_string.rs

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1-
use rustc_hash::FxHashMap;
2-
use serde_json::{Map, Value};
31
use std::convert::Infallible;
2+
3+
use lazy_static::lazy_static;
4+
use regex::Regex;
5+
use rustc_hash::FxHashMap;
6+
use serde_json::{from_str, Value};
47
use urlencoding::decode;
58

9+
lazy_static! {
10+
static ref PARENTHESES_RE: Regex = Regex::new(r"(^\[.*\]$|^\{.*\}$)").unwrap();
11+
}
12+
613
#[inline]
714
pub fn parse_query_string(qs: &[u8], separator: char) -> Vec<(String, String)> {
815
String::from_utf8(qs.to_vec())
@@ -12,7 +19,7 @@ pub fn parse_query_string(qs: &[u8], separator: char) -> Vec<(String, String)> {
1219
.filter_map(|value| {
1320
if !value.is_empty() {
1421
return match decode(value).unwrap_or_default().split_once('=') {
15-
Some(value) => Some((value.0.to_owned(), value.1.to_owned())),
22+
Some((key, value)) => Some((key.to_owned(), value.to_owned())),
1623
None => Some((value.to_owned(), String::from(""))),
1724
};
1825
}
@@ -23,29 +30,17 @@ pub fn parse_query_string(qs: &[u8], separator: char) -> Vec<(String, String)> {
2330

2431
#[inline]
2532
fn decode_value(json_str: String) -> Value {
26-
if json_str.starts_with('{') && json_str.ends_with('}') {
27-
let values_map: Map<String, Value> =
28-
serde_json::from_str(json_str.as_str()).unwrap_or_default();
29-
let mut result: Map<String, Value> = Map::new();
30-
31-
for (k, v) in values_map {
32-
result.insert(k, decode_value(v.to_string()));
33-
}
34-
35-
return Value::from(result);
36-
}
37-
if json_str.starts_with('[') && json_str.ends_with(']') {
38-
let values_array: Value = serde_json::from_str(json_str.as_str()).unwrap_or_default();
39-
let vector_values = match values_array.as_array() {
40-
Some(arr) => arr
41-
.iter()
42-
.map(|el| decode_value(el.to_string()))
43-
.collect::<Vec<Value>>(),
44-
None => Vec::new(),
33+
if PARENTHESES_RE.is_match(json_str.as_str()) {
34+
let result: Value = match from_str(json_str.as_str()) {
35+
Ok(value) => value,
36+
Err(_) => match from_str(json_str.replace('\'', "\"").as_str()) {
37+
Ok(normalized) => normalized,
38+
Err(_) => Value::Null,
39+
},
4540
};
46-
47-
return Value::from(vector_values);
41+
return result;
4842
}
43+
4944
let normalized = json_str.replace('"', "");
5045

5146
let json_integer = normalized.parse::<i64>();
@@ -64,40 +59,37 @@ fn decode_value(json_str: String) -> Value {
6459

6560
#[inline]
6661
pub fn parse_query_string_to_json(bs: &[u8]) -> Value {
67-
let mut values_map: Map<String, Value> = Map::new();
68-
let mut array_map: FxHashMap<String, Vec<String>> = FxHashMap::default();
62+
let mut array_map: FxHashMap<String, Vec<Value>> = FxHashMap::default();
6963

7064
for (key, value) in parse_query_string(bs, '&') {
7165
match array_map.get_mut(&key) {
7266
Some(entry) => {
73-
entry.push(value);
67+
entry.push(decode_value(value));
7468
}
7569
None => {
76-
array_map.insert(key, vec![value]);
70+
array_map.insert(key, vec![decode_value(value)]);
7771
}
7872
}
7973
}
8074

81-
for (key, value) in array_map {
82-
if value.len() == 1 {
83-
values_map.insert(key, decode_value(value[0].to_owned()));
84-
} else {
85-
values_map.insert(
86-
key,
87-
decode_value(serde_json::to_string(&value).unwrap_or_default()),
88-
);
89-
}
90-
}
91-
92-
values_map.into()
75+
array_map
76+
.iter()
77+
.map(|(key, value)| {
78+
if value.len() == 1 {
79+
(key, value[0].to_owned())
80+
} else {
81+
(key, Value::Array(value.to_owned()))
82+
}
83+
})
84+
.collect::<Value>()
9385
}
9486

9587
#[cfg(test)]
9688
mod tests {
97-
use super::*;
98-
9989
use serde_json::{json, to_string, Value};
10090

91+
use super::*;
92+
10193
fn eq_str(value: Value, string: &str) {
10294
assert_eq!(&to_string(&value).unwrap_or_default(), string)
10395
}
@@ -239,8 +231,7 @@ mod tests {
239231
let result = parse_query_string_to_json(b"_id=637ca2c6a8178b1d6aab4140&index=0&guid=92d50031-11ee-4756-af59-cd47a45082e7&isActive=false&balance=%242%2C627.33&picture=http%3A%2F%2Fplacehold.it%2F32x32&age=36&eyeColor=blue&name=Colette+Suarez&gender=female&company=ZENTILITY&email=colettesuarez%40zentility.com&phone=%2B1+%28841%29+509-2669&address=400+Polar+Street%2C+Emory%2C+Palau%2C+3376&about=Deserunt+nostrud+quis+enim+fugiat+labore+labore+sint+deserunt+aliquip+est+fugiat+mollit+commodo.+Labore+pariatur+laboris+ut+irure+voluptate+aliqua+non+ex+enim.+Dolor+ea+mollit+dolore+anim+eu+velit+labore+aliquip+laborum+irure+duis+aliqua+sunt+sint.+Ex+elit+ea+irure+nisi+qui+exercitation+ullamco+occaecat+eu+culpa+magna+quis+dolor+dolor.+Officia+nostrud+consectetur+exercitation+consequat+qui+est+dolore+cillum+dolor+minim+tempor.%0D%0A&registered=2015-12-11T05%3A34%3A25+-01%3A00&latitude=-14.326509&longitude=-32.417451&tags=qui&tags=occaecat&tags=quis&tags=minim&tags=aliquip&tags=sunt&tags=pariatur&friends=%7B%27id%27%3A+0%2C+%27name%27%3A+%27Flora+Phelps%27%7D&friends=%7B%27id%27%3A+1%2C+%27name%27%3A+%27Coffey+Warner%27%7D&friends=%7B%27id%27%3A+2%2C+%27name%27%3A+%27Lyons+Mccall%27%7D&greeting=Hello%2C+Colette+Suarez%21+You+have+4+unread+messages.&favoriteFruit=banana");
240232
assert_eq!(
241233
result,
242-
json!(
243-
{
234+
json!({
244235
"_id": "637ca2c6a8178b1d6aab4140",
245236
"about": "Deserunt nostrud quis enim fugiat labore labore sint deserunt aliquip est fugiat mollit commodo. Labore pariatur laboris ut irure voluptate aliqua non ex enim. Dolor ea mollit dolore anim eu velit labore aliquip laborum irure duis aliqua sunt sint. Ex elit ea irure nisi qui exercitation ullamco occaecat eu culpa magna quis dolor dolor. Officia nostrud consectetur exercitation consequat qui est dolore cillum dolor minim tempor.\r\n",
246237
"address": "400 Polar Street, Emory, Palau, 3376",
@@ -251,9 +242,18 @@ mod tests {
251242
"eyeColor": "blue",
252243
"favoriteFruit": "banana",
253244
"friends": [
254-
"{'id': 0, 'name': 'Flora Phelps'}",
255-
"{'id': 1, 'name': 'Coffey Warner'}",
256-
"{'id': 2, 'name': 'Lyons Mccall'}"
245+
{
246+
"id":0,
247+
"name": "Flora Phelps"
248+
},
249+
{
250+
"id":1,
251+
"name": "Coffey Warner"
252+
},
253+
{
254+
"id":2,
255+
"name": "Lyons Mccall"
256+
}
257257
],
258258
"gender": "female",
259259
"greeting": "Hello, Colette Suarez! You have 4 unread messages.",
@@ -263,9 +263,9 @@ mod tests {
263263
"latitude": -14.326509,
264264
"longitude": -32.417451,
265265
"name": "Colette Suarez",
266-
"phone": "+1 (841) 509-2669",
267-
"picture": "http://placehold.it/32x32",
268-
"registered": "2015-12-11T05:34:25 -01:00",
266+
"phone":"+1 (841) 509-2669",
267+
"picture":"http://placehold.it/32x32",
268+
"registered":"2015-12-11T05:34:25 -01:00",
269269
"tags": [
270270
"qui",
271271
"occaecat",

0 commit comments

Comments
 (0)