From 833d2cdfae9cfc3556919916a0fe69dd2e3961d5 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sat, 25 Nov 2023 10:14:59 -0500 Subject: [PATCH 01/13] feat: add URLSearchParams implementation --- src/ffi.rs | 133 ++++++++++++++++++++++++++++ src/lib.rs | 2 + src/url_search_params.rs | 184 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 319 insertions(+) create mode 100644 src/url_search_params.rs diff --git a/src/ffi.rs b/src/ffi.rs index a7bab7d..911d59d 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -13,6 +13,12 @@ pub struct ada_url { _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, } +#[repr(C)] +pub struct ada_url_search_params { + _unused: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + #[repr(C)] pub struct ada_string { pub data: *const c_char, @@ -62,6 +68,37 @@ impl Drop for ada_owned_string { ada_free_owned_string(copy); }; } + +/// Represents an std::vector +#[repr(C)] +pub struct ada_strings { + _unused: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +#[repr(C)] +pub struct ada_url_search_params_keys_iter { + _unused: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +#[repr(C)] +pub struct ada_url_search_params_values_iter { + _unused: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +#[repr(C)] +pub struct ada_url_search_params_entries_iter { + _unused: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +/// Represents a key/value pair of strings +#[repr(C)] +pub struct ada_string_pair { + pub key: ada_string, + pub value: ada_string, } #[repr(C)] @@ -143,6 +180,102 @@ extern "C" { // IDNA methods pub fn ada_idna_to_unicode(input: *const c_char, length: usize) -> ada_owned_string; pub fn ada_idna_to_ascii(input: *const c_char, length: usize) -> ada_owned_string; + + // URLSearchParams + pub fn ada_parse_search_params( + input: *const c_char, + length: usize, + ) -> *mut ada_url_search_params; + pub fn ada_free_search_params(search_params: *mut ada_url_search_params); + pub fn ada_search_params_size(search_params: *mut ada_url_search_params) -> usize; + pub fn ada_search_params_sort(search_params: *mut ada_url_search_params); + pub fn ada_search_params_to_string( + search_params: *mut ada_url_search_params, + ) -> ada_owned_string; + pub fn ada_search_params_append( + search_params: *mut ada_url_search_params, + name: *const c_char, + name_length: usize, + value: *const c_char, + value_length: usize, + ); + pub fn ada_search_params_set( + search_params: *mut ada_url_search_params, + name: *const c_char, + name_length: usize, + value: *const c_char, + value_length: usize, + ); + pub fn ada_search_params_remove( + search_params: *mut ada_url_search_params, + name: *const c_char, + name_length: usize, + ); + pub fn ada_search_params_remove_value( + search_params: *mut ada_url_search_params, + name: *const c_char, + name_length: usize, + value: *const c_char, + value_length: usize, + ); + pub fn ada_search_params_has( + search_params: *mut ada_url_search_params, + name: *const c_char, + name_length: usize, + ) -> bool; + pub fn ada_search_params_has_value( + search_params: *mut ada_url_search_params, + name: *const c_char, + name_length: usize, + value: *const c_char, + value_length: usize, + ) -> bool; + pub fn ada_search_params_get( + search_params: *mut ada_url_search_params, + key: *const c_char, + key_length: usize, + ) -> ada_string; + pub fn ada_search_params_get_all( + // not implemented + search_params: *mut ada_url_search_params, + key: *const c_char, + key_length: usize, + ) -> *mut ada_strings; + pub fn ada_search_params_get_keys( + search_params: *mut ada_url_search_params, + ) -> *mut ada_url_search_params_keys_iter; + pub fn ada_search_params_get_values( + search_params: *mut ada_url_search_params, + ) -> *mut ada_url_search_params_values_iter; + pub fn ada_search_params_get_entries( + search_params: *mut ada_url_search_params, + ) -> *mut ada_url_search_params_entries_iter; + + pub fn ada_free_strings(strings: *mut ada_strings); + pub fn ada_strings_size(strings: *mut ada_strings) -> usize; + pub fn ada_strings_get(strings: *mut ada_strings, index: usize) -> ada_string; + pub fn ada_free_search_params_keys_iter(iter: *mut ada_url_search_params_keys_iter); + pub fn ada_search_params_keys_iter_next( + iter: *mut ada_url_search_params_keys_iter, + ) -> *mut ada_string; + pub fn ada_search_params_keys_iter_has_next(iter: *mut ada_url_search_params_keys_iter) + -> bool; + + pub fn ada_free_search_params_values_iter(iter: *mut ada_url_search_params_values_iter); + pub fn ada_search_params_values_iter_next( + iter: *mut ada_url_search_params_values_iter, + ) -> *mut ada_string; + pub fn ada_search_params_values_iter_has_next( + iter: *mut ada_url_search_params_values_iter, + ) -> bool; + + pub fn ada_free_search_params_entries_iter(iter: *mut ada_url_search_params_entries_iter); + pub fn ada_search_params_entries_iter_next( + iter: *mut ada_url_search_params_entries_iter, + ) -> *mut ada_string_pair; + pub fn ada_search_params_entries_iter_has_next( + iter: *mut ada_url_search_params_entries_iter, + ) -> bool; } #[cfg(test)] diff --git a/src/lib.rs b/src/lib.rs index d944c5f..b365a50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,9 @@ pub mod ffi; mod idna; +mod url_search_params; pub use idna::Idna; +pub use url_search_params::URLSearchParams; #[cfg(feature = "std")] extern crate std; diff --git a/src/url_search_params.rs b/src/url_search_params.rs new file mode 100644 index 0000000..c5bca2d --- /dev/null +++ b/src/url_search_params.rs @@ -0,0 +1,184 @@ +use crate::ffi; + +pub struct URLSearchParams(*mut ffi::ada_url_search_params); + +impl Drop for URLSearchParams { + fn drop(&mut self) { + unsafe { ffi::ada_free_search_params(self.0) } + } +} + +impl URLSearchParams { + /// Parses an return a URLSearchParams struct. + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1&b=2"); + /// assert_eq!(params.get("a"), Some("1")); + /// assert_eq!(params.get("b"), Some("2")); + /// ``` + pub fn parse(input: &str) -> Self { + Self(unsafe { ffi::ada_parse_search_params(input.as_ptr().cast(), input.len()) }) + } + + /// Returns the size of the URLSearchParams struct. + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1&b=2"); + /// assert_eq!(params.size(), 2); + /// ``` + pub fn size(&self) -> usize { + unsafe { ffi::ada_search_params_size(self.0) } + } + + /// Sorts the keys of the URLSearchParams struct. + pub fn sort(&self) { + unsafe { ffi::ada_search_params_sort(self.0) } + } + + /// Appends a key/value to the URLSearchParams struct. + pub fn append(&self, key: &str, value: &str) { + unsafe { + ffi::ada_search_params_append( + self.0, + key.as_ptr().cast(), + key.len(), + value.as_ptr().cast(), + value.len(), + ) + } + } + + /// Removes all keys pre-existing keys from the URLSearchParams struct + /// and appends the new key/value. + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1&b=2"); + /// params.set("a", "3"); + /// assert_eq!(params.get("a"), Some("3")); + /// ``` + pub fn set(&self, key: &str, value: &str) { + unsafe { + ffi::ada_search_params_set( + self.0, + key.as_ptr().cast(), + key.len(), + value.as_ptr().cast(), + value.len(), + ) + } + } + + /// Removes a key/value from the URLSearchParams struct. + /// Depending on the value parameter, it will either remove + /// the key/value pair or just the key. + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1&b=2"); + /// params.remove("a", Some("1")); + /// assert_eq!(params.get("a"), None); + /// ``` + pub fn remove(&self, key: &str, value: Option<&str>) { + if let Some(value) = value { + unsafe { + ffi::ada_search_params_remove_value( + self.0, + key.as_ptr().cast(), + key.len(), + value.as_ptr().cast(), + value.len(), + ) + } + } else { + unsafe { ffi::ada_search_params_remove(self.0, key.as_ptr().cast(), key.len()) } + } + } + + /// Retruns true if the URLSearchParams struct contains the key. + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1&b=2"); + /// assert_eq!(params.has("a", None), true); + /// ``` + pub fn has(&self, key: &str, value: Option<&str>) -> bool { + if let Some(value) = value { + unsafe { + ffi::ada_search_params_has_value( + self.0, + key.as_ptr().cast(), + key.len(), + value.as_ptr().cast(), + value.len(), + ) + } + } else { + unsafe { ffi::ada_search_params_has(self.0, key.as_ptr().cast(), key.len()) } + } + } + + /// Returns the value of the key. + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1&b=2"); + /// assert_eq!(params.get("a"), Some("1")); + /// assert_eq!(params.get("c"), None); + /// ``` + pub fn get(&self, key: &str) -> Option<&str> { + unsafe { + let out = ffi::ada_search_params_get(self.0, key.as_ptr().cast(), key.len()); + + if out.data.is_null() { + return None; + } + let slice = core::slice::from_raw_parts(out.data.cast(), out.length); + Some(core::str::from_utf8_unchecked(slice)) + } + } + + /// Returns the stringified version of the URLSearchParams struct. + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1&b=2"); + /// assert_eq!(params.to_string(), "a=1&b=2"); + /// ``` + pub fn to_string(&self) -> &str { + unsafe { + let out = ffi::ada_search_params_to_string(self.0); + let slice = core::slice::from_raw_parts(out.data.cast(), out.length); + core::str::from_utf8_unchecked(slice) + } + } + + /// Returns all values of the key. + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1&a=2"); + /// assert_eq!(params.get_all("a"), vec!["1", "2"]); + /// ``` + pub fn get_all(&self, key: &str) -> Vec<&str> { + unsafe { + let strings = ffi::ada_search_params_get_all(self.0, key.as_ptr().cast(), key.len()); + let size = ffi::ada_strings_size(strings); + let mut out = Vec::with_capacity(size); + + if size == 0 { + return out; + } + + for index in 0..size { + let string = ffi::ada_strings_get(strings, index); + let slice = core::slice::from_raw_parts(string.data.cast(), string.length); + out.push(core::str::from_utf8_unchecked(slice)); + } + + out + } + } +} From ac2efd06680c590b1a37b09036ecfb17a4a0e4fe Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 1 Dec 2024 11:47:48 -0500 Subject: [PATCH 02/13] add iterator functions --- src/ffi.rs | 5 +- src/url_search_params.rs | 206 +++++++++++++++++++++++++++++++++++---- 2 files changed, 192 insertions(+), 19 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 911d59d..1ed2f73 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -68,6 +68,7 @@ impl Drop for ada_owned_string { ada_free_owned_string(copy); }; } +} /// Represents an std::vector #[repr(C)] @@ -257,14 +258,14 @@ extern "C" { pub fn ada_free_search_params_keys_iter(iter: *mut ada_url_search_params_keys_iter); pub fn ada_search_params_keys_iter_next( iter: *mut ada_url_search_params_keys_iter, - ) -> *mut ada_string; + ) -> ada_string; pub fn ada_search_params_keys_iter_has_next(iter: *mut ada_url_search_params_keys_iter) -> bool; pub fn ada_free_search_params_values_iter(iter: *mut ada_url_search_params_values_iter); pub fn ada_search_params_values_iter_next( iter: *mut ada_url_search_params_values_iter, - ) -> *mut ada_string; + ) -> ada_string; pub fn ada_search_params_values_iter_has_next( iter: *mut ada_url_search_params_values_iter, ) -> bool; diff --git a/src/url_search_params.rs b/src/url_search_params.rs index c5bca2d..7dfb9c2 100644 --- a/src/url_search_params.rs +++ b/src/url_search_params.rs @@ -147,12 +147,10 @@ impl URLSearchParams { /// let params = URLSearchParams::parse("a=1&b=2"); /// assert_eq!(params.to_string(), "a=1&b=2"); /// ``` - pub fn to_string(&self) -> &str { - unsafe { - let out = ffi::ada_search_params_to_string(self.0); - let slice = core::slice::from_raw_parts(out.data.cast(), out.length); - core::str::from_utf8_unchecked(slice) - } + #[cfg(feature = "std")] + #[allow(clippy::inherent_to_string)] + pub fn to_string(&self) -> String { + unsafe { ffi::ada_search_params_to_string(self.0).to_string() } } /// Returns all values of the key. @@ -160,25 +158,199 @@ impl URLSearchParams { /// ``` /// use ada_url::URLSearchParams; /// let params = URLSearchParams::parse("a=1&a=2"); - /// assert_eq!(params.get_all("a"), vec!["1", "2"]); + /// let pairs = params.get_all("a"); + /// assert_eq!(pairs.get_size(), 2); /// ``` - pub fn get_all(&self, key: &str) -> Vec<&str> { + pub fn get_all(&self, key: &str) -> URLSearchParamsEntry { unsafe { let strings = ffi::ada_search_params_get_all(self.0, key.as_ptr().cast(), key.len()); let size = ffi::ada_strings_size(strings); - let mut out = Vec::with_capacity(size); - if size == 0 { - return out; - } + URLSearchParamsEntry::new(strings, size) + } + } + + /// Returns all keys as an iterator + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1"); + /// let mut keys = params.get_keys(); + /// assert!(keys.has_next()); + pub fn get_keys(&self) -> URLSearchParamsKeysIterator { + let iterator = unsafe { ffi::ada_search_params_get_keys(self.0) }; + URLSearchParamsKeysIterator::new(iterator) + } + + /// Returns all keys as an iterator + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1"); + /// let mut values = params.get_values(); + /// assert!(values.has_next()); + pub fn get_values(&self) -> URLSearchParamsValuesIterator { + let iterator = unsafe { ffi::ada_search_params_get_values(self.0) }; + URLSearchParamsValuesIterator::new(iterator) + } +} + +pub struct URLSearchParamsKeysIterator<'a> { + iterator: *mut ffi::ada_url_search_params_keys_iter, + _phantom: core::marker::PhantomData<&'a str>, +} + +impl<'a> Drop for URLSearchParamsKeysIterator<'a> { + fn drop(&mut self) { + unsafe { ffi::ada_free_search_params_keys_iter(self.iterator) } + } +} + +impl<'a> URLSearchParamsKeysIterator<'a> { + /// Returns true if iterator has a next value. + pub fn has_next(&self) -> bool { + unsafe { ffi::ada_search_params_keys_iter_has_next(self.iterator) } + } + + /// Returns a new value if it's available + pub fn get_next(&self) -> Option<&str> { + if self.has_next() { + return None; + } + let string = unsafe { ffi::ada_search_params_keys_iter_next(self.iterator) }; + Some(string.as_str()) + } +} + +pub struct URLSearchParamsValuesIterator<'a> { + iterator: *mut ffi::ada_url_search_params_values_iter, + _phantom: core::marker::PhantomData<&'a str>, +} + +impl<'a> URLSearchParamsKeysIterator<'a> { + fn new(iterator: *mut ffi::ada_url_search_params_keys_iter) -> URLSearchParamsKeysIterator<'a> { + URLSearchParamsKeysIterator { + iterator, + _phantom: core::marker::PhantomData, + } + } +} + +impl<'a> Drop for URLSearchParamsValuesIterator<'a> { + fn drop(&mut self) { + unsafe { ffi::ada_free_search_params_values_iter(self.iterator) } + } +} - for index in 0..size { - let string = ffi::ada_strings_get(strings, index); +impl<'a> URLSearchParamsValuesIterator<'a> { + fn new( + iterator: *mut ffi::ada_url_search_params_values_iter, + ) -> URLSearchParamsValuesIterator<'a> { + URLSearchParamsValuesIterator { + iterator, + _phantom: core::marker::PhantomData, + } + } +} + +impl<'a> URLSearchParamsValuesIterator<'a> { + /// Returns true if iterator has a next value. + pub fn has_next(&self) -> bool { + unsafe { ffi::ada_search_params_values_iter_has_next(self.iterator) } + } + + /// Returns a new value if it's available + pub fn get_next(&self) -> Option<&str> { + if self.has_next() { + return None; + } + let string = unsafe { ffi::ada_search_params_values_iter_next(self.iterator) }; + Some(string.as_str()) + } +} + +pub struct URLSearchParamsEntry<'a> { + strings: *mut ffi::ada_strings, + size: usize, + _phantom: core::marker::PhantomData<&'a str>, +} + +impl<'a> URLSearchParamsEntry<'a> { + fn new(strings: *mut ffi::ada_strings, size: usize) -> URLSearchParamsEntry<'a> { + URLSearchParamsEntry { + strings, + size, + _phantom: core::marker::PhantomData, + } + } + + /// Returns whether the key value pair is empty or not + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1&b=2"); + /// let pairs = params.get_all("a"); + /// assert_eq!(pairs.is_empty(), false); + /// ``` + pub fn is_empty(&self) -> bool { + self.size == 0 + } + + /// Returns the size of the key value pairs + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1&b=2"); + /// let pairs = params.get_all("a"); + /// assert_eq!(pairs.get_size(), 1); + /// ``` + pub fn get_size(&self) -> usize { + self.size + } + + /// Get an entry by index + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1&a=2"); + /// let pairs = params.get_all("a"); + /// assert_eq!(pairs.get_size(), 2); + /// assert_eq!(pairs.get(0), Some("1")); + /// assert_eq!(pairs.get(1), Some("2")); + /// assert_eq!(pairs.get(2), None); + /// assert_eq!(pairs.get(55), None); + /// ``` + pub fn get(&self, index: usize) -> Option<&str> { + if self.size == 0 || index > self.size - 1 { + return None; + } + + unsafe { + let string = ffi::ada_strings_get(self.strings, index); + let slice = core::slice::from_raw_parts(string.data.cast(), string.length); + Some(core::str::from_utf8_unchecked(slice)) + } + } +} + +impl<'a> Drop for URLSearchParamsEntry<'a> { + /// Automatically frees the underlying C pointer. + fn drop(&mut self) { + unsafe { ffi::ada_free_strings(self.strings) } + } +} + +#[cfg(feature = "std")] +impl<'a> From> for Vec<&'a str> { + fn from(val: URLSearchParamsEntry<'a>) -> Self { + let mut vec = Vec::with_capacity(val.size); + unsafe { + for index in 0..val.size { + let string = ffi::ada_strings_get(val.strings, index); let slice = core::slice::from_raw_parts(string.data.cast(), string.length); - out.push(core::str::from_utf8_unchecked(slice)); + vec.push(core::str::from_utf8_unchecked(slice)); } - - out } + vec } } From 7652e3375e494e2926153c560d9a77b6862ea929 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 1 Dec 2024 11:56:14 -0500 Subject: [PATCH 03/13] fix clippy warnings --- src/url_search_params.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/url_search_params.rs b/src/url_search_params.rs index 7dfb9c2..d43e60a 100644 --- a/src/url_search_params.rs +++ b/src/url_search_params.rs @@ -135,8 +135,7 @@ impl URLSearchParams { if out.data.is_null() { return None; } - let slice = core::slice::from_raw_parts(out.data.cast(), out.length); - Some(core::str::from_utf8_unchecked(slice)) + Some(out.as_str()) } } @@ -165,7 +164,6 @@ impl URLSearchParams { unsafe { let strings = ffi::ada_search_params_get_all(self.0, key.as_ptr().cast(), key.len()); let size = ffi::ada_strings_size(strings); - URLSearchParamsEntry::new(strings, size) } } @@ -200,13 +198,13 @@ pub struct URLSearchParamsKeysIterator<'a> { _phantom: core::marker::PhantomData<&'a str>, } -impl<'a> Drop for URLSearchParamsKeysIterator<'a> { +impl Drop for URLSearchParamsKeysIterator<'_> { fn drop(&mut self) { unsafe { ffi::ada_free_search_params_keys_iter(self.iterator) } } } -impl<'a> URLSearchParamsKeysIterator<'a> { +impl URLSearchParamsKeysIterator<'_> { /// Returns true if iterator has a next value. pub fn has_next(&self) -> bool { unsafe { ffi::ada_search_params_keys_iter_has_next(self.iterator) } @@ -236,7 +234,7 @@ impl<'a> URLSearchParamsKeysIterator<'a> { } } -impl<'a> Drop for URLSearchParamsValuesIterator<'a> { +impl Drop for URLSearchParamsValuesIterator<'_> { fn drop(&mut self) { unsafe { ffi::ada_free_search_params_values_iter(self.iterator) } } @@ -253,7 +251,7 @@ impl<'a> URLSearchParamsValuesIterator<'a> { } } -impl<'a> URLSearchParamsValuesIterator<'a> { +impl URLSearchParamsValuesIterator<'_> { /// Returns true if iterator has a next value. pub fn has_next(&self) -> bool { unsafe { ffi::ada_search_params_values_iter_has_next(self.iterator) } @@ -327,14 +325,12 @@ impl<'a> URLSearchParamsEntry<'a> { unsafe { let string = ffi::ada_strings_get(self.strings, index); - let slice = core::slice::from_raw_parts(string.data.cast(), string.length); - Some(core::str::from_utf8_unchecked(slice)) + Some(string.as_str()) } } } -impl<'a> Drop for URLSearchParamsEntry<'a> { - /// Automatically frees the underlying C pointer. +impl Drop for URLSearchParamsEntry<'_> { fn drop(&mut self) { unsafe { ffi::ada_free_strings(self.strings) } } From 0cb9dd27c0bf9e832c9a8f382bd7a98b8ab22f81 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 1 Dec 2024 12:00:03 -0500 Subject: [PATCH 04/13] expose more structs --- src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index b365a50..7077850 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,10 @@ pub mod ffi; mod idna; mod url_search_params; pub use idna::Idna; -pub use url_search_params::URLSearchParams; +pub use url_search_params::{ + URLSearchParams, URLSearchParamsEntry, URLSearchParamsKeysIterator, + URLSearchParamsValuesIterator, +}; #[cfg(feature = "std")] extern crate std; From 9b46978a4937bf458c88f3f4be3910b9f9d3c145 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 1 Dec 2024 14:25:17 -0500 Subject: [PATCH 05/13] change several apis --- src/url_search_params.rs | 49 ++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/url_search_params.rs b/src/url_search_params.rs index d43e60a..b0e6614 100644 --- a/src/url_search_params.rs +++ b/src/url_search_params.rs @@ -26,19 +26,24 @@ impl URLSearchParams { /// ``` /// use ada_url::URLSearchParams; /// let params = URLSearchParams::parse("a=1&b=2"); - /// assert_eq!(params.size(), 2); + /// assert_eq!(params.len(), 2); /// ``` - pub fn size(&self) -> usize { + pub fn len(&self) -> usize { unsafe { ffi::ada_search_params_size(self.0) } } + /// Returns true if no entries exist in the URLSearchParams. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + /// Sorts the keys of the URLSearchParams struct. - pub fn sort(&self) { + pub fn sort(&mut self) { unsafe { ffi::ada_search_params_sort(self.0) } } /// Appends a key/value to the URLSearchParams struct. - pub fn append(&self, key: &str, value: &str) { + pub fn append(&mut self, key: &str, value: &str) { unsafe { ffi::ada_search_params_append( self.0, @@ -50,16 +55,16 @@ impl URLSearchParams { } } - /// Removes all keys pre-existing keys from the URLSearchParams struct + /// Removes all pre-existing keys from the URLSearchParams struct /// and appends the new key/value. /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2"); + /// let mut params = URLSearchParams::parse("a=1&b=2"); /// params.set("a", "3"); /// assert_eq!(params.get("a"), Some("3")); /// ``` - pub fn set(&self, key: &str, value: &str) { + pub fn set(&mut self, key: &str, value: &str) { unsafe { ffi::ada_search_params_set( self.0, @@ -77,11 +82,11 @@ impl URLSearchParams { /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2"); + /// let mut params = URLSearchParams::parse("a=1&b=2"); /// params.remove("a", Some("1")); /// assert_eq!(params.get("a"), None); /// ``` - pub fn remove(&self, key: &str, value: Option<&str>) { + pub fn remove(&mut self, key: &str, value: Option<&str>) { if let Some(value) = value { unsafe { ffi::ada_search_params_remove_value( @@ -97,14 +102,14 @@ impl URLSearchParams { } } - /// Retruns true if the URLSearchParams struct contains the key. + /// Returns whether the [`URLSearchParams`] contains the `key`. /// /// ``` /// use ada_url::URLSearchParams; /// let params = URLSearchParams::parse("a=1&b=2"); - /// assert_eq!(params.has("a", None), true); + /// assert_eq!(params.contains("a", None), true); /// ``` - pub fn has(&self, key: &str, value: Option<&str>) -> bool { + pub fn contains(&self, key: &str, value: Option<&str>) -> bool { if let Some(value) = value { unsafe { ffi::ada_search_params_has_value( @@ -158,7 +163,7 @@ impl URLSearchParams { /// use ada_url::URLSearchParams; /// let params = URLSearchParams::parse("a=1&a=2"); /// let pairs = params.get_all("a"); - /// assert_eq!(pairs.get_size(), 2); + /// assert_eq!(pairs.len(), 2); /// ``` pub fn get_all(&self, key: &str) -> URLSearchParamsEntry { unsafe { @@ -173,9 +178,9 @@ impl URLSearchParams { /// ``` /// use ada_url::URLSearchParams; /// let params = URLSearchParams::parse("a=1"); - /// let mut keys = params.get_keys(); + /// let mut keys = params.keys(); /// assert!(keys.has_next()); - pub fn get_keys(&self) -> URLSearchParamsKeysIterator { + pub fn keys(&self) -> URLSearchParamsKeysIterator { let iterator = unsafe { ffi::ada_search_params_get_keys(self.0) }; URLSearchParamsKeysIterator::new(iterator) } @@ -185,9 +190,9 @@ impl URLSearchParams { /// ``` /// use ada_url::URLSearchParams; /// let params = URLSearchParams::parse("a=1"); - /// let mut values = params.get_values(); + /// let mut values = params.values(); /// assert!(values.has_next()); - pub fn get_values(&self) -> URLSearchParamsValuesIterator { + pub fn values(&self) -> URLSearchParamsValuesIterator { let iterator = unsafe { ffi::ada_search_params_get_values(self.0) }; URLSearchParamsValuesIterator::new(iterator) } @@ -211,7 +216,7 @@ impl URLSearchParamsKeysIterator<'_> { } /// Returns a new value if it's available - pub fn get_next(&self) -> Option<&str> { + pub fn get_next(&mut self) -> Option<&str> { if self.has_next() { return None; } @@ -258,7 +263,7 @@ impl URLSearchParamsValuesIterator<'_> { } /// Returns a new value if it's available - pub fn get_next(&self) -> Option<&str> { + pub fn get_next(&mut self) -> Option<&str> { if self.has_next() { return None; } @@ -300,9 +305,9 @@ impl<'a> URLSearchParamsEntry<'a> { /// use ada_url::URLSearchParams; /// let params = URLSearchParams::parse("a=1&b=2"); /// let pairs = params.get_all("a"); - /// assert_eq!(pairs.get_size(), 1); + /// assert_eq!(pairs.len(), 1); /// ``` - pub fn get_size(&self) -> usize { + pub fn len(&self) -> usize { self.size } @@ -312,7 +317,7 @@ impl<'a> URLSearchParamsEntry<'a> { /// use ada_url::URLSearchParams; /// let params = URLSearchParams::parse("a=1&a=2"); /// let pairs = params.get_all("a"); - /// assert_eq!(pairs.get_size(), 2); + /// assert_eq!(pairs.len(), 2); /// assert_eq!(pairs.get(0), Some("1")); /// assert_eq!(pairs.get(1), Some("2")); /// assert_eq!(pairs.get(2), None); From bced8d00ae01b1a123025b1c679f92c58893707a Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 1 Dec 2024 17:34:35 -0500 Subject: [PATCH 06/13] update parse method and apply recommendations --- src/url_search_params.rs | 85 +++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/src/url_search_params.rs b/src/url_search_params.rs index b0e6614..d8c8bd2 100644 --- a/src/url_search_params.rs +++ b/src/url_search_params.rs @@ -1,4 +1,4 @@ -use crate::ffi; +use crate::{ffi, ParseUrlError}; pub struct URLSearchParams(*mut ffi::ada_url_search_params); @@ -13,19 +13,26 @@ impl URLSearchParams { /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2"); + /// let params = URLSearchParams::parse("a=1&b=2") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// assert_eq!(params.get("a"), Some("1")); /// assert_eq!(params.get("b"), Some("2")); /// ``` - pub fn parse(input: &str) -> Self { - Self(unsafe { ffi::ada_parse_search_params(input.as_ptr().cast(), input.len()) }) + pub fn parse(input: Input) -> Result> + where + Input: AsRef, + { + Ok(Self(unsafe { + ffi::ada_parse_search_params(input.as_ref().as_ptr().cast(), input.as_ref().len()) + })) } /// Returns the size of the URLSearchParams struct. /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2"); + /// let params = URLSearchParams::parse("a=1&b=2") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// assert_eq!(params.len(), 2); /// ``` pub fn len(&self) -> usize { @@ -60,7 +67,8 @@ impl URLSearchParams { /// /// ``` /// use ada_url::URLSearchParams; - /// let mut params = URLSearchParams::parse("a=1&b=2"); + /// let mut params = URLSearchParams::parse("a=1&b=2") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// params.set("a", "3"); /// assert_eq!(params.get("a"), Some("3")); /// ``` @@ -82,7 +90,8 @@ impl URLSearchParams { /// /// ``` /// use ada_url::URLSearchParams; - /// let mut params = URLSearchParams::parse("a=1&b=2"); + /// let mut params = URLSearchParams::parse("a=1&b=2") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// params.remove("a", Some("1")); /// assert_eq!(params.get("a"), None); /// ``` @@ -106,7 +115,8 @@ impl URLSearchParams { /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2"); + /// let params = URLSearchParams::parse("a=1&b=2") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// assert_eq!(params.contains("a", None), true); /// ``` pub fn contains(&self, key: &str, value: Option<&str>) -> bool { @@ -129,7 +139,8 @@ impl URLSearchParams { /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2"); + /// let params = URLSearchParams::parse("a=1&b=2") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// assert_eq!(params.get("a"), Some("1")); /// assert_eq!(params.get("c"), None); /// ``` @@ -144,24 +155,12 @@ impl URLSearchParams { } } - /// Returns the stringified version of the URLSearchParams struct. - /// - /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2"); - /// assert_eq!(params.to_string(), "a=1&b=2"); - /// ``` - #[cfg(feature = "std")] - #[allow(clippy::inherent_to_string)] - pub fn to_string(&self) -> String { - unsafe { ffi::ada_search_params_to_string(self.0).to_string() } - } - /// Returns all values of the key. /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&a=2"); + /// let params = URLSearchParams::parse("a=1&a=2") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.len(), 2); /// ``` @@ -177,7 +176,8 @@ impl URLSearchParams { /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1"); + /// let params = URLSearchParams::parse("a=1") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// let mut keys = params.keys(); /// assert!(keys.has_next()); pub fn keys(&self) -> URLSearchParamsKeysIterator { @@ -189,7 +189,8 @@ impl URLSearchParams { /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1"); + /// let params = URLSearchParams::parse("a=1") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// let mut values = params.values(); /// assert!(values.has_next()); pub fn values(&self) -> URLSearchParamsValuesIterator { @@ -198,6 +199,31 @@ impl URLSearchParams { } } +#[cfg(feature = "std")] +impl core::str::FromStr for URLSearchParams { + type Err = ParseUrlError>; + + fn from_str(s: &str) -> Result { + Self::parse(s).map_err(|ParseUrlError { input }| ParseUrlError { + input: input.into(), + }) + } +} + +/// Returns the stringified version of the URLSearchParams struct. +/// +/// ``` +/// use ada_url::URLSearchParams; +/// let params = URLSearchParams::parse("a=1&b=2") +/// .expect("This is a valid URLSearchParams. Should have parsed it."); +/// assert_eq!(params.to_string(), "a=1&b=2"); +/// ``` +impl core::fmt::Display for URLSearchParams { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(unsafe { ffi::ada_search_params_to_string(self.0).as_ref() }) + } +} + pub struct URLSearchParamsKeysIterator<'a> { iterator: *mut ffi::ada_url_search_params_keys_iter, _phantom: core::marker::PhantomData<&'a str>, @@ -291,7 +317,8 @@ impl<'a> URLSearchParamsEntry<'a> { /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2"); + /// let params = URLSearchParams::parse("a=1&b=2") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.is_empty(), false); /// ``` @@ -303,7 +330,8 @@ impl<'a> URLSearchParamsEntry<'a> { /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2"); + /// let params = URLSearchParams::parse("a=1&b=2") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.len(), 1); /// ``` @@ -315,7 +343,8 @@ impl<'a> URLSearchParamsEntry<'a> { /// /// ``` /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&a=2"); + /// let params = URLSearchParams::parse("a=1&a=2") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.len(), 2); /// assert_eq!(pairs.get(0), Some("1")); From cabde6da8c7a9ec372f76df6cc8de4b65857ad40 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 1 Dec 2024 18:25:37 -0500 Subject: [PATCH 07/13] add extend trait to urlsearchparams --- src/url_search_params.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/url_search_params.rs b/src/url_search_params.rs index d8c8bd2..098ece2 100644 --- a/src/url_search_params.rs +++ b/src/url_search_params.rs @@ -224,6 +224,28 @@ impl core::fmt::Display for URLSearchParams { } } +#[cfg(feature = "std")] +impl Extend<(Input, Input)> for URLSearchParams +where + Input: AsRef, +{ + /// Supports extending URLSearchParams through an iterator. + /// + ///``` + /// use ada_url::URLSearchParams; + /// let mut params = URLSearchParams::parse("a=1&b=2") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// assert_eq!(params.len(), 2); + /// params.extend([("foo", "bar")]); + /// assert_eq!(params.len(), 3); + /// ``` + fn extend>(&mut self, iter: T) { + for item in iter { + self.append(item.0.as_ref(), item.1.as_ref()); + } + } +} + pub struct URLSearchParamsKeysIterator<'a> { iterator: *mut ffi::ada_url_search_params_keys_iter, _phantom: core::marker::PhantomData<&'a str>, From f5cc3eb1cff6b003565a5f2c6cf4bb3f49238755 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 1 Dec 2024 18:30:11 -0500 Subject: [PATCH 08/13] add `FromIterator` trait --- src/url_search_params.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/url_search_params.rs b/src/url_search_params.rs index 098ece2..e6a7c76 100644 --- a/src/url_search_params.rs +++ b/src/url_search_params.rs @@ -246,6 +246,29 @@ where } } +#[cfg(feature = "std")] +impl FromIterator<(Input, Input)> for URLSearchParams +where + Input: AsRef, +{ + /// Converts an iterator to URLSearchParams + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let iterator = std::iter::repeat(("hello", "world")).take(5); + /// let params = URLSearchParams::from_iter(iterator); + /// assert_eq!(params.len(), 5); + /// ``` + fn from_iter>(iter: T) -> Self { + let mut params = URLSearchParams::parse("") + .expect("Failed to parse empty string. This is likely due to a bug"); + for item in iter { + params.append(item.0.as_ref(), item.1.as_ref()); + } + params + } +} + pub struct URLSearchParamsKeysIterator<'a> { iterator: *mut ffi::ada_url_search_params_keys_iter, _phantom: core::marker::PhantomData<&'a str>, From 2ab1c7fb9fcb4cb2d255070be2af3e29b4fc0be1 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 1 Dec 2024 18:34:05 -0500 Subject: [PATCH 09/13] add `Iterator` trait for URLSearchParams --- src/url_search_params.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/url_search_params.rs b/src/url_search_params.rs index e6a7c76..699bd1f 100644 --- a/src/url_search_params.rs +++ b/src/url_search_params.rs @@ -280,14 +280,22 @@ impl Drop for URLSearchParamsKeysIterator<'_> { } } -impl URLSearchParamsKeysIterator<'_> { +impl<'a> Iterator for URLSearchParamsKeysIterator<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option { + self.get_next() + } +} + +impl<'a> URLSearchParamsKeysIterator<'a> { /// Returns true if iterator has a next value. pub fn has_next(&self) -> bool { unsafe { ffi::ada_search_params_keys_iter_has_next(self.iterator) } } /// Returns a new value if it's available - pub fn get_next(&mut self) -> Option<&str> { + pub fn get_next(&mut self) -> Option<&'a str> { if self.has_next() { return None; } @@ -316,6 +324,14 @@ impl Drop for URLSearchParamsValuesIterator<'_> { } } +impl<'a> Iterator for URLSearchParamsValuesIterator<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option { + self.get_next() + } +} + impl<'a> URLSearchParamsValuesIterator<'a> { fn new( iterator: *mut ffi::ada_url_search_params_values_iter, @@ -327,14 +343,14 @@ impl<'a> URLSearchParamsValuesIterator<'a> { } } -impl URLSearchParamsValuesIterator<'_> { +impl<'a> URLSearchParamsValuesIterator<'a> { /// Returns true if iterator has a next value. pub fn has_next(&self) -> bool { unsafe { ffi::ada_search_params_values_iter_has_next(self.iterator) } } /// Returns a new value if it's available - pub fn get_next(&mut self) -> Option<&str> { + pub fn get_next(&mut self) -> Option<&'a str> { if self.has_next() { return None; } From 3f4c21ec3eba3cbaeb212ec7eed6bf4eeff34ef5 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 1 Dec 2024 18:50:34 -0500 Subject: [PATCH 10/13] simplify iterator structs --- src/ffi.rs | 2 +- src/lib.rs | 4 +- src/url_search_params.rs | 132 ++++++++++++++++++++++++--------------- 3 files changed, 84 insertions(+), 54 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 1ed2f73..43f87a2 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -273,7 +273,7 @@ extern "C" { pub fn ada_free_search_params_entries_iter(iter: *mut ada_url_search_params_entries_iter); pub fn ada_search_params_entries_iter_next( iter: *mut ada_url_search_params_entries_iter, - ) -> *mut ada_string_pair; + ) -> ada_string_pair; pub fn ada_search_params_entries_iter_has_next( iter: *mut ada_url_search_params_entries_iter, ) -> bool; diff --git a/src/lib.rs b/src/lib.rs index 7077850..5203938 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,8 +47,8 @@ mod idna; mod url_search_params; pub use idna::Idna; pub use url_search_params::{ - URLSearchParams, URLSearchParamsEntry, URLSearchParamsKeysIterator, - URLSearchParamsValuesIterator, + URLSearchParams, URLSearchParamsEntry, URLSearchParamsEntryIterator, + URLSearchParamsKeyIterator, URLSearchParamsValueIterator, }; #[cfg(feature = "std")] diff --git a/src/url_search_params.rs b/src/url_search_params.rs index 699bd1f..a60cadd 100644 --- a/src/url_search_params.rs +++ b/src/url_search_params.rs @@ -179,10 +179,10 @@ impl URLSearchParams { /// let params = URLSearchParams::parse("a=1") /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// let mut keys = params.keys(); - /// assert!(keys.has_next()); - pub fn keys(&self) -> URLSearchParamsKeysIterator { + /// assert!(keys.next().is_some()); + pub fn keys(&self) -> URLSearchParamsKeyIterator { let iterator = unsafe { ffi::ada_search_params_get_keys(self.0) }; - URLSearchParamsKeysIterator::new(iterator) + URLSearchParamsKeyIterator::new(iterator) } /// Returns all keys as an iterator @@ -192,10 +192,24 @@ impl URLSearchParams { /// let params = URLSearchParams::parse("a=1") /// .expect("This is a valid URLSearchParams. Should have parsed it."); /// let mut values = params.values(); - /// assert!(values.has_next()); - pub fn values(&self) -> URLSearchParamsValuesIterator { + /// assert!(values.next().is_some()); + pub fn values(&self) -> URLSearchParamsValueIterator { let iterator = unsafe { ffi::ada_search_params_get_values(self.0) }; - URLSearchParamsValuesIterator::new(iterator) + URLSearchParamsValueIterator::new(iterator) + } + + /// Returns all entries as an iterator + /// + /// ``` + /// use ada_url::URLSearchParams; + /// let params = URLSearchParams::parse("a=1") + /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// let mut entries = params.entries(); + /// assert_eq!(entries.next(), Some(("a", "1"))); + /// ``` + pub fn entries(&self) -> URLSearchParamsEntryIterator { + let iterator = unsafe { ffi::ada_search_params_get_entries(self.0) }; + URLSearchParamsEntryIterator::new(iterator) } } @@ -269,96 +283,76 @@ where } } -pub struct URLSearchParamsKeysIterator<'a> { +pub struct URLSearchParamsKeyIterator<'a> { iterator: *mut ffi::ada_url_search_params_keys_iter, _phantom: core::marker::PhantomData<&'a str>, } -impl Drop for URLSearchParamsKeysIterator<'_> { +impl Drop for URLSearchParamsKeyIterator<'_> { fn drop(&mut self) { unsafe { ffi::ada_free_search_params_keys_iter(self.iterator) } } } -impl<'a> Iterator for URLSearchParamsKeysIterator<'a> { +impl<'a> Iterator for URLSearchParamsKeyIterator<'a> { type Item = &'a str; fn next(&mut self) -> Option { - self.get_next() - } -} - -impl<'a> URLSearchParamsKeysIterator<'a> { - /// Returns true if iterator has a next value. - pub fn has_next(&self) -> bool { - unsafe { ffi::ada_search_params_keys_iter_has_next(self.iterator) } - } - - /// Returns a new value if it's available - pub fn get_next(&mut self) -> Option<&'a str> { - if self.has_next() { - return None; + let has_next = unsafe { ffi::ada_search_params_keys_iter_has_next(self.iterator) }; + if has_next { + let string = unsafe { ffi::ada_search_params_keys_iter_next(self.iterator) }; + Some(string.as_str()) + } else { + None } - let string = unsafe { ffi::ada_search_params_keys_iter_next(self.iterator) }; - Some(string.as_str()) } } -pub struct URLSearchParamsValuesIterator<'a> { +pub struct URLSearchParamsValueIterator<'a> { iterator: *mut ffi::ada_url_search_params_values_iter, _phantom: core::marker::PhantomData<&'a str>, } -impl<'a> URLSearchParamsKeysIterator<'a> { - fn new(iterator: *mut ffi::ada_url_search_params_keys_iter) -> URLSearchParamsKeysIterator<'a> { - URLSearchParamsKeysIterator { +impl<'a> URLSearchParamsKeyIterator<'a> { + fn new(iterator: *mut ffi::ada_url_search_params_keys_iter) -> URLSearchParamsKeyIterator<'a> { + URLSearchParamsKeyIterator { iterator, _phantom: core::marker::PhantomData, } } } -impl Drop for URLSearchParamsValuesIterator<'_> { +impl Drop for URLSearchParamsValueIterator<'_> { fn drop(&mut self) { unsafe { ffi::ada_free_search_params_values_iter(self.iterator) } } } -impl<'a> Iterator for URLSearchParamsValuesIterator<'a> { +impl<'a> Iterator for URLSearchParamsValueIterator<'a> { type Item = &'a str; fn next(&mut self) -> Option { - self.get_next() + let has_next = unsafe { ffi::ada_search_params_values_iter_has_next(self.iterator) }; + if has_next { + let string = unsafe { ffi::ada_search_params_values_iter_next(self.iterator) }; + Some(string.as_str()) + } else { + None + } } } -impl<'a> URLSearchParamsValuesIterator<'a> { +impl<'a> URLSearchParamsValueIterator<'a> { fn new( iterator: *mut ffi::ada_url_search_params_values_iter, - ) -> URLSearchParamsValuesIterator<'a> { - URLSearchParamsValuesIterator { + ) -> URLSearchParamsValueIterator<'a> { + URLSearchParamsValueIterator { iterator, _phantom: core::marker::PhantomData, } } } -impl<'a> URLSearchParamsValuesIterator<'a> { - /// Returns true if iterator has a next value. - pub fn has_next(&self) -> bool { - unsafe { ffi::ada_search_params_values_iter_has_next(self.iterator) } - } - - /// Returns a new value if it's available - pub fn get_next(&mut self) -> Option<&'a str> { - if self.has_next() { - return None; - } - let string = unsafe { ffi::ada_search_params_values_iter_next(self.iterator) }; - Some(string.as_str()) - } -} - pub struct URLSearchParamsEntry<'a> { strings: *mut ffi::ada_strings, size: usize, @@ -445,3 +439,39 @@ impl<'a> From> for Vec<&'a str> { vec } } + +pub struct URLSearchParamsEntryIterator<'a> { + iterator: *mut ffi::ada_url_search_params_entries_iter, + _phantom: core::marker::PhantomData<&'a str>, +} + +impl<'a> URLSearchParamsEntryIterator<'a> { + fn new( + iterator: *mut ffi::ada_url_search_params_entries_iter, + ) -> URLSearchParamsEntryIterator<'a> { + URLSearchParamsEntryIterator { + iterator, + _phantom: core::marker::PhantomData, + } + } +} + +impl Drop for URLSearchParamsEntryIterator<'_> { + fn drop(&mut self) { + unsafe { ffi::ada_free_search_params_entries_iter(self.iterator) } + } +} + +impl<'a> Iterator for URLSearchParamsEntryIterator<'a> { + type Item = (&'a str, &'a str); + + fn next(&mut self) -> Option { + let has_next = unsafe { ffi::ada_search_params_entries_iter_has_next(self.iterator) }; + if has_next { + let pair = unsafe { ffi::ada_search_params_entries_iter_next(self.iterator) }; + Some((pair.key.as_str(), pair.value.as_str())) + } else { + None + } + } +} From ab30ce9e5fbcff82a596e5d6d033bde351106ea6 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 1 Dec 2024 19:49:17 -0500 Subject: [PATCH 11/13] rename url search params --- src/lib.rs | 4 +- src/url_search_params.rs | 198 +++++++++++++++++++-------------------- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5203938..6d4392a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,8 +47,8 @@ mod idna; mod url_search_params; pub use idna::Idna; pub use url_search_params::{ - URLSearchParams, URLSearchParamsEntry, URLSearchParamsEntryIterator, - URLSearchParamsKeyIterator, URLSearchParamsValueIterator, + UrlSearchParams, UrlSearchParamsEntry, UrlSearchParamsEntryIterator, + UrlSearchParamsKeyIterator, UrlSearchParamsValueIterator, }; #[cfg(feature = "std")] diff --git a/src/url_search_params.rs b/src/url_search_params.rs index a60cadd..6ff02e2 100644 --- a/src/url_search_params.rs +++ b/src/url_search_params.rs @@ -1,20 +1,20 @@ use crate::{ffi, ParseUrlError}; -pub struct URLSearchParams(*mut ffi::ada_url_search_params); +pub struct UrlSearchParams(*mut ffi::ada_url_search_params); -impl Drop for URLSearchParams { +impl Drop for UrlSearchParams { fn drop(&mut self) { unsafe { ffi::ada_free_search_params(self.0) } } } -impl URLSearchParams { - /// Parses an return a URLSearchParams struct. +impl UrlSearchParams { + /// Parses an return a UrlSearchParams struct. /// /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1&b=2") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// assert_eq!(params.get("a"), Some("1")); /// assert_eq!(params.get("b"), Some("2")); /// ``` @@ -27,29 +27,29 @@ impl URLSearchParams { })) } - /// Returns the size of the URLSearchParams struct. + /// Returns the size of the UrlSearchParams struct. /// /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1&b=2") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// assert_eq!(params.len(), 2); /// ``` pub fn len(&self) -> usize { unsafe { ffi::ada_search_params_size(self.0) } } - /// Returns true if no entries exist in the URLSearchParams. + /// Returns true if no entries exist in the UrlSearchParams. pub fn is_empty(&self) -> bool { self.len() == 0 } - /// Sorts the keys of the URLSearchParams struct. + /// Sorts the keys of the UrlSearchParams struct. pub fn sort(&mut self) { unsafe { ffi::ada_search_params_sort(self.0) } } - /// Appends a key/value to the URLSearchParams struct. + /// Appends a key/value to the UrlSearchParams struct. pub fn append(&mut self, key: &str, value: &str) { unsafe { ffi::ada_search_params_append( @@ -62,13 +62,13 @@ impl URLSearchParams { } } - /// Removes all pre-existing keys from the URLSearchParams struct + /// Removes all pre-existing keys from the UrlSearchParams struct /// and appends the new key/value. /// /// ``` - /// use ada_url::URLSearchParams; - /// let mut params = URLSearchParams::parse("a=1&b=2") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let mut params = UrlSearchParams::parse("a=1&b=2") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// params.set("a", "3"); /// assert_eq!(params.get("a"), Some("3")); /// ``` @@ -84,14 +84,14 @@ impl URLSearchParams { } } - /// Removes a key/value from the URLSearchParams struct. + /// Removes a key/value from the UrlSearchParams struct. /// Depending on the value parameter, it will either remove /// the key/value pair or just the key. /// /// ``` - /// use ada_url::URLSearchParams; - /// let mut params = URLSearchParams::parse("a=1&b=2") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let mut params = UrlSearchParams::parse("a=1&b=2") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// params.remove("a", Some("1")); /// assert_eq!(params.get("a"), None); /// ``` @@ -111,12 +111,12 @@ impl URLSearchParams { } } - /// Returns whether the [`URLSearchParams`] contains the `key`. + /// Returns whether the [`UrlSearchParams`] contains the `key`. /// /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1&b=2") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// assert_eq!(params.contains("a", None), true); /// ``` pub fn contains(&self, key: &str, value: Option<&str>) -> bool { @@ -138,9 +138,9 @@ impl URLSearchParams { /// Returns the value of the key. /// /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1&b=2") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// assert_eq!(params.get("a"), Some("1")); /// assert_eq!(params.get("c"), None); /// ``` @@ -158,63 +158,63 @@ impl URLSearchParams { /// Returns all values of the key. /// /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&a=2") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1&a=2") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.len(), 2); /// ``` - pub fn get_all(&self, key: &str) -> URLSearchParamsEntry { + pub fn get_all(&self, key: &str) -> UrlSearchParamsEntry { unsafe { let strings = ffi::ada_search_params_get_all(self.0, key.as_ptr().cast(), key.len()); let size = ffi::ada_strings_size(strings); - URLSearchParamsEntry::new(strings, size) + UrlSearchParamsEntry::new(strings, size) } } /// Returns all keys as an iterator /// /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// let mut keys = params.keys(); /// assert!(keys.next().is_some()); - pub fn keys(&self) -> URLSearchParamsKeyIterator { + pub fn keys(&self) -> UrlSearchParamsKeyIterator { let iterator = unsafe { ffi::ada_search_params_get_keys(self.0) }; - URLSearchParamsKeyIterator::new(iterator) + UrlSearchParamsKeyIterator::new(iterator) } /// Returns all keys as an iterator /// /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// let mut values = params.values(); /// assert!(values.next().is_some()); - pub fn values(&self) -> URLSearchParamsValueIterator { + pub fn values(&self) -> UrlSearchParamsValueIterator { let iterator = unsafe { ffi::ada_search_params_get_values(self.0) }; - URLSearchParamsValueIterator::new(iterator) + UrlSearchParamsValueIterator::new(iterator) } /// Returns all entries as an iterator /// /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// let mut entries = params.entries(); /// assert_eq!(entries.next(), Some(("a", "1"))); /// ``` - pub fn entries(&self) -> URLSearchParamsEntryIterator { + pub fn entries(&self) -> UrlSearchParamsEntryIterator { let iterator = unsafe { ffi::ada_search_params_get_entries(self.0) }; - URLSearchParamsEntryIterator::new(iterator) + UrlSearchParamsEntryIterator::new(iterator) } } #[cfg(feature = "std")] -impl core::str::FromStr for URLSearchParams { +impl core::str::FromStr for UrlSearchParams { type Err = ParseUrlError>; fn from_str(s: &str) -> Result { @@ -224,31 +224,31 @@ impl core::str::FromStr for URLSearchParams { } } -/// Returns the stringified version of the URLSearchParams struct. +/// Returns the stringified version of the UrlSearchParams struct. /// /// ``` -/// use ada_url::URLSearchParams; -/// let params = URLSearchParams::parse("a=1&b=2") -/// .expect("This is a valid URLSearchParams. Should have parsed it."); +/// use ada_url::UrlSearchParams; +/// let params = UrlSearchParams::parse("a=1&b=2") +/// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// assert_eq!(params.to_string(), "a=1&b=2"); /// ``` -impl core::fmt::Display for URLSearchParams { +impl core::fmt::Display for UrlSearchParams { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str(unsafe { ffi::ada_search_params_to_string(self.0).as_ref() }) } } #[cfg(feature = "std")] -impl Extend<(Input, Input)> for URLSearchParams +impl Extend<(Input, Input)> for UrlSearchParams where Input: AsRef, { - /// Supports extending URLSearchParams through an iterator. + /// Supports extending UrlSearchParams through an iterator. /// ///``` - /// use ada_url::URLSearchParams; - /// let mut params = URLSearchParams::parse("a=1&b=2") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let mut params = UrlSearchParams::parse("a=1&b=2") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// assert_eq!(params.len(), 2); /// params.extend([("foo", "bar")]); /// assert_eq!(params.len(), 3); @@ -261,20 +261,20 @@ where } #[cfg(feature = "std")] -impl FromIterator<(Input, Input)> for URLSearchParams +impl FromIterator<(Input, Input)> for UrlSearchParams where Input: AsRef, { - /// Converts an iterator to URLSearchParams + /// Converts an iterator to UrlSearchParams /// /// ``` - /// use ada_url::URLSearchParams; + /// use ada_url::UrlSearchParams; /// let iterator = std::iter::repeat(("hello", "world")).take(5); - /// let params = URLSearchParams::from_iter(iterator); + /// let params = UrlSearchParams::from_iter(iterator); /// assert_eq!(params.len(), 5); /// ``` fn from_iter>(iter: T) -> Self { - let mut params = URLSearchParams::parse("") + let mut params = UrlSearchParams::parse("") .expect("Failed to parse empty string. This is likely due to a bug"); for item in iter { params.append(item.0.as_ref(), item.1.as_ref()); @@ -283,18 +283,18 @@ where } } -pub struct URLSearchParamsKeyIterator<'a> { +pub struct UrlSearchParamsKeyIterator<'a> { iterator: *mut ffi::ada_url_search_params_keys_iter, _phantom: core::marker::PhantomData<&'a str>, } -impl Drop for URLSearchParamsKeyIterator<'_> { +impl Drop for UrlSearchParamsKeyIterator<'_> { fn drop(&mut self) { unsafe { ffi::ada_free_search_params_keys_iter(self.iterator) } } } -impl<'a> Iterator for URLSearchParamsKeyIterator<'a> { +impl<'a> Iterator for UrlSearchParamsKeyIterator<'a> { type Item = &'a str; fn next(&mut self) -> Option { @@ -308,27 +308,27 @@ impl<'a> Iterator for URLSearchParamsKeyIterator<'a> { } } -pub struct URLSearchParamsValueIterator<'a> { +pub struct UrlSearchParamsValueIterator<'a> { iterator: *mut ffi::ada_url_search_params_values_iter, _phantom: core::marker::PhantomData<&'a str>, } -impl<'a> URLSearchParamsKeyIterator<'a> { - fn new(iterator: *mut ffi::ada_url_search_params_keys_iter) -> URLSearchParamsKeyIterator<'a> { - URLSearchParamsKeyIterator { +impl<'a> UrlSearchParamsKeyIterator<'a> { + fn new(iterator: *mut ffi::ada_url_search_params_keys_iter) -> UrlSearchParamsKeyIterator<'a> { + UrlSearchParamsKeyIterator { iterator, _phantom: core::marker::PhantomData, } } } -impl Drop for URLSearchParamsValueIterator<'_> { +impl Drop for UrlSearchParamsValueIterator<'_> { fn drop(&mut self) { unsafe { ffi::ada_free_search_params_values_iter(self.iterator) } } } -impl<'a> Iterator for URLSearchParamsValueIterator<'a> { +impl<'a> Iterator for UrlSearchParamsValueIterator<'a> { type Item = &'a str; fn next(&mut self) -> Option { @@ -342,26 +342,26 @@ impl<'a> Iterator for URLSearchParamsValueIterator<'a> { } } -impl<'a> URLSearchParamsValueIterator<'a> { +impl<'a> UrlSearchParamsValueIterator<'a> { fn new( iterator: *mut ffi::ada_url_search_params_values_iter, - ) -> URLSearchParamsValueIterator<'a> { - URLSearchParamsValueIterator { + ) -> UrlSearchParamsValueIterator<'a> { + UrlSearchParamsValueIterator { iterator, _phantom: core::marker::PhantomData, } } } -pub struct URLSearchParamsEntry<'a> { +pub struct UrlSearchParamsEntry<'a> { strings: *mut ffi::ada_strings, size: usize, _phantom: core::marker::PhantomData<&'a str>, } -impl<'a> URLSearchParamsEntry<'a> { - fn new(strings: *mut ffi::ada_strings, size: usize) -> URLSearchParamsEntry<'a> { - URLSearchParamsEntry { +impl<'a> UrlSearchParamsEntry<'a> { + fn new(strings: *mut ffi::ada_strings, size: usize) -> UrlSearchParamsEntry<'a> { + UrlSearchParamsEntry { strings, size, _phantom: core::marker::PhantomData, @@ -371,9 +371,9 @@ impl<'a> URLSearchParamsEntry<'a> { /// Returns whether the key value pair is empty or not /// /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1&b=2") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.is_empty(), false); /// ``` @@ -384,9 +384,9 @@ impl<'a> URLSearchParamsEntry<'a> { /// Returns the size of the key value pairs /// /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&b=2") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1&b=2") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.len(), 1); /// ``` @@ -397,9 +397,9 @@ impl<'a> URLSearchParamsEntry<'a> { /// Get an entry by index /// /// ``` - /// use ada_url::URLSearchParams; - /// let params = URLSearchParams::parse("a=1&a=2") - /// .expect("This is a valid URLSearchParams. Should have parsed it."); + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1&a=2") + /// .expect("This is a valid UrlSearchParams. Should have parsed it."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.len(), 2); /// assert_eq!(pairs.get(0), Some("1")); @@ -419,15 +419,15 @@ impl<'a> URLSearchParamsEntry<'a> { } } -impl Drop for URLSearchParamsEntry<'_> { +impl Drop for UrlSearchParamsEntry<'_> { fn drop(&mut self) { unsafe { ffi::ada_free_strings(self.strings) } } } #[cfg(feature = "std")] -impl<'a> From> for Vec<&'a str> { - fn from(val: URLSearchParamsEntry<'a>) -> Self { +impl<'a> From> for Vec<&'a str> { + fn from(val: UrlSearchParamsEntry<'a>) -> Self { let mut vec = Vec::with_capacity(val.size); unsafe { for index in 0..val.size { @@ -440,29 +440,29 @@ impl<'a> From> for Vec<&'a str> { } } -pub struct URLSearchParamsEntryIterator<'a> { +pub struct UrlSearchParamsEntryIterator<'a> { iterator: *mut ffi::ada_url_search_params_entries_iter, _phantom: core::marker::PhantomData<&'a str>, } -impl<'a> URLSearchParamsEntryIterator<'a> { +impl<'a> UrlSearchParamsEntryIterator<'a> { fn new( iterator: *mut ffi::ada_url_search_params_entries_iter, - ) -> URLSearchParamsEntryIterator<'a> { - URLSearchParamsEntryIterator { + ) -> UrlSearchParamsEntryIterator<'a> { + UrlSearchParamsEntryIterator { iterator, _phantom: core::marker::PhantomData, } } } -impl Drop for URLSearchParamsEntryIterator<'_> { +impl Drop for UrlSearchParamsEntryIterator<'_> { fn drop(&mut self) { unsafe { ffi::ada_free_search_params_entries_iter(self.iterator) } } } -impl<'a> Iterator for URLSearchParamsEntryIterator<'a> { +impl<'a> Iterator for UrlSearchParamsEntryIterator<'a> { type Item = (&'a str, &'a str); fn next(&mut self) -> Option { From 3da7861bb8950f085bf34794c5bb8fa4b03745ed Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sun, 1 Dec 2024 20:08:07 -0500 Subject: [PATCH 12/13] add hash trait to url search params --- src/url_search_params.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/url_search_params.rs b/src/url_search_params.rs index 6ff02e2..ea3fe5f 100644 --- a/src/url_search_params.rs +++ b/src/url_search_params.rs @@ -213,6 +213,12 @@ impl UrlSearchParams { } } +impl core::hash::Hash for UrlSearchParams { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + #[cfg(feature = "std")] impl core::str::FromStr for UrlSearchParams { type Err = ParseUrlError>; From 08ca7a8c7cde76602eecfe4e2bd2111018f15576 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Tue, 3 Dec 2024 15:23:56 -0500 Subject: [PATCH 13/13] address reviews --- src/url_search_params.rs | 125 ++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 55 deletions(-) diff --git a/src/url_search_params.rs b/src/url_search_params.rs index ea3fe5f..f3ffe66 100644 --- a/src/url_search_params.rs +++ b/src/url_search_params.rs @@ -1,5 +1,6 @@ use crate::{ffi, ParseUrlError}; +#[derive(Hash)] pub struct UrlSearchParams(*mut ffi::ada_url_search_params); impl Drop for UrlSearchParams { @@ -14,7 +15,7 @@ impl UrlSearchParams { /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1&b=2") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// assert_eq!(params.get("a"), Some("1")); /// assert_eq!(params.get("b"), Some("2")); /// ``` @@ -27,13 +28,15 @@ impl UrlSearchParams { })) } - /// Returns the size of the UrlSearchParams struct. + /// Returns the unique keys in a UrlSearchParams. /// /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1&b=2") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// assert_eq!(params.len(), 2); + /// let keys = params.keys().into_iter(); + /// assert_eq!(keys.count(), params.len()); /// ``` pub fn len(&self) -> usize { unsafe { ffi::ada_search_params_size(self.0) } @@ -68,7 +71,7 @@ impl UrlSearchParams { /// ``` /// use ada_url::UrlSearchParams; /// let mut params = UrlSearchParams::parse("a=1&b=2") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// params.set("a", "3"); /// assert_eq!(params.get("a"), Some("3")); /// ``` @@ -84,30 +87,37 @@ impl UrlSearchParams { } } - /// Removes a key/value from the UrlSearchParams struct. - /// Depending on the value parameter, it will either remove - /// the key/value pair or just the key. + /// Removes a key from the UrlSearchParams struct. /// /// ``` /// use ada_url::UrlSearchParams; /// let mut params = UrlSearchParams::parse("a=1&b=2") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); - /// params.remove("a", Some("1")); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); + /// params.remove_key("a"); /// assert_eq!(params.get("a"), None); /// ``` - pub fn remove(&mut self, key: &str, value: Option<&str>) { - if let Some(value) = value { - unsafe { - ffi::ada_search_params_remove_value( - self.0, - key.as_ptr().cast(), - key.len(), - value.as_ptr().cast(), - value.len(), - ) - } - } else { - unsafe { ffi::ada_search_params_remove(self.0, key.as_ptr().cast(), key.len()) } + pub fn remove_key(&mut self, key: &str) { + unsafe { ffi::ada_search_params_remove(self.0, key.as_ptr().cast(), key.len()) } + } + + /// Removes a key with a value from the UrlSearchParams struct. + /// + /// ``` + /// use ada_url::UrlSearchParams; + /// let mut params = UrlSearchParams::parse("a=1&b=2") + /// .expect("String should have been able to be parsed into an UrlSearchParams."); + /// params.remove("a", "1"); + /// assert_eq!(params.get("a"), None); + /// ``` + pub fn remove(&mut self, key: &str, value: &str) { + unsafe { + ffi::ada_search_params_remove_value( + self.0, + key.as_ptr().cast(), + key.len(), + value.as_ptr().cast(), + value.len(), + ) } } @@ -116,22 +126,30 @@ impl UrlSearchParams { /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1&b=2") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); - /// assert_eq!(params.contains("a", None), true); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); + /// assert_eq!(params.contains_key("a"), true); /// ``` - pub fn contains(&self, key: &str, value: Option<&str>) -> bool { - if let Some(value) = value { - unsafe { - ffi::ada_search_params_has_value( - self.0, - key.as_ptr().cast(), - key.len(), - value.as_ptr().cast(), - value.len(), - ) - } - } else { - unsafe { ffi::ada_search_params_has(self.0, key.as_ptr().cast(), key.len()) } + pub fn contains_key(&self, key: &str) -> bool { + unsafe { ffi::ada_search_params_has(self.0, key.as_ptr().cast(), key.len()) } + } + + /// Returns whether the [`UrlSearchParams`] contains the `key` with the `value`. + /// + /// ``` + /// use ada_url::UrlSearchParams; + /// let params = UrlSearchParams::parse("a=1&b=2") + /// .expect("String should have been able to be parsed into an UrlSearchParams."); + /// assert_eq!(params.contains("a", "1"), true); + /// ``` + pub fn contains(&self, key: &str, value: &str) -> bool { + unsafe { + ffi::ada_search_params_has_value( + self.0, + key.as_ptr().cast(), + key.len(), + value.as_ptr().cast(), + value.len(), + ) } } @@ -140,7 +158,7 @@ impl UrlSearchParams { /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1&b=2") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// assert_eq!(params.get("a"), Some("1")); /// assert_eq!(params.get("c"), None); /// ``` @@ -160,7 +178,7 @@ impl UrlSearchParams { /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1&a=2") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.len(), 2); /// ``` @@ -177,7 +195,7 @@ impl UrlSearchParams { /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// let mut keys = params.keys(); /// assert!(keys.next().is_some()); pub fn keys(&self) -> UrlSearchParamsKeyIterator { @@ -185,12 +203,12 @@ impl UrlSearchParams { UrlSearchParamsKeyIterator::new(iterator) } - /// Returns all keys as an iterator + /// Returns all values as an iterator /// /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// let mut values = params.values(); /// assert!(values.next().is_some()); pub fn values(&self) -> UrlSearchParamsValueIterator { @@ -203,7 +221,7 @@ impl UrlSearchParams { /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// let mut entries = params.entries(); /// assert_eq!(entries.next(), Some(("a", "1"))); /// ``` @@ -213,12 +231,6 @@ impl UrlSearchParams { } } -impl core::hash::Hash for UrlSearchParams { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - #[cfg(feature = "std")] impl core::str::FromStr for UrlSearchParams { type Err = ParseUrlError>; @@ -235,7 +247,7 @@ impl core::str::FromStr for UrlSearchParams { /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1&b=2") -/// .expect("This is a valid UrlSearchParams. Should have parsed it."); +/// .expect("String should have been able to be parsed into an UrlSearchParams."); /// assert_eq!(params.to_string(), "a=1&b=2"); /// ``` impl core::fmt::Display for UrlSearchParams { @@ -254,7 +266,7 @@ where ///``` /// use ada_url::UrlSearchParams; /// let mut params = UrlSearchParams::parse("a=1&b=2") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// assert_eq!(params.len(), 2); /// params.extend([("foo", "bar")]); /// assert_eq!(params.len(), 3); @@ -281,7 +293,7 @@ where /// ``` fn from_iter>(iter: T) -> Self { let mut params = UrlSearchParams::parse("") - .expect("Failed to parse empty string. This is likely due to a bug"); + .expect("Should be able to parse empty string. This is likely due to a bug"); for item in iter { params.append(item.0.as_ref(), item.1.as_ref()); } @@ -289,6 +301,7 @@ where } } +#[derive(Hash)] pub struct UrlSearchParamsKeyIterator<'a> { iterator: *mut ffi::ada_url_search_params_keys_iter, _phantom: core::marker::PhantomData<&'a str>, @@ -314,6 +327,7 @@ impl<'a> Iterator for UrlSearchParamsKeyIterator<'a> { } } +#[derive(Hash)] pub struct UrlSearchParamsValueIterator<'a> { iterator: *mut ffi::ada_url_search_params_values_iter, _phantom: core::marker::PhantomData<&'a str>, @@ -379,7 +393,7 @@ impl<'a> UrlSearchParamsEntry<'a> { /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1&b=2") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.is_empty(), false); /// ``` @@ -392,7 +406,7 @@ impl<'a> UrlSearchParamsEntry<'a> { /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1&b=2") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.len(), 1); /// ``` @@ -405,7 +419,7 @@ impl<'a> UrlSearchParamsEntry<'a> { /// ``` /// use ada_url::UrlSearchParams; /// let params = UrlSearchParams::parse("a=1&a=2") - /// .expect("This is a valid UrlSearchParams. Should have parsed it."); + /// .expect("String should have been able to be parsed into an UrlSearchParams."); /// let pairs = params.get_all("a"); /// assert_eq!(pairs.len(), 2); /// assert_eq!(pairs.get(0), Some("1")); @@ -446,6 +460,7 @@ impl<'a> From> for Vec<&'a str> { } } +#[derive(Hash)] pub struct UrlSearchParamsEntryIterator<'a> { iterator: *mut ffi::ada_url_search_params_entries_iter, _phantom: core::marker::PhantomData<&'a str>,