Skip to content

Commit 833d2cd

Browse files
committed
feat: add URLSearchParams implementation
1 parent 40c7d01 commit 833d2cd

File tree

3 files changed

+319
-0
lines changed

3 files changed

+319
-0
lines changed

src/ffi.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ pub struct ada_url {
1313
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
1414
}
1515

16+
#[repr(C)]
17+
pub struct ada_url_search_params {
18+
_unused: [u8; 0],
19+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
20+
}
21+
1622
#[repr(C)]
1723
pub struct ada_string {
1824
pub data: *const c_char,
@@ -62,6 +68,37 @@ impl Drop for ada_owned_string {
6268
ada_free_owned_string(copy);
6369
};
6470
}
71+
72+
/// Represents an std::vector<std::string>
73+
#[repr(C)]
74+
pub struct ada_strings {
75+
_unused: [u8; 0],
76+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
77+
}
78+
79+
#[repr(C)]
80+
pub struct ada_url_search_params_keys_iter {
81+
_unused: [u8; 0],
82+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
83+
}
84+
85+
#[repr(C)]
86+
pub struct ada_url_search_params_values_iter {
87+
_unused: [u8; 0],
88+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
89+
}
90+
91+
#[repr(C)]
92+
pub struct ada_url_search_params_entries_iter {
93+
_unused: [u8; 0],
94+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
95+
}
96+
97+
/// Represents a key/value pair of strings
98+
#[repr(C)]
99+
pub struct ada_string_pair {
100+
pub key: ada_string,
101+
pub value: ada_string,
65102
}
66103

67104
#[repr(C)]
@@ -143,6 +180,102 @@ extern "C" {
143180
// IDNA methods
144181
pub fn ada_idna_to_unicode(input: *const c_char, length: usize) -> ada_owned_string;
145182
pub fn ada_idna_to_ascii(input: *const c_char, length: usize) -> ada_owned_string;
183+
184+
// URLSearchParams
185+
pub fn ada_parse_search_params(
186+
input: *const c_char,
187+
length: usize,
188+
) -> *mut ada_url_search_params;
189+
pub fn ada_free_search_params(search_params: *mut ada_url_search_params);
190+
pub fn ada_search_params_size(search_params: *mut ada_url_search_params) -> usize;
191+
pub fn ada_search_params_sort(search_params: *mut ada_url_search_params);
192+
pub fn ada_search_params_to_string(
193+
search_params: *mut ada_url_search_params,
194+
) -> ada_owned_string;
195+
pub fn ada_search_params_append(
196+
search_params: *mut ada_url_search_params,
197+
name: *const c_char,
198+
name_length: usize,
199+
value: *const c_char,
200+
value_length: usize,
201+
);
202+
pub fn ada_search_params_set(
203+
search_params: *mut ada_url_search_params,
204+
name: *const c_char,
205+
name_length: usize,
206+
value: *const c_char,
207+
value_length: usize,
208+
);
209+
pub fn ada_search_params_remove(
210+
search_params: *mut ada_url_search_params,
211+
name: *const c_char,
212+
name_length: usize,
213+
);
214+
pub fn ada_search_params_remove_value(
215+
search_params: *mut ada_url_search_params,
216+
name: *const c_char,
217+
name_length: usize,
218+
value: *const c_char,
219+
value_length: usize,
220+
);
221+
pub fn ada_search_params_has(
222+
search_params: *mut ada_url_search_params,
223+
name: *const c_char,
224+
name_length: usize,
225+
) -> bool;
226+
pub fn ada_search_params_has_value(
227+
search_params: *mut ada_url_search_params,
228+
name: *const c_char,
229+
name_length: usize,
230+
value: *const c_char,
231+
value_length: usize,
232+
) -> bool;
233+
pub fn ada_search_params_get(
234+
search_params: *mut ada_url_search_params,
235+
key: *const c_char,
236+
key_length: usize,
237+
) -> ada_string;
238+
pub fn ada_search_params_get_all(
239+
// not implemented
240+
search_params: *mut ada_url_search_params,
241+
key: *const c_char,
242+
key_length: usize,
243+
) -> *mut ada_strings;
244+
pub fn ada_search_params_get_keys(
245+
search_params: *mut ada_url_search_params,
246+
) -> *mut ada_url_search_params_keys_iter;
247+
pub fn ada_search_params_get_values(
248+
search_params: *mut ada_url_search_params,
249+
) -> *mut ada_url_search_params_values_iter;
250+
pub fn ada_search_params_get_entries(
251+
search_params: *mut ada_url_search_params,
252+
) -> *mut ada_url_search_params_entries_iter;
253+
254+
pub fn ada_free_strings(strings: *mut ada_strings);
255+
pub fn ada_strings_size(strings: *mut ada_strings) -> usize;
256+
pub fn ada_strings_get(strings: *mut ada_strings, index: usize) -> ada_string;
257+
pub fn ada_free_search_params_keys_iter(iter: *mut ada_url_search_params_keys_iter);
258+
pub fn ada_search_params_keys_iter_next(
259+
iter: *mut ada_url_search_params_keys_iter,
260+
) -> *mut ada_string;
261+
pub fn ada_search_params_keys_iter_has_next(iter: *mut ada_url_search_params_keys_iter)
262+
-> bool;
263+
264+
pub fn ada_free_search_params_values_iter(iter: *mut ada_url_search_params_values_iter);
265+
pub fn ada_search_params_values_iter_next(
266+
iter: *mut ada_url_search_params_values_iter,
267+
) -> *mut ada_string;
268+
pub fn ada_search_params_values_iter_has_next(
269+
iter: *mut ada_url_search_params_values_iter,
270+
) -> bool;
271+
272+
pub fn ada_free_search_params_entries_iter(iter: *mut ada_url_search_params_entries_iter);
273+
pub fn ada_search_params_entries_iter_next(
274+
iter: *mut ada_url_search_params_entries_iter,
275+
) -> *mut ada_string_pair;
276+
pub fn ada_search_params_entries_iter_has_next(
277+
iter: *mut ada_url_search_params_entries_iter,
278+
) -> bool;
146279
}
147280

148281
#[cfg(test)]

src/lib.rs

Lines changed: 2 additions & 0 deletions
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
#[cfg(feature = "std")]
5052
extern crate std;

src/url_search_params.rs

Lines changed: 184 additions & 0 deletions
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)