Skip to content

Commit ac2efd0

Browse files
committed
add iterator functions
1 parent 833d2cd commit ac2efd0

File tree

2 files changed

+192
-19
lines changed

2 files changed

+192
-19
lines changed

src/ffi.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ impl Drop for ada_owned_string {
6868
ada_free_owned_string(copy);
6969
};
7070
}
71+
}
7172

7273
/// Represents an std::vector<std::string>
7374
#[repr(C)]
@@ -257,14 +258,14 @@ extern "C" {
257258
pub fn ada_free_search_params_keys_iter(iter: *mut ada_url_search_params_keys_iter);
258259
pub fn ada_search_params_keys_iter_next(
259260
iter: *mut ada_url_search_params_keys_iter,
260-
) -> *mut ada_string;
261+
) -> ada_string;
261262
pub fn ada_search_params_keys_iter_has_next(iter: *mut ada_url_search_params_keys_iter)
262263
-> bool;
263264

264265
pub fn ada_free_search_params_values_iter(iter: *mut ada_url_search_params_values_iter);
265266
pub fn ada_search_params_values_iter_next(
266267
iter: *mut ada_url_search_params_values_iter,
267-
) -> *mut ada_string;
268+
) -> ada_string;
268269
pub fn ada_search_params_values_iter_has_next(
269270
iter: *mut ada_url_search_params_values_iter,
270271
) -> bool;

src/url_search_params.rs

Lines changed: 189 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -147,38 +147,210 @@ impl URLSearchParams {
147147
/// let params = URLSearchParams::parse("a=1&b=2");
148148
/// assert_eq!(params.to_string(), "a=1&b=2");
149149
/// ```
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-
}
150+
#[cfg(feature = "std")]
151+
#[allow(clippy::inherent_to_string)]
152+
pub fn to_string(&self) -> String {
153+
unsafe { ffi::ada_search_params_to_string(self.0).to_string() }
156154
}
157155

158156
/// Returns all values of the key.
159157
///
160158
/// ```
161159
/// use ada_url::URLSearchParams;
162160
/// let params = URLSearchParams::parse("a=1&a=2");
163-
/// assert_eq!(params.get_all("a"), vec!["1", "2"]);
161+
/// let pairs = params.get_all("a");
162+
/// assert_eq!(pairs.get_size(), 2);
164163
/// ```
165-
pub fn get_all(&self, key: &str) -> Vec<&str> {
164+
pub fn get_all(&self, key: &str) -> URLSearchParamsEntry {
166165
unsafe {
167166
let strings = ffi::ada_search_params_get_all(self.0, key.as_ptr().cast(), key.len());
168167
let size = ffi::ada_strings_size(strings);
169-
let mut out = Vec::with_capacity(size);
170168

171-
if size == 0 {
172-
return out;
173-
}
169+
URLSearchParamsEntry::new(strings, size)
170+
}
171+
}
172+
173+
/// Returns all keys as an iterator
174+
///
175+
/// ```
176+
/// use ada_url::URLSearchParams;
177+
/// let params = URLSearchParams::parse("a=1");
178+
/// let mut keys = params.get_keys();
179+
/// assert!(keys.has_next());
180+
pub fn get_keys(&self) -> URLSearchParamsKeysIterator {
181+
let iterator = unsafe { ffi::ada_search_params_get_keys(self.0) };
182+
URLSearchParamsKeysIterator::new(iterator)
183+
}
184+
185+
/// Returns all keys as an iterator
186+
///
187+
/// ```
188+
/// use ada_url::URLSearchParams;
189+
/// let params = URLSearchParams::parse("a=1");
190+
/// let mut values = params.get_values();
191+
/// assert!(values.has_next());
192+
pub fn get_values(&self) -> URLSearchParamsValuesIterator {
193+
let iterator = unsafe { ffi::ada_search_params_get_values(self.0) };
194+
URLSearchParamsValuesIterator::new(iterator)
195+
}
196+
}
197+
198+
pub struct URLSearchParamsKeysIterator<'a> {
199+
iterator: *mut ffi::ada_url_search_params_keys_iter,
200+
_phantom: core::marker::PhantomData<&'a str>,
201+
}
202+
203+
impl<'a> Drop for URLSearchParamsKeysIterator<'a> {
204+
fn drop(&mut self) {
205+
unsafe { ffi::ada_free_search_params_keys_iter(self.iterator) }
206+
}
207+
}
208+
209+
impl<'a> URLSearchParamsKeysIterator<'a> {
210+
/// Returns true if iterator has a next value.
211+
pub fn has_next(&self) -> bool {
212+
unsafe { ffi::ada_search_params_keys_iter_has_next(self.iterator) }
213+
}
214+
215+
/// Returns a new value if it's available
216+
pub fn get_next(&self) -> Option<&str> {
217+
if self.has_next() {
218+
return None;
219+
}
220+
let string = unsafe { ffi::ada_search_params_keys_iter_next(self.iterator) };
221+
Some(string.as_str())
222+
}
223+
}
224+
225+
pub struct URLSearchParamsValuesIterator<'a> {
226+
iterator: *mut ffi::ada_url_search_params_values_iter,
227+
_phantom: core::marker::PhantomData<&'a str>,
228+
}
229+
230+
impl<'a> URLSearchParamsKeysIterator<'a> {
231+
fn new(iterator: *mut ffi::ada_url_search_params_keys_iter) -> URLSearchParamsKeysIterator<'a> {
232+
URLSearchParamsKeysIterator {
233+
iterator,
234+
_phantom: core::marker::PhantomData,
235+
}
236+
}
237+
}
238+
239+
impl<'a> Drop for URLSearchParamsValuesIterator<'a> {
240+
fn drop(&mut self) {
241+
unsafe { ffi::ada_free_search_params_values_iter(self.iterator) }
242+
}
243+
}
174244

175-
for index in 0..size {
176-
let string = ffi::ada_strings_get(strings, index);
245+
impl<'a> URLSearchParamsValuesIterator<'a> {
246+
fn new(
247+
iterator: *mut ffi::ada_url_search_params_values_iter,
248+
) -> URLSearchParamsValuesIterator<'a> {
249+
URLSearchParamsValuesIterator {
250+
iterator,
251+
_phantom: core::marker::PhantomData,
252+
}
253+
}
254+
}
255+
256+
impl<'a> URLSearchParamsValuesIterator<'a> {
257+
/// Returns true if iterator has a next value.
258+
pub fn has_next(&self) -> bool {
259+
unsafe { ffi::ada_search_params_values_iter_has_next(self.iterator) }
260+
}
261+
262+
/// Returns a new value if it's available
263+
pub fn get_next(&self) -> Option<&str> {
264+
if self.has_next() {
265+
return None;
266+
}
267+
let string = unsafe { ffi::ada_search_params_values_iter_next(self.iterator) };
268+
Some(string.as_str())
269+
}
270+
}
271+
272+
pub struct URLSearchParamsEntry<'a> {
273+
strings: *mut ffi::ada_strings,
274+
size: usize,
275+
_phantom: core::marker::PhantomData<&'a str>,
276+
}
277+
278+
impl<'a> URLSearchParamsEntry<'a> {
279+
fn new(strings: *mut ffi::ada_strings, size: usize) -> URLSearchParamsEntry<'a> {
280+
URLSearchParamsEntry {
281+
strings,
282+
size,
283+
_phantom: core::marker::PhantomData,
284+
}
285+
}
286+
287+
/// Returns whether the key value pair is empty or not
288+
///
289+
/// ```
290+
/// use ada_url::URLSearchParams;
291+
/// let params = URLSearchParams::parse("a=1&b=2");
292+
/// let pairs = params.get_all("a");
293+
/// assert_eq!(pairs.is_empty(), false);
294+
/// ```
295+
pub fn is_empty(&self) -> bool {
296+
self.size == 0
297+
}
298+
299+
/// Returns the size of the key value pairs
300+
///
301+
/// ```
302+
/// use ada_url::URLSearchParams;
303+
/// let params = URLSearchParams::parse("a=1&b=2");
304+
/// let pairs = params.get_all("a");
305+
/// assert_eq!(pairs.get_size(), 1);
306+
/// ```
307+
pub fn get_size(&self) -> usize {
308+
self.size
309+
}
310+
311+
/// Get an entry by index
312+
///
313+
/// ```
314+
/// use ada_url::URLSearchParams;
315+
/// let params = URLSearchParams::parse("a=1&a=2");
316+
/// let pairs = params.get_all("a");
317+
/// assert_eq!(pairs.get_size(), 2);
318+
/// assert_eq!(pairs.get(0), Some("1"));
319+
/// assert_eq!(pairs.get(1), Some("2"));
320+
/// assert_eq!(pairs.get(2), None);
321+
/// assert_eq!(pairs.get(55), None);
322+
/// ```
323+
pub fn get(&self, index: usize) -> Option<&str> {
324+
if self.size == 0 || index > self.size - 1 {
325+
return None;
326+
}
327+
328+
unsafe {
329+
let string = ffi::ada_strings_get(self.strings, index);
330+
let slice = core::slice::from_raw_parts(string.data.cast(), string.length);
331+
Some(core::str::from_utf8_unchecked(slice))
332+
}
333+
}
334+
}
335+
336+
impl<'a> Drop for URLSearchParamsEntry<'a> {
337+
/// Automatically frees the underlying C pointer.
338+
fn drop(&mut self) {
339+
unsafe { ffi::ada_free_strings(self.strings) }
340+
}
341+
}
342+
343+
#[cfg(feature = "std")]
344+
impl<'a> From<URLSearchParamsEntry<'a>> for Vec<&'a str> {
345+
fn from(val: URLSearchParamsEntry<'a>) -> Self {
346+
let mut vec = Vec::with_capacity(val.size);
347+
unsafe {
348+
for index in 0..val.size {
349+
let string = ffi::ada_strings_get(val.strings, index);
177350
let slice = core::slice::from_raw_parts(string.data.cast(), string.length);
178-
out.push(core::str::from_utf8_unchecked(slice));
351+
vec.push(core::str::from_utf8_unchecked(slice));
179352
}
180-
181-
out
182353
}
354+
vec
183355
}
184356
}

0 commit comments

Comments
 (0)