Skip to content

Commit 4816774

Browse files
committed
feat: add URLSearchParams implementation
1 parent 57b5a20 commit 4816774

File tree

3 files changed

+321
-1
lines changed

3 files changed

+321
-1
lines changed

src/ffi.rs

+134
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ pub struct ada_url {
77
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
88
}
99

10+
#[repr(C)]
11+
pub struct ada_url_search_params {
12+
_unused: [u8; 0],
13+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
14+
}
15+
1016
#[repr(C)]
1117
pub struct ada_string {
1218
pub data: *const c_char,
@@ -37,6 +43,38 @@ impl AsRef<str> for ada_owned_string {
3743
}
3844
}
3945

46+
/// Represents an std::vector<std::string>
47+
#[repr(C)]
48+
pub struct ada_strings {
49+
_unused: [u8; 0],
50+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
51+
}
52+
53+
#[repr(C)]
54+
pub struct ada_url_search_params_keys_iter {
55+
_unused: [u8; 0],
56+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
57+
}
58+
59+
#[repr(C)]
60+
pub struct ada_url_search_params_values_iter {
61+
_unused: [u8; 0],
62+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
63+
}
64+
65+
#[repr(C)]
66+
pub struct ada_url_search_params_entries_iter {
67+
_unused: [u8; 0],
68+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
69+
}
70+
71+
/// Represents a key/value pair of strings
72+
#[repr(C)]
73+
pub struct ada_string_pair {
74+
pub key: ada_string,
75+
pub value: ada_string,
76+
}
77+
4078
#[repr(C)]
4179
pub struct ada_url_components {
4280
pub protocol_end: u32,
@@ -116,4 +154,100 @@ extern "C" {
116154
// IDNA methods
117155
pub fn ada_idna_to_unicode(input: *const c_char, length: usize) -> ada_owned_string;
118156
pub fn ada_idna_to_ascii(input: *const c_char, length: usize) -> ada_owned_string;
157+
158+
// URLSearchParams
159+
pub fn ada_parse_search_params(
160+
input: *const c_char,
161+
length: usize,
162+
) -> *mut ada_url_search_params;
163+
pub fn ada_free_search_params(search_params: *mut ada_url_search_params);
164+
pub fn ada_search_params_size(search_params: *mut ada_url_search_params) -> usize;
165+
pub fn ada_search_params_sort(search_params: *mut ada_url_search_params);
166+
pub fn ada_search_params_to_string(
167+
search_params: *mut ada_url_search_params,
168+
) -> ada_owned_string;
169+
pub fn ada_search_params_append(
170+
search_params: *mut ada_url_search_params,
171+
name: *const c_char,
172+
name_length: usize,
173+
value: *const c_char,
174+
value_length: usize,
175+
);
176+
pub fn ada_search_params_set(
177+
search_params: *mut ada_url_search_params,
178+
name: *const c_char,
179+
name_length: usize,
180+
value: *const c_char,
181+
value_length: usize,
182+
);
183+
pub fn ada_search_params_remove(
184+
search_params: *mut ada_url_search_params,
185+
name: *const c_char,
186+
name_length: usize,
187+
);
188+
pub fn ada_search_params_remove_value(
189+
search_params: *mut ada_url_search_params,
190+
name: *const c_char,
191+
name_length: usize,
192+
value: *const c_char,
193+
value_length: usize,
194+
);
195+
pub fn ada_search_params_has(
196+
search_params: *mut ada_url_search_params,
197+
name: *const c_char,
198+
name_length: usize,
199+
) -> bool;
200+
pub fn ada_search_params_has_value(
201+
search_params: *mut ada_url_search_params,
202+
name: *const c_char,
203+
name_length: usize,
204+
value: *const c_char,
205+
value_length: usize,
206+
) -> bool;
207+
pub fn ada_search_params_get(
208+
search_params: *mut ada_url_search_params,
209+
key: *const c_char,
210+
key_length: usize,
211+
) -> ada_string;
212+
pub fn ada_search_params_get_all(
213+
// not implemented
214+
search_params: *mut ada_url_search_params,
215+
key: *const c_char,
216+
key_length: usize,
217+
) -> *mut ada_strings;
218+
pub fn ada_search_params_get_keys(
219+
search_params: *mut ada_url_search_params,
220+
) -> *mut ada_url_search_params_keys_iter;
221+
pub fn ada_search_params_get_values(
222+
search_params: *mut ada_url_search_params,
223+
) -> *mut ada_url_search_params_values_iter;
224+
pub fn ada_search_params_get_entries(
225+
search_params: *mut ada_url_search_params,
226+
) -> *mut ada_url_search_params_entries_iter;
227+
228+
pub fn ada_free_strings(strings: *mut ada_strings);
229+
pub fn ada_strings_size(strings: *mut ada_strings) -> usize;
230+
pub fn ada_strings_get(strings: *mut ada_strings, index: usize) -> ada_string;
231+
pub fn ada_free_search_params_keys_iter(iter: *mut ada_url_search_params_keys_iter);
232+
pub fn ada_search_params_keys_iter_next(
233+
iter: *mut ada_url_search_params_keys_iter,
234+
) -> *mut ada_string;
235+
pub fn ada_search_params_keys_iter_has_next(iter: *mut ada_url_search_params_keys_iter)
236+
-> bool;
237+
238+
pub fn ada_free_search_params_values_iter(iter: *mut ada_url_search_params_values_iter);
239+
pub fn ada_search_params_values_iter_next(
240+
iter: *mut ada_url_search_params_values_iter,
241+
) -> *mut ada_string;
242+
pub fn ada_search_params_values_iter_has_next(
243+
iter: *mut ada_url_search_params_values_iter,
244+
) -> bool;
245+
246+
pub fn ada_free_search_params_entries_iter(iter: *mut ada_url_search_params_entries_iter);
247+
pub fn ada_search_params_entries_iter_next(
248+
iter: *mut ada_url_search_params_entries_iter,
249+
) -> *mut ada_string_pair;
250+
pub fn ada_search_params_entries_iter_has_next(
251+
iter: *mut ada_url_search_params_entries_iter,
252+
) -> bool;
119253
}

src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@
4444

4545
pub mod ffi;
4646
mod idna;
47+
mod url_search_params;
4748
pub use idna::Idna;
49+
pub use url_search_params::URLSearchParams;
4850

4951
use core::{borrow, ffi::c_uint, fmt, hash, ops};
5052
use derive_more::Display;
@@ -730,7 +732,7 @@ impl PartialEq for Url {
730732

731733
impl PartialOrd for Url {
732734
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
733-
self.href().partial_cmp(other.href())
735+
Some(self.cmp(other))
734736
}
735737
}
736738

src/url_search_params.rs

+184
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
use crate::ffi;
2+
3+
pub struct URLSearchParams(*mut ffi::ada_url_search_params);
4+
5+
impl Drop for URLSearchParams {
6+
fn drop(&mut self) {
7+
unsafe { ffi::ada_free_search_params(self.0) }
8+
}
9+
}
10+
11+
impl URLSearchParams {
12+
/// Parses an return a URLSearchParams struct.
13+
///
14+
/// ```
15+
/// use ada_url::URLSearchParams;
16+
/// let params = URLSearchParams::parse("a=1&b=2");
17+
/// assert_eq!(params.get("a"), Some("1"));
18+
/// assert_eq!(params.get("b"), Some("2"));
19+
/// ```
20+
pub fn parse(input: &str) -> Self {
21+
Self(unsafe { ffi::ada_parse_search_params(input.as_ptr().cast(), input.len()) })
22+
}
23+
24+
/// Returns the size of the URLSearchParams struct.
25+
///
26+
/// ```
27+
/// use ada_url::URLSearchParams;
28+
/// let params = URLSearchParams::parse("a=1&b=2");
29+
/// assert_eq!(params.size(), 2);
30+
/// ```
31+
pub fn size(&self) -> usize {
32+
unsafe { ffi::ada_search_params_size(self.0) }
33+
}
34+
35+
/// Sorts the keys of the URLSearchParams struct.
36+
pub fn sort(&self) {
37+
unsafe { ffi::ada_search_params_sort(self.0) }
38+
}
39+
40+
/// Appends a key/value to the URLSearchParams struct.
41+
pub fn append(&self, key: &str, value: &str) {
42+
unsafe {
43+
ffi::ada_search_params_append(
44+
self.0,
45+
key.as_ptr().cast(),
46+
key.len(),
47+
value.as_ptr().cast(),
48+
value.len(),
49+
)
50+
}
51+
}
52+
53+
/// Removes all keys pre-existing keys from the URLSearchParams struct
54+
/// and appends the new key/value.
55+
///
56+
/// ```
57+
/// use ada_url::URLSearchParams;
58+
/// let params = URLSearchParams::parse("a=1&b=2");
59+
/// params.set("a", "3");
60+
/// assert_eq!(params.get("a"), Some("3"));
61+
/// ```
62+
pub fn set(&self, key: &str, value: &str) {
63+
unsafe {
64+
ffi::ada_search_params_set(
65+
self.0,
66+
key.as_ptr().cast(),
67+
key.len(),
68+
value.as_ptr().cast(),
69+
value.len(),
70+
)
71+
}
72+
}
73+
74+
/// Removes a key/value from the URLSearchParams struct.
75+
/// Depending on the value parameter, it will either remove
76+
/// the key/value pair or just the key.
77+
///
78+
/// ```
79+
/// use ada_url::URLSearchParams;
80+
/// let params = URLSearchParams::parse("a=1&b=2");
81+
/// params.remove("a", Some("1"));
82+
/// assert_eq!(params.get("a"), None);
83+
/// ```
84+
pub fn remove(&self, key: &str, value: Option<&str>) {
85+
if let Some(value) = value {
86+
unsafe {
87+
ffi::ada_search_params_remove_value(
88+
self.0,
89+
key.as_ptr().cast(),
90+
key.len(),
91+
value.as_ptr().cast(),
92+
value.len(),
93+
)
94+
}
95+
} else {
96+
unsafe { ffi::ada_search_params_remove(self.0, key.as_ptr().cast(), key.len()) }
97+
}
98+
}
99+
100+
/// Retruns true if the URLSearchParams struct contains the key.
101+
///
102+
/// ```
103+
/// use ada_url::URLSearchParams;
104+
/// let params = URLSearchParams::parse("a=1&b=2");
105+
/// assert_eq!(params.has("a", None), true);
106+
/// ```
107+
pub fn has(&self, key: &str, value: Option<&str>) -> bool {
108+
if let Some(value) = value {
109+
unsafe {
110+
ffi::ada_search_params_has_value(
111+
self.0,
112+
key.as_ptr().cast(),
113+
key.len(),
114+
value.as_ptr().cast(),
115+
value.len(),
116+
)
117+
}
118+
} else {
119+
unsafe { ffi::ada_search_params_has(self.0, key.as_ptr().cast(), key.len()) }
120+
}
121+
}
122+
123+
/// Returns the value of the key.
124+
///
125+
/// ```
126+
/// use ada_url::URLSearchParams;
127+
/// let params = URLSearchParams::parse("a=1&b=2");
128+
/// assert_eq!(params.get("a"), Some("1"));
129+
/// assert_eq!(params.get("c"), None);
130+
/// ```
131+
pub fn get(&self, key: &str) -> Option<&str> {
132+
unsafe {
133+
let out = ffi::ada_search_params_get(self.0, key.as_ptr().cast(), key.len());
134+
135+
if out.data.is_null() {
136+
return None;
137+
}
138+
let slice = core::slice::from_raw_parts(out.data.cast(), out.length);
139+
Some(core::str::from_utf8_unchecked(slice))
140+
}
141+
}
142+
143+
/// Returns the stringified version of the URLSearchParams struct.
144+
///
145+
/// ```
146+
/// use ada_url::URLSearchParams;
147+
/// let params = URLSearchParams::parse("a=1&b=2");
148+
/// assert_eq!(params.to_string(), "a=1&b=2");
149+
/// ```
150+
pub fn to_string(&self) -> &str {
151+
unsafe {
152+
let out = ffi::ada_search_params_to_string(self.0);
153+
let slice = core::slice::from_raw_parts(out.data.cast(), out.length);
154+
core::str::from_utf8_unchecked(slice)
155+
}
156+
}
157+
158+
/// Returns all values of the key.
159+
///
160+
/// ```
161+
/// use ada_url::URLSearchParams;
162+
/// let params = URLSearchParams::parse("a=1&a=2");
163+
/// assert_eq!(params.get_all("a"), vec!["1", "2"]);
164+
/// ```
165+
pub fn get_all(&self, key: &str) -> Vec<&str> {
166+
unsafe {
167+
let strings = ffi::ada_search_params_get_all(self.0, key.as_ptr().cast(), key.len());
168+
let size = ffi::ada_strings_size(strings);
169+
let mut out = Vec::with_capacity(size);
170+
171+
if size == 0 {
172+
return out;
173+
}
174+
175+
for index in 0..size {
176+
let string = ffi::ada_strings_get(strings, index);
177+
let slice = core::slice::from_raw_parts(string.data.cast(), string.length);
178+
out.push(core::str::from_utf8_unchecked(slice));
179+
}
180+
181+
out
182+
}
183+
}
184+
}

0 commit comments

Comments
 (0)