diff --git a/src/ffi.rs b/src/ffi.rs index 749a450..94fc93f 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1,6 +1,9 @@ #![allow(non_camel_case_types)] use core::ffi::{c_char, c_uint}; +#[cfg(feature = "std")] +extern crate std; + #[repr(C)] pub struct ada_url { _unused: [u8; 0], @@ -38,6 +41,26 @@ impl AsRef for ada_owned_string { } } +#[cfg(feature = "std")] +impl ToString for ada_owned_string { + fn to_string(&self) -> std::string::String { + self.as_ref().to_owned() + } +} + +impl Drop for ada_owned_string { + fn drop(&mut self) { + // @note This is needed because ada_free_owned_string accepts by value + let copy = ada_owned_string { + data: self.data, + length: self.length, + }; + unsafe { + ada_free_owned_string(copy); + }; + } +} + #[repr(C)] pub struct ada_url_components { pub protocol_end: u32, diff --git a/src/idna.rs b/src/idna.rs index 9f035a4..d6d6832 100644 --- a/src/idna.rs +++ b/src/idna.rs @@ -1,5 +1,12 @@ +#[cfg(feature = "std")] +extern crate std; + +#[cfg_attr(not(feature = "std"), allow(unused_imports))] use crate::ffi; +#[cfg(feature = "std")] +use std::string::String; + /// 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) @@ -16,12 +23,9 @@ impl 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()); - let slice = core::slice::from_raw_parts(out.data.cast(), out.length); - core::str::from_utf8_unchecked(slice) - } + #[cfg(feature = "std")] + pub fn unicode(input: &str) -> String { + unsafe { ffi::ada_idna_to_unicode(input.as_ptr().cast(), input.len()) }.to_string() } /// Process international domains according to the UTS #46 standard. @@ -34,26 +38,26 @@ impl 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()); - let slice = core::slice::from_raw_parts(out.data.cast(), out.length); - core::str::from_utf8_unchecked(slice) - } + #[cfg(feature = "std")] + pub fn ascii(input: &str) -> String { + unsafe { ffi::ada_idna_to_ascii(input.as_ptr().cast(), input.len()) }.to_string() } } #[cfg(test)] mod tests { + #[cfg_attr(not(feature = "std"), allow(unused_imports))] use crate::idna::*; #[test] fn unicode_should_work() { + #[cfg(feature = "std")] assert_eq!(Idna::unicode("xn--meagefactory-m9a.ca"), "meßagefactory.ca"); } #[test] fn ascii_should_work() { + #[cfg(feature = "std")] assert_eq!(Idna::ascii("meßagefactory.ca"), "xn--meagefactory-m9a.ca"); } } diff --git a/src/lib.rs b/src/lib.rs index 1bdd2ef..8199db8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,6 +46,12 @@ pub mod ffi; mod idna; pub use idna::Idna; +#[cfg(feature = "std")] +extern crate std; + +#[cfg(feature = "std")] +use std::string::String; + use core::{borrow, ffi::c_uint, fmt, hash, ops}; use derive_more::Display; @@ -270,12 +276,9 @@ impl Url { /// assert_eq!(url.origin(), "https://example.com"); /// ``` #[must_use] - pub fn origin(&self) -> &str { - unsafe { - let out = ffi::ada_get_origin(self.0); - let slice = core::slice::from_raw_parts(out.data.cast(), out.length); - core::str::from_utf8_unchecked(slice) - } + #[cfg(feature = "std")] + pub fn origin(&self) -> String { + unsafe { ffi::ada_get_origin(self.0) }.to_string() } /// Return the parsed version of the URL with all components. @@ -949,7 +952,10 @@ mod test { None, ) .expect("Should have parsed a simple url"); + + #[cfg(feature = "std")] assert_eq!(out.origin(), "https://google.com:9090"); + assert_eq!( out.href(), "https://username:password@google.com:9090/search?query#hash"