From b5a6e1a41e5793123b006af029bb3729ef05a01e Mon Sep 17 00:00:00 2001 From: Alex Povel Date: Wed, 20 Mar 2024 13:34:14 +0100 Subject: [PATCH 1/9] docs: Fix sample code In a new project, after `cargo add ada-url`, now compiles successfully --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5ee1587..9aa3772 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,12 @@ Here is an example illustrating a common usage: ```Rust use ada_url::Url; fn main() { - let u = Url::parse("http://www.google:8080/love#drug", None).expect("bad url"); + let mut u = Url::parse("http://www.google:8080/love#drug", None).expect("bad url"); println!("port: {:?}", u.port()); println!("hash: {:?}", u.hash()); println!("pathname: {:?}", u.pathname()); println!("href: {:?}", u.href()); - u.set_port("9999"); + u.set_port(Some("9999")); println!("href: {:?}", u.href()); } ``` From 391f44ad55da65b0035e5de908f9b7a5f664ab9a Mon Sep 17 00:00:00 2001 From: Alex Povel Date: Wed, 20 Mar 2024 13:37:57 +0100 Subject: [PATCH 2/9] docs: Use unused `Result` `set_port` returns a `Result` we `must_use`. Fixes the compiler warning. --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9aa3772..def8060 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,16 @@ Here is an example illustrating a common usage: ```Rust use ada_url::Url; -fn main() { +fn main() -> Result<(), ()> { let mut u = Url::parse("http://www.google:8080/love#drug", None).expect("bad url"); println!("port: {:?}", u.port()); println!("hash: {:?}", u.hash()); println!("pathname: {:?}", u.pathname()); println!("href: {:?}", u.href()); - u.set_port(Some("9999")); + u.set_port(Some("9999"))?; println!("href: {:?}", u.href()); + + Ok(()) } ``` From 93d3ccb1e8ff7e758c736247c1c77e8da21821b4 Mon Sep 17 00:00:00 2001 From: Alex Povel Date: Wed, 20 Mar 2024 13:56:07 +0100 Subject: [PATCH 3/9] feat!: `Error` for `SetterResult` This implements `std::error::Error` for a newly introduced error type. We cannot implement that trait on `()` in this crate, so cannot offer consumers convenient error handling via `?` etc. (`anyhow`, ...) without a dedicated error type we own. --- README.md | 2 +- src/lib.rs | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index def8060..468a0dc 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Here is an example illustrating a common usage: ```Rust use ada_url::Url; -fn main() -> Result<(), ()> { +fn main() -> Result<(), Box> { let mut u = Url::parse("http://www.google:8080/love#drug", None).expect("bad url"); println!("port: {:?}", u.port()); println!("hash: {:?}", u.hash()); diff --git a/src/lib.rs b/src/lib.rs index 92ead82..d0b7fcd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -179,14 +179,19 @@ impl From<*mut ffi::ada_url> for Url { } } -type SetterResult = Result<(), ()>; +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Display)] +pub struct SetterError; + +impl std::error::Error for SetterError {} + +type SetterResult = Result<(), SetterError>; #[inline] fn setter_result(successful: bool) -> SetterResult { if successful { Ok(()) } else { - Err(()) + Err(SetterError) } } @@ -290,7 +295,6 @@ impl Url { /// url.set_href("https://lemire.me").unwrap(); /// assert_eq!(url.href(), "https://lemire.me/"); /// ``` - #[allow(clippy::result_unit_err)] pub fn set_href(&mut self, input: &str) -> SetterResult { setter_result(unsafe { ffi::ada_set_href(self.0, input.as_ptr().cast(), input.len()) }) } @@ -318,7 +322,6 @@ impl Url { /// url.set_username(Some("username")).unwrap(); /// assert_eq!(url.href(), "https://username@yagiz.co/"); /// ``` - #[allow(clippy::result_unit_err)] pub fn set_username(&mut self, input: Option<&str>) -> SetterResult { setter_result(unsafe { ffi::ada_set_username( @@ -352,7 +355,6 @@ impl Url { /// url.set_password(Some("password")).unwrap(); /// assert_eq!(url.href(), "https://:password@yagiz.co/"); /// ``` - #[allow(clippy::result_unit_err)] pub fn set_password(&mut self, input: Option<&str>) -> SetterResult { setter_result(unsafe { ffi::ada_set_password( @@ -389,7 +391,6 @@ impl Url { /// url.set_port(Some("8080")).unwrap(); /// assert_eq!(url.href(), "https://yagiz.co:8080/"); /// ``` - #[allow(clippy::result_unit_err)] pub fn set_port(&mut self, input: Option<&str>) -> SetterResult { match input { Some(value) => setter_result(unsafe { @@ -462,7 +463,6 @@ impl Url { /// url.set_host(Some("localhost:3000")).unwrap(); /// assert_eq!(url.href(), "https://localhost:3000/"); /// ``` - #[allow(clippy::result_unit_err)] pub fn set_host(&mut self, input: Option<&str>) -> SetterResult { setter_result(unsafe { ffi::ada_set_host( @@ -500,7 +500,6 @@ impl Url { /// url.set_hostname(Some("localhost")).unwrap(); /// assert_eq!(url.href(), "https://localhost/"); /// ``` - #[allow(clippy::result_unit_err)] pub fn set_hostname(&mut self, input: Option<&str>) -> SetterResult { setter_result(unsafe { ffi::ada_set_hostname( @@ -534,7 +533,6 @@ impl Url { /// url.set_pathname(Some("/contact")).unwrap(); /// assert_eq!(url.href(), "https://yagiz.co/contact"); /// ``` - #[allow(clippy::result_unit_err)] pub fn set_pathname(&mut self, input: Option<&str>) -> SetterResult { setter_result(unsafe { ffi::ada_set_pathname( @@ -603,7 +601,6 @@ impl Url { /// url.set_protocol("http").unwrap(); /// assert_eq!(url.href(), "http://yagiz.co/"); /// ``` - #[allow(clippy::result_unit_err)] pub fn set_protocol(&mut self, input: &str) -> SetterResult { setter_result(unsafe { ffi::ada_set_protocol(self.0, input.as_ptr().cast(), input.len()) }) } From c73e6e1bda39674c8c285aeeeb3cf8b64c1b9074 Mon Sep 17 00:00:00 2001 From: Alex Povel Date: Wed, 20 Mar 2024 14:18:02 +0100 Subject: [PATCH 4/9] chore: Fix various `clippy` lints Found by temporarily adding ```rust ``` to `lib.rs`. Removed it again because not all lints are solved (I only applied the more useful ones, which should benefit library consumers at no costs), and I didn't think putting `#[allow(...)]` throughout was a good idea. --- src/ffi.rs | 3 +- src/idna.rs | 4 ++- src/lib.rs | 80 ++++++++++++++++++++++++++++++++++------------------- 3 files changed, 56 insertions(+), 31 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 4110bed..10e3d3b 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -14,7 +14,8 @@ pub struct ada_string { } impl ada_string { - pub fn as_str(&self) -> &'static str { + #[must_use] + pub const fn as_str(&self) -> &'static str { unsafe { let slice = core::slice::from_raw_parts(self.data.cast(), self.length); core::str::from_utf8_unchecked(slice) diff --git a/src/idna.rs b/src/idna.rs index d5df15c..9f035a4 100644 --- a/src/idna.rs +++ b/src/idna.rs @@ -1,6 +1,6 @@ use crate::ffi; -/// IDNA struct implements the to_ascii and to_unicode functions from the Unicode Technical +/// IDNA struct implements the `to_ascii` and `to_unicode` functions from the Unicode Technical /// Standard supporting a wide range of systems. It is suitable for URL parsing. /// For more information, [read the specification](https://www.unicode.org/reports/tr46/#ToUnicode) pub struct Idna {} @@ -15,6 +15,7 @@ impl Idna { /// use ada_url::Idna; /// assert_eq!(Idna::unicode("xn--meagefactory-m9a.ca"), "meßagefactory.ca"); /// ``` + #[must_use] pub fn unicode(input: &str) -> &str { unsafe { let out = ffi::ada_idna_to_unicode(input.as_ptr().cast(), input.len()); @@ -32,6 +33,7 @@ impl Idna { /// use ada_url::Idna; /// assert_eq!(Idna::ascii("meßagefactory.ca"), "xn--meagefactory-m9a.ca"); /// ``` + #[must_use] pub fn ascii(input: &str) -> &str { unsafe { let out = ffi::ada_idna_to_ascii(input.as_ptr().cast(), input.len()); diff --git a/src/lib.rs b/src/lib.rs index d0b7fcd..edf9f6f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,10 +70,10 @@ pub enum HostType { impl From for HostType { fn from(value: c_uint) -> Self { match value { - 0 => HostType::Domain, - 1 => HostType::IPV4, - 2 => HostType::IPV6, - _ => HostType::Domain, + 0 => Self::Domain, + 1 => Self::IPV4, + 2 => Self::IPV6, + _ => Self::Domain, } } } @@ -93,14 +93,14 @@ pub enum SchemeType { impl From for SchemeType { fn from(value: c_uint) -> Self { match value { - 0 => SchemeType::Http, - 1 => SchemeType::NotSpecial, - 2 => SchemeType::Https, - 3 => SchemeType::Ws, - 4 => SchemeType::Ftp, - 5 => SchemeType::Wss, - 6 => SchemeType::File, - _ => SchemeType::NotSpecial, + 0 => Self::Http, + 1 => Self::NotSpecial, + 2 => Self::Https, + 3 => Self::Ws, + 4 => Self::Ftp, + 5 => Self::Wss, + 6 => Self::File, + _ => Self::NotSpecial, } } } @@ -187,7 +187,7 @@ impl std::error::Error for SetterError {} type SetterResult = Result<(), SetterError>; #[inline] -fn setter_result(successful: bool) -> SetterResult { +const fn setter_result(successful: bool) -> SetterResult { if successful { Ok(()) } else { @@ -204,7 +204,7 @@ impl Url { /// .expect("This is a valid URL. Should have parsed it."); /// assert_eq!(out.protocol(), "https:"); /// ``` - pub fn parse(input: Input, base: Option<&str>) -> Result> + pub fn parse(input: Input, base: Option<&str>) -> Result> where Input: AsRef, { @@ -236,6 +236,7 @@ impl Url { /// assert!(Url::can_parse("https://ada-url.github.io/ada", None)); /// assert!(Url::can_parse("/pathname", Some("https://ada-url.github.io/ada"))); /// ``` + #[must_use] pub fn can_parse(input: &str, base: Option<&str>) -> bool { unsafe { if let Some(base) = base { @@ -252,11 +253,13 @@ impl Url { } /// Returns the type of the host such as default, ipv4 or ipv6. + #[must_use] pub fn host_type(&self) -> HostType { HostType::from(unsafe { ffi::ada_get_host_type(self.0) }) } /// Returns the type of the scheme such as http, https, etc. + #[must_use] pub fn scheme_type(&self) -> SchemeType { SchemeType::from(unsafe { ffi::ada_get_scheme_type(self.0) }) } @@ -271,6 +274,7 @@ impl Url { /// let url = Url::parse("blob:https://example.com/foo", None).expect("Invalid URL"); /// assert_eq!(url.origin(), "https://example.com"); /// ``` + #[must_use] pub fn origin(&self) -> &str { unsafe { let out = ffi::ada_get_origin(self.0); @@ -282,6 +286,7 @@ impl Url { /// Return the parsed version of the URL with all components. /// /// For more information, read [WHATWG URL spec](https://url.spec.whatwg.org/#dom-url-href) + #[must_use] pub fn href(&self) -> &str { unsafe { ffi::ada_get_href(self.0) }.as_str() } @@ -309,6 +314,7 @@ impl Url { /// let url = Url::parse("ftp://rms:secret123@example.com", None).expect("Invalid URL"); /// assert_eq!(url.username(), "rms"); /// ``` + #[must_use] pub fn username(&self) -> &str { unsafe { ffi::ada_get_username(self.0) }.as_str() } @@ -327,7 +333,7 @@ impl Url { ffi::ada_set_username( self.0, input.unwrap_or("").as_ptr().cast(), - input.map_or(0, |i| i.len()), + input.map_or(0, str::len), ) }) } @@ -342,6 +348,7 @@ impl Url { /// let url = Url::parse("ftp://rms:secret123@example.com", None).expect("Invalid URL"); /// assert_eq!(url.password(), "secret123"); /// ``` + #[must_use] pub fn password(&self) -> &str { unsafe { ffi::ada_get_password(self.0) }.as_str() } @@ -360,7 +367,7 @@ impl Url { ffi::ada_set_password( self.0, input.unwrap_or("").as_ptr().cast(), - input.map_or(0, |i| i.len()), + input.map_or(0, str::len), ) }) } @@ -378,6 +385,7 @@ impl Url { /// let url = Url::parse("https://example.com:8080", None).expect("Invalid URL"); /// assert_eq!(url.port(), "8080"); /// ``` + #[must_use] pub fn port(&self) -> &str { unsafe { ffi::ada_get_port(self.0) }.as_str() } @@ -392,14 +400,11 @@ impl Url { /// assert_eq!(url.href(), "https://yagiz.co:8080/"); /// ``` pub fn set_port(&mut self, input: Option<&str>) -> SetterResult { - match input { - Some(value) => setter_result(unsafe { - ffi::ada_set_port(self.0, value.as_ptr().cast(), value.len()) - }), - None => { - unsafe { ffi::ada_clear_port(self.0) } - Ok(()) - } + if let Some(value) = input { + setter_result(unsafe { ffi::ada_set_port(self.0, value.as_ptr().cast(), value.len()) }) + } else { + unsafe { ffi::ada_clear_port(self.0) } + Ok(()) } } @@ -420,6 +425,7 @@ impl Url { /// assert_eq!(url.hash(), "#row=4"); /// assert!(url.has_hash()); /// ``` + #[must_use] pub fn hash(&self) -> &str { unsafe { ffi::ada_get_hash(self.0) }.as_str() } @@ -450,6 +456,7 @@ impl Url { /// let url = Url::parse("https://127.0.0.1:8080/index.html", None).expect("Invalid URL"); /// assert_eq!(url.host(), "127.0.0.1:8080"); /// ``` + #[must_use] pub fn host(&self) -> &str { unsafe { ffi::ada_get_host(self.0) }.as_str() } @@ -468,7 +475,7 @@ impl Url { ffi::ada_set_host( self.0, input.unwrap_or("").as_ptr().cast(), - input.map_or(0, |i| i.len()), + input.map_or(0, str::len), ) }) } @@ -487,6 +494,7 @@ impl Url { /// let url = Url::parse("https://127.0.0.1:8080/index.html", None).expect("Invalid URL"); /// assert_eq!(url.hostname(), "127.0.0.1"); /// ``` + #[must_use] pub fn hostname(&self) -> &str { unsafe { ffi::ada_get_hostname(self.0) }.as_str() } @@ -505,7 +513,7 @@ impl Url { ffi::ada_set_hostname( self.0, input.unwrap_or("").as_ptr().cast(), - input.map_or(0, |i| i.len()), + input.map_or(0, str::len), ) }) } @@ -520,6 +528,7 @@ impl Url { /// let url = Url::parse("https://example.com/api/versions?page=2", None).expect("Invalid URL"); /// assert_eq!(url.pathname(), "/api/versions"); /// ``` + #[must_use] pub fn pathname(&self) -> &str { unsafe { ffi::ada_get_pathname(self.0) }.as_str() } @@ -538,7 +547,7 @@ impl Url { ffi::ada_set_pathname( self.0, input.unwrap_or("").as_ptr().cast(), - input.map_or(0, |i| i.len()), + input.map_or(0, str::len), ) }) } @@ -556,6 +565,7 @@ impl Url { /// let url = Url::parse("https://example.com/products", None).expect("Invalid URL"); /// assert_eq!(url.search(), ""); /// ``` + #[must_use] pub fn search(&self) -> &str { unsafe { ffi::ada_get_search(self.0) }.as_str() } @@ -572,7 +582,7 @@ impl Url { pub fn set_search(&mut self, input: Option<&str>) { match input { Some(value) => unsafe { - ffi::ada_set_search(self.0, value.as_ptr().cast(), value.len()) + ffi::ada_set_search(self.0, value.as_ptr().cast(), value.len()); }, None => unsafe { ffi::ada_clear_search(self.0) }, } @@ -588,6 +598,7 @@ impl Url { /// let url = Url::parse("file:///tmp/foo", None).expect("Invalid URL"); /// assert_eq!(url.protocol(), "file:"); /// ``` + #[must_use] pub fn protocol(&self) -> &str { unsafe { ffi::ada_get_protocol(self.0) }.as_str() } @@ -606,46 +617,55 @@ impl Url { } /// A URL includes credentials if its username or password is not the empty string. + #[must_use] pub fn has_credentials(&self) -> bool { unsafe { ffi::ada_has_credentials(self.0) } } /// Returns true if it has an host but it is the empty string. + #[must_use] pub fn has_empty_hostname(&self) -> bool { unsafe { ffi::ada_has_empty_hostname(self.0) } } /// Returns true if it has a host (included an empty host) + #[must_use] pub fn has_hostname(&self) -> bool { unsafe { ffi::ada_has_hostname(self.0) } } /// Returns true if URL has a non-empty username. + #[must_use] pub fn has_non_empty_username(&self) -> bool { unsafe { ffi::ada_has_non_empty_username(self.0) } } /// Returns true if URL has a non-empty password. + #[must_use] pub fn has_non_empty_password(&self) -> bool { unsafe { ffi::ada_has_non_empty_password(self.0) } } /// Returns true if URL has a port. + #[must_use] pub fn has_port(&self) -> bool { unsafe { ffi::ada_has_port(self.0) } } /// Returns true if URL has password. + #[must_use] pub fn has_password(&self) -> bool { unsafe { ffi::ada_has_password(self.0) } } /// Returns true if URL has a hash/fragment. + #[must_use] pub fn has_hash(&self) -> bool { unsafe { ffi::ada_has_hash(self.0) } } /// Returns true if URL has search/query. + #[must_use] pub fn has_search(&self) -> bool { unsafe { ffi::ada_has_search(self.0) } } @@ -653,11 +673,13 @@ impl Url { /// Returns the parsed version of the URL with all components. /// /// For more information, read [WHATWG URL spec](https://url.spec.whatwg.org/#dom-url-href) + #[must_use] pub fn as_str(&self) -> &str { self.href() } /// Returns the URL components of the instance. + #[must_use] pub fn components(&self) -> UrlComponents { unsafe { ffi::ada_get_components(self.0).as_ref().unwrap() }.into() } @@ -739,7 +761,7 @@ impl Ord for Url { impl hash::Hash for Url { fn hash(&self, state: &mut H) { - self.href().hash(state) + self.href().hash(state); } } From aac9b6c736484e0ffd467e83705d1348165b6056 Mon Sep 17 00:00:00 2001 From: Alex Povel Date: Wed, 20 Mar 2024 14:28:45 +0100 Subject: [PATCH 5/9] docs: Dedicated `examples/` Files in `examples/` will be compiled by `cargo test`. Hence, uncompilable code will be caught from now on. One can `cargo run --example simple` to see the `println!` output. This allows users to get started hacking quickly. --- README.md | 19 +++---------------- examples/simple.rs | 13 +++++++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 examples/simple.rs diff --git a/README.md b/README.md index 468a0dc..ee72148 100644 --- a/README.md +++ b/README.md @@ -8,22 +8,9 @@ It fully supports the relevant [Unicode Technical Standard](https://www.unicode. ### Usage -Here is an example illustrating a common usage: - -```Rust -use ada_url::Url; -fn main() -> Result<(), Box> { - let mut u = Url::parse("http://www.google:8080/love#drug", None).expect("bad url"); - println!("port: {:?}", u.port()); - println!("hash: {:?}", u.hash()); - println!("pathname: {:?}", u.pathname()); - println!("href: {:?}", u.href()); - u.set_port(Some("9999"))?; - println!("href: {:?}", u.href()); - - Ok(()) -} -``` +See [here](examples/simple.rs) for a usage example. +You can run it locally with `cargo run --example simple`. +Feel free to adjust it for exploring this crate further. #### Features diff --git a/examples/simple.rs b/examples/simple.rs new file mode 100644 index 0000000..1cbcb93 --- /dev/null +++ b/examples/simple.rs @@ -0,0 +1,13 @@ +use ada_url::Url; + +fn main() -> Result<(), Box> { + let mut u = Url::parse("http://www.google:8080/love#drug", None).expect("bad url"); + println!("port: {:?}", u.port()); + println!("hash: {:?}", u.hash()); + println!("pathname: {:?}", u.pathname()); + println!("href: {:?}", u.href()); + u.set_port(Some("9999"))?; + println!("href: {:?}", u.href()); + + Ok(()) +} From f9eaa6ca5feff76d779cb31c137de474127980ae Mon Sep 17 00:00:00 2001 From: Alex Povel Date: Wed, 20 Mar 2024 14:35:03 +0100 Subject: [PATCH 6/9] docs: Apply Markdown lints --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ee72148..22979bd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## WHATWG URL parser for Rust +# WHATWG URL parser for Rust Fast [WHATWG URL Specification](https://url.spec.whatwg.org) compliant URL parser for Rust. Well-tested and widely used by Node.js since [Node 18](https://nodejs.org/en/blog/release/v18.17.0). @@ -6,7 +6,7 @@ Well-tested and widely used by Node.js since [Node 18](https://nodejs.org/en/blo The Ada library passes the full range of tests from the specification, across a wide range of platforms (e.g., Windows, Linux, macOS). It fully supports the relevant [Unicode Technical Standard](https://www.unicode.org/reports/tr46/#ToUnicode). -### Usage +## Usage See [here](examples/simple.rs) for a usage example. You can run it locally with `cargo run --example simple`. @@ -27,7 +27,7 @@ Enabling this feature without `libc++` installed would cause compile error. Ada is fast. The benchmark below shows **3.34 times** faster URL parsing compared to `url` -``` +```text parse/ada_url time: [2.0790 µs 2.0812 µs 2.0835 µs] thrpt: [369.84 MiB/s 370.25 MiB/s 370.65 MiB/s] @@ -54,9 +54,9 @@ parse/url time: [6.9266 µs 6.9677 µs 7.0199 µs] | **[`Send`](https://doc.rust-lang.org/std/marker/trait.Send.html)** | Used to declare that the type can be transferred across thread boundaries. | | **[`Sync`](https://doc.rust-lang.org/stable/std/marker/trait.Sync.html)** | Used to declare that the type is thread-safe. | -### Development +## Development -#### `justfile` +### `justfile` The [`justfile`](./justfile) contains commands (called "recipes") that can be executed by [just](https://github.com/casey/just) for convenience. @@ -72,7 +72,7 @@ just all just all --skip=libcpp,serde ``` -### License +## License This code is made available under the Apache License 2.0 as well as the MIT license. From 0657c521242a35e22ca18e9f74afa6b7e7e0f3c6 Mon Sep 17 00:00:00 2001 From: Alex Povel Date: Wed, 20 Mar 2024 15:10:04 +0100 Subject: [PATCH 7/9] fix: `SetterError` is `no_std` friendly Now passes `just all` --- examples/simple.rs | 23 ++++++++++++++++------- src/lib.rs | 3 +-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index 1cbcb93..7dcafc9 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,13 +1,22 @@ use ada_url::Url; fn main() -> Result<(), Box> { - let mut u = Url::parse("http://www.google:8080/love#drug", None).expect("bad url"); - println!("port: {:?}", u.port()); - println!("hash: {:?}", u.hash()); - println!("pathname: {:?}", u.pathname()); - println!("href: {:?}", u.href()); - u.set_port(Some("9999"))?; - println!("href: {:?}", u.href()); + let url = Url::parse("http://www.google:8080/love#drug", None).expect("bad url"); + + println!("port: {:?}", url.port()); + println!("hash: {:?}", url.hash()); + println!("pathname: {:?}", url.pathname()); + println!("href: {:?}", url.href()); + + let mut url = url; + + #[cfg(feature = "std")] + url.set_port(Some("9999"))?; + + #[cfg(not(feature = "std"))] + url.set_port(Some("9999")).unwrap(); + + println!("href: {:?}", url.href()); Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index edf9f6f..4bdd019 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -180,10 +180,9 @@ impl From<*mut ffi::ada_url> for Url { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Display)] +#[cfg_attr(feature = "std", derive(derive_more::Error))] // error still requires std: https://github.com/rust-lang/rust/issues/103765 pub struct SetterError; -impl std::error::Error for SetterError {} - type SetterResult = Result<(), SetterError>; #[inline] From e9e48974da78f13b9772a5c2d60fe3926874115a Mon Sep 17 00:00:00 2001 From: Alex Povel Date: Wed, 20 Mar 2024 15:10:19 +0100 Subject: [PATCH 8/9] docs: Apply Markdown lint --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 22979bd..935a064 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ See [here](examples/simple.rs) for a usage example. You can run it locally with `cargo run --example simple`. Feel free to adjust it for exploring this crate further. -#### Features +### Features **std:** Functionalities that require `std`. This feature is enabled by default, set `no-default-features` to `true` if you want `no-std`. From c7db138edd9254832fe4010e8a0595c2146b1ec1 Mon Sep 17 00:00:00 2001 From: Alex Povel Date: Thu, 21 Mar 2024 13:18:40 +0100 Subject: [PATCH 9/9] chore: Undo `Error` for `SetterResult` --- examples/simple.rs | 12 ++---------- src/lib.rs | 16 ++++++++++------ 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index 7dcafc9..e6dbfe4 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,6 +1,6 @@ use ada_url::Url; -fn main() -> Result<(), Box> { +fn main() { let url = Url::parse("http://www.google:8080/love#drug", None).expect("bad url"); println!("port: {:?}", url.port()); @@ -9,14 +9,6 @@ fn main() -> Result<(), Box> { println!("href: {:?}", url.href()); let mut url = url; - - #[cfg(feature = "std")] - url.set_port(Some("9999"))?; - - #[cfg(not(feature = "std"))] - url.set_port(Some("9999")).unwrap(); - + url.set_port(Some("9999")).expect("bad port"); println!("href: {:?}", url.href()); - - Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 4bdd019..7df43f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -179,18 +179,14 @@ impl From<*mut ffi::ada_url> for Url { } } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Display)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] // error still requires std: https://github.com/rust-lang/rust/issues/103765 -pub struct SetterError; - -type SetterResult = Result<(), SetterError>; +type SetterResult = Result<(), ()>; #[inline] const fn setter_result(successful: bool) -> SetterResult { if successful { Ok(()) } else { - Err(SetterError) + Err(()) } } @@ -299,6 +295,7 @@ impl Url { /// url.set_href("https://lemire.me").unwrap(); /// assert_eq!(url.href(), "https://lemire.me/"); /// ``` + #[allow(clippy::result_unit_err)] pub fn set_href(&mut self, input: &str) -> SetterResult { setter_result(unsafe { ffi::ada_set_href(self.0, input.as_ptr().cast(), input.len()) }) } @@ -327,6 +324,7 @@ impl Url { /// url.set_username(Some("username")).unwrap(); /// assert_eq!(url.href(), "https://username@yagiz.co/"); /// ``` + #[allow(clippy::result_unit_err)] pub fn set_username(&mut self, input: Option<&str>) -> SetterResult { setter_result(unsafe { ffi::ada_set_username( @@ -361,6 +359,7 @@ impl Url { /// url.set_password(Some("password")).unwrap(); /// assert_eq!(url.href(), "https://:password@yagiz.co/"); /// ``` + #[allow(clippy::result_unit_err)] pub fn set_password(&mut self, input: Option<&str>) -> SetterResult { setter_result(unsafe { ffi::ada_set_password( @@ -398,6 +397,7 @@ impl Url { /// url.set_port(Some("8080")).unwrap(); /// assert_eq!(url.href(), "https://yagiz.co:8080/"); /// ``` + #[allow(clippy::result_unit_err)] pub fn set_port(&mut self, input: Option<&str>) -> SetterResult { if let Some(value) = input { setter_result(unsafe { ffi::ada_set_port(self.0, value.as_ptr().cast(), value.len()) }) @@ -469,6 +469,7 @@ impl Url { /// url.set_host(Some("localhost:3000")).unwrap(); /// assert_eq!(url.href(), "https://localhost:3000/"); /// ``` + #[allow(clippy::result_unit_err)] pub fn set_host(&mut self, input: Option<&str>) -> SetterResult { setter_result(unsafe { ffi::ada_set_host( @@ -507,6 +508,7 @@ impl Url { /// url.set_hostname(Some("localhost")).unwrap(); /// assert_eq!(url.href(), "https://localhost/"); /// ``` + #[allow(clippy::result_unit_err)] pub fn set_hostname(&mut self, input: Option<&str>) -> SetterResult { setter_result(unsafe { ffi::ada_set_hostname( @@ -541,6 +543,7 @@ impl Url { /// url.set_pathname(Some("/contact")).unwrap(); /// assert_eq!(url.href(), "https://yagiz.co/contact"); /// ``` + #[allow(clippy::result_unit_err)] pub fn set_pathname(&mut self, input: Option<&str>) -> SetterResult { setter_result(unsafe { ffi::ada_set_pathname( @@ -611,6 +614,7 @@ impl Url { /// url.set_protocol("http").unwrap(); /// assert_eq!(url.href(), "http://yagiz.co/"); /// ``` + #[allow(clippy::result_unit_err)] pub fn set_protocol(&mut self, input: &str) -> SetterResult { setter_result(unsafe { ffi::ada_set_protocol(self.0, input.as_ptr().cast(), input.len()) }) }