Skip to content

Commit cec22c8

Browse files
committed
feat: add uri-plz crate
1 parent d1e299a commit cec22c8

File tree

7 files changed

+601
-0
lines changed

7 files changed

+601
-0
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ members = [
66
"header-plz",
77
"mime-plz",
88
"protocol-traits-plz",
9+
"uri-plz"
910
]
1011

1112
[workspace.dependencies]

uri-plz/Cargo.lock

+16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

uri-plz/Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "uri-plz"
3+
version = "0.0.1"
4+
authors = ["darkseid", "sytten <[email protected]>"]
5+
description = "Uri parser for the ParsePlz ecosystem"
6+
repository = "https://github.com/parseplz/primitives"
7+
license = "MIT"
8+
edition = "2024"
9+
10+
[dependencies]
11+
bytes = "1.10.1"

uri-plz/src/lib.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![allow(unused)]
2+
mod query;
3+
mod querykvpair;
4+
mod uri;
5+
6+
pub const FRAGMENT: u8 = b'#';
7+
pub const QMARK: u8 = b'?';
8+
pub const FORWARD_SLASH: u8 = b'/';
9+
pub const AMBER: u8 = b'&';
10+
pub const EQUAL: u8 = b'=';

uri-plz/src/query.rs

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
use bytes::BytesMut;
2+
3+
use crate::{AMBER, querykvpair::QueryKvPair};
4+
5+
#[derive(Default)]
6+
pub struct Query {
7+
qmark: BytesMut, // "?" mandatory as identifies query
8+
pub kv_pair: Option<Vec<QueryKvPair>>,
9+
}
10+
11+
impl Query {
12+
fn new(qmark: BytesMut, kv_pair: Option<Vec<QueryKvPair>>) -> Self {
13+
Query { qmark, kv_pair }
14+
}
15+
16+
pub fn parse(mut input: BytesMut) -> Option<Self> {
17+
let qmark = input.split_to(1); // always present
18+
let kv_pair = split_query_kv_pair(input);
19+
Some(Query::new(qmark, kv_pair))
20+
}
21+
22+
pub fn into_data(self) -> Option<BytesMut> {
23+
let mut data = self.qmark;
24+
if let Some(kv_vec) = self.kv_pair {
25+
for kv in kv_vec {
26+
if let Some(kv_data) = kv.into_data() {
27+
data.unsplit(kv_data);
28+
}
29+
}
30+
}
31+
Some(data)
32+
}
33+
}
34+
35+
fn split_query_kv_pair(mut input: BytesMut) -> Option<Vec<QueryKvPair>> {
36+
let mut kv_vec = Vec::new();
37+
38+
while !input.is_empty() {
39+
match input.iter().position(|&c| c == AMBER) {
40+
Some(index) => {
41+
let kv = input.split_to(index + 1);
42+
if let Some(v) = QueryKvPair::parse(kv, true) {
43+
kv_vec.push(v)
44+
}
45+
}
46+
None => {
47+
// single pair
48+
if let Some(v) = QueryKvPair::parse(input, false) {
49+
kv_vec.push(v)
50+
}
51+
break;
52+
}
53+
}
54+
}
55+
56+
(!kv_vec.is_empty()).then_some(kv_vec)
57+
}
58+
59+
mod tests {
60+
use super::*;
61+
62+
#[test]
63+
fn test_query_parse_only_qmark() {
64+
let buf = BytesMut::from("?");
65+
let verify = buf.as_ptr_range();
66+
let query = Query::parse(buf).unwrap();
67+
assert_eq!(query.qmark, "?");
68+
assert!(query.kv_pair.is_none());
69+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
70+
}
71+
72+
#[test]
73+
fn test_query_parse_single() {
74+
let buf = BytesMut::from("?a=b");
75+
let verify = buf.as_ptr_range();
76+
let query = Query::parse(buf).unwrap();
77+
assert_eq!(query.qmark, "?");
78+
assert_eq!(query.qmark, "?");
79+
let kv_vec = query.kv_pair.as_ref().unwrap();
80+
assert_eq!(kv_vec[0].key, Some("a".into()));
81+
assert_eq!(kv_vec[0].val, Some("b".into()));
82+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
83+
}
84+
85+
#[test]
86+
fn test_query_parse_multiple() {
87+
let buf = BytesMut::from("?a=b&c=d&e=f");
88+
let verify = buf.as_ptr_range();
89+
let query = Query::parse(buf).unwrap();
90+
assert_eq!(query.qmark, "?");
91+
let kv_vec = query.kv_pair.as_ref().unwrap();
92+
assert_eq!(kv_vec[0].key, Some("a".into()));
93+
assert_eq!(kv_vec[0].val, Some("b".into()));
94+
assert_eq!(kv_vec[1].key, Some("c".into()));
95+
assert_eq!(kv_vec[1].val, Some("d".into()));
96+
assert_eq!(kv_vec[2].key, Some("e".into()));
97+
assert_eq!(kv_vec[2].val, Some("f".into()));
98+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
99+
}
100+
101+
#[test]
102+
fn test_query_parse_empty_key_and_value() {
103+
let buf = BytesMut::from("?=value&key=");
104+
let verify = buf.as_ptr_range();
105+
let query = Query::parse(buf).unwrap();
106+
let kv = query.kv_pair.as_ref().unwrap();
107+
assert_eq!(kv[0].key, None);
108+
assert_eq!(kv[0].val, Some("value".into()));
109+
assert_eq!(kv[1].key, Some("key".into()));
110+
assert_eq!(kv[1].val, None);
111+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
112+
}
113+
114+
#[test]
115+
fn test_query_parse_key_only() {
116+
let buf = BytesMut::from("?key");
117+
let verify = buf.as_ptr_range();
118+
let query = Query::parse(buf).unwrap();
119+
let kv = query.kv_pair.as_ref().unwrap();
120+
assert_eq!(kv[0].key, None);
121+
assert_eq!(kv[0].val, Some("key".into()));
122+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
123+
}
124+
125+
#[test]
126+
fn test_query_parse_trailing_ampersand() {
127+
let buf = BytesMut::from("?a=b&");
128+
let verify = buf.as_ptr_range();
129+
let query = Query::parse(buf).unwrap();
130+
assert_eq!(query.qmark, "?");
131+
let kv_vec = query.kv_pair.as_ref().unwrap();
132+
assert_eq!(kv_vec[0].key, Some("a".into()));
133+
assert_eq!(kv_vec[0].val, Some("b".into()));
134+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
135+
}
136+
137+
#[test]
138+
fn test_query_double_ampersand() {
139+
let buf = BytesMut::from("?a=b&&c=d");
140+
let verify = buf.as_ptr_range();
141+
let query = Query::parse(buf).unwrap();
142+
let kv = query.kv_pair.as_ref().unwrap();
143+
assert_eq!(kv[0].key, Some("a".into()));
144+
assert_eq!(kv[0].val, Some("b".into()));
145+
assert_eq!(kv[1].key, None); // empty pair
146+
assert_eq!(kv[1].val, None);
147+
assert_eq!(kv[2].key, Some("c".into()));
148+
assert_eq!(kv[2].val, Some("d".into()));
149+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
150+
}
151+
152+
#[test]
153+
fn test_query_only_value() {
154+
let buf = BytesMut::from("?=value");
155+
let verify = buf.as_ptr_range();
156+
let query = Query::parse(buf).unwrap();
157+
let kv = query.kv_pair.as_ref().unwrap();
158+
assert_eq!(kv[0].key, None);
159+
assert_eq!(kv[0].val, Some("value".into()));
160+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
161+
}
162+
}

uri-plz/src/querykvpair.rs

+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
use crate::EQUAL;
2+
use bytes::BytesMut;
3+
4+
#[derive(Default, Debug)]
5+
pub struct QueryKvPair {
6+
pub key: Option<BytesMut>,
7+
equal: Option<BytesMut>,
8+
pub val: Option<BytesMut>,
9+
amp: Option<BytesMut>,
10+
}
11+
12+
impl QueryKvPair {
13+
pub fn new(
14+
key: Option<BytesMut>,
15+
equal: Option<BytesMut>,
16+
val: Option<BytesMut>,
17+
amp: Option<BytesMut>,
18+
) -> Self {
19+
QueryKvPair {
20+
key,
21+
equal,
22+
val,
23+
amp,
24+
}
25+
}
26+
27+
pub fn parse(mut input: BytesMut, with_amper: bool) -> Option<Self> {
28+
if input.is_empty() {
29+
return None;
30+
}
31+
32+
if let Some(index) = input.iter().position(|&c| c == EQUAL) {
33+
let raw_key = empty_to_none(input.split_to(index));
34+
let equal = Some(input.split_to(1)); // equal persent
35+
let amp = if with_amper {
36+
empty_to_none(input.split_off(input.len() - 1))
37+
} else {
38+
None
39+
};
40+
let val = empty_to_none(input);
41+
let kvpair = QueryKvPair::new(raw_key, equal, val, amp);
42+
Some(kvpair)
43+
} else {
44+
// only value
45+
let amp = if with_amper {
46+
empty_to_none(input.split_off(input.len() - 1))
47+
} else {
48+
None
49+
};
50+
let val = empty_to_none(input);
51+
let kvpair = QueryKvPair::new(None, None, val, amp);
52+
Some(kvpair)
53+
}
54+
}
55+
56+
pub fn into_data(self) -> Option<BytesMut> {
57+
let mut data = self.key.unwrap_or_default();
58+
if let Some(equal) = self.equal {
59+
data.unsplit(equal);
60+
};
61+
if let Some(val) = self.val {
62+
data.unsplit(val);
63+
}
64+
if let Some(amp) = self.amp {
65+
data.unsplit(amp);
66+
}
67+
68+
empty_to_none(data)
69+
}
70+
}
71+
72+
pub fn empty_to_none(input: BytesMut) -> Option<BytesMut> {
73+
(!input.is_empty()).then_some(input)
74+
}
75+
76+
mod tests {
77+
use super::*;
78+
79+
#[test]
80+
fn test_kv_pair() {
81+
let raw_query = BytesMut::from("a=b");
82+
let verify = raw_query.as_ptr_range();
83+
let query = QueryKvPair::parse(raw_query, false).unwrap();
84+
assert_eq!(query.key.as_ref().unwrap(), "a");
85+
assert_eq!(query.val.as_ref().unwrap(), "b");
86+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
87+
}
88+
89+
#[test]
90+
fn test_kv_pair_key_only() {
91+
let raw_query = BytesMut::from("a=");
92+
let verify = raw_query.as_ptr_range();
93+
let query = QueryKvPair::parse(raw_query, false).unwrap();
94+
assert_eq!(query.key.as_ref().unwrap(), "a");
95+
assert_eq!(query.val, None);
96+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
97+
}
98+
99+
#[test]
100+
fn test_kv_pair_val_only() {
101+
let raw_query = BytesMut::from("=b");
102+
let verify = raw_query.as_ptr_range();
103+
let query = QueryKvPair::parse(raw_query, false).unwrap();
104+
assert_eq!(query.key, None);
105+
assert_eq!(query.val.as_ref().unwrap(), "b");
106+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
107+
}
108+
109+
#[test]
110+
fn test_kv_pair_no_equal() {
111+
let raw_query = BytesMut::from("a");
112+
let verify = raw_query.as_ptr_range();
113+
let query = QueryKvPair::parse(raw_query, false).unwrap();
114+
assert_eq!(query.key, None);
115+
assert_eq!(query.val.as_ref().unwrap(), "a");
116+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
117+
}
118+
119+
#[test]
120+
fn test_kv_pair_with_amp() {
121+
let raw_query = BytesMut::from("a=b&");
122+
let verify = raw_query.as_ptr_range();
123+
let query = QueryKvPair::parse(raw_query, true).unwrap();
124+
assert_eq!(query.key.as_ref().unwrap(), "a");
125+
assert_eq!(query.val.as_ref().unwrap(), "b");
126+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
127+
}
128+
129+
#[test]
130+
fn test_kv_pair_key_only_with_amp() {
131+
let raw_query = BytesMut::from("a=&");
132+
let verify = raw_query.as_ptr_range();
133+
let query = QueryKvPair::parse(raw_query, true).unwrap();
134+
assert_eq!(query.key.as_ref().unwrap(), "a");
135+
assert_eq!(query.val, None);
136+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
137+
}
138+
139+
#[test]
140+
fn test_kv_pair_val_only_with_amp() {
141+
let raw_query = BytesMut::from("=b&");
142+
let verify = raw_query.as_ptr_range();
143+
let query = QueryKvPair::parse(raw_query, true).unwrap();
144+
assert_eq!(query.key, None);
145+
assert_eq!(query.val.as_ref().unwrap(), "b");
146+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
147+
}
148+
149+
#[test]
150+
fn test_kv_pair_no_equal_with_amp() {
151+
let raw_query = BytesMut::from("a&");
152+
let verify = raw_query.as_ptr_range();
153+
let query = QueryKvPair::parse(raw_query, true).unwrap();
154+
assert_eq!(query.key, None);
155+
assert_eq!(query.val.as_ref().unwrap(), "a");
156+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
157+
}
158+
159+
#[test]
160+
fn test_kv_pair_only_equal() {
161+
let raw = BytesMut::from("=");
162+
let verify = raw.as_ptr_range();
163+
let query = QueryKvPair::parse(raw, false).unwrap();
164+
assert!(query.key.is_none());
165+
assert!(query.val.is_none());
166+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
167+
}
168+
169+
#[test]
170+
fn test_kv_pair_multiple_equals() {
171+
let raw = BytesMut::from("a=b=c");
172+
let verify = raw.as_ptr_range();
173+
let query = QueryKvPair::parse(raw, false).unwrap();
174+
assert_eq!(query.key.as_ref().unwrap(), "a");
175+
assert_eq!(query.val.as_ref().unwrap(), "b=c");
176+
assert_eq!(query.into_data().unwrap().as_ptr_range(), verify);
177+
}
178+
}

0 commit comments

Comments
 (0)