Skip to content

Commit 28028b1

Browse files
committed
feat: add getters for now
1 parent c8cdf5c commit 28028b1

File tree

4 files changed

+191
-27
lines changed

4 files changed

+191
-27
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ license = "MIT AND APACHE-2.0"
1010
exclude = [".github"]
1111

1212
[dependencies]
13-
cxx = "1.0"
13+
thiserror = "1"
1414

1515
[build-dependencies]
16-
cxx-build = "1.0"
16+
cc = { version = "1.0", features = ["parallel"] }

build.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
1+
use std::env;
2+
13
fn main() {
2-
println!("cargo:rerun-if-changed=src/lib.rs");
3-
println!("cargo:rerun-if-changed=src/binding.rs");
4+
println!("cargo:rerun-if-changed=deps/ada.cpp");
45
println!("cargo:rerun-if-changed=deps/ada.h");
6+
println!("cargo:rerun-if-changed=deps/ada_c.h");
7+
8+
let mut build = cc::Build::new();
9+
build
10+
.file("./deps/ada.cpp")
11+
.file("./deps/ada.h")
12+
.include("./deps/ada_c.h");
13+
14+
let compile_target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS");
15+
let compile_target_env = env::var("CARGO_CFG_TARGET_ENV").expect("CARGO_CFG_TARGET_ENV");
16+
if !(compile_target_os == "windows" && compile_target_env == "msvc") {
17+
build.compiler("clang++");
18+
build.cpp_set_stdlib("c++").flag("-std=c++17");
19+
println!("cargo:rustc-link-lib=c++");
20+
} else {
21+
build.flag("/std:c++17").static_crt(true);
22+
}
523

6-
cxx_build::bridge("src/binding.rs")
7-
.file("deps/ada.cpp")
8-
.flag_if_supported("-std=c++17")
9-
.compile("ada");
24+
build.compile("ada");
1025
}

src/binding.rs

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/lib.rs

Lines changed: 168 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,168 @@
1-
mod binding;
1+
use std::{ptr, mem};
2+
use thiserror::Error;
3+
4+
pub mod ffi {
5+
use std::ffi::c_char;
6+
7+
#[repr(C)]
8+
pub struct ada_url {
9+
_unused: [u8; 0],
10+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
11+
}
12+
13+
#[repr(C)]
14+
pub struct ada_string {
15+
pub data: *const c_char,
16+
pub length: usize,
17+
}
18+
19+
impl AsRef<str> for ada_string {
20+
fn as_ref(&self) -> &str {
21+
unsafe {
22+
let slice = std::slice::from_raw_parts(self.data.cast(), self.length);
23+
std::str::from_utf8_unchecked(slice)
24+
}
25+
}
26+
}
27+
28+
#[repr(C)]
29+
pub struct ada_owned_string {
30+
pub data: *const c_char,
31+
pub length: usize,
32+
}
33+
34+
impl AsRef<str> for ada_owned_string {
35+
fn as_ref(&self) -> &str {
36+
unsafe {
37+
let slice = std::slice::from_raw_parts(self.data.cast(), self.length);
38+
std::str::from_utf8_unchecked(slice)
39+
}
40+
}
41+
}
42+
43+
#[repr(C)]
44+
pub struct url_components {
45+
pub protocol_end: u32,
46+
pub username_end: u32,
47+
pub host_start: u32,
48+
pub host_end: u32,
49+
pub port: u32,
50+
pub pathname_start: u32,
51+
pub search_start: u32,
52+
pub hash_start: u32,
53+
}
54+
55+
extern "C" {
56+
pub fn ada_parse(url: *const c_char) -> ada_url;
57+
pub fn ada_free(url: *mut ada_url);
58+
pub fn ada_free_owned_string(url: *mut ada_owned_string);
59+
pub fn ada_is_valid(url: *mut ada_url) -> bool;
60+
pub fn ada_can_parse(url: *const c_char, base: *const c_char) -> bool;
61+
pub fn ada_get_origin(url: *mut ada_url) -> ada_owned_string;
62+
pub fn ada_get_href(url: *mut ada_url) -> ada_string;
63+
pub fn ada_get_username(url: *mut ada_url) -> ada_string;
64+
pub fn ada_get_password(url: *mut ada_url) -> ada_string;
65+
pub fn ada_get_port(url: *mut ada_url) -> ada_string;
66+
pub fn ada_get_hash(url: *mut ada_url) -> ada_string;
67+
pub fn ada_get_host(url: *mut ada_url) -> ada_string;
68+
pub fn ada_get_hostname(url: *mut ada_url) -> ada_string;
69+
pub fn ada_get_pathname(url: *mut ada_url) -> ada_string;
70+
pub fn ada_get_search(url: *mut ada_url) -> ada_string;
71+
pub fn ada_get_protocol(url: *mut ada_url) -> ada_string;
72+
}
73+
}
74+
75+
#[derive(Error, Debug)]
76+
pub enum Error {
77+
#[error("Invalid url: \"{0}\"")]
78+
ParseUrl(String),
79+
}
80+
81+
pub struct Url {
82+
origin: Option<*mut ffi::ada_owned_string>,
83+
url: *mut ffi::ada_url,
84+
}
85+
86+
impl Drop for Url {
87+
fn drop(&mut self) {
88+
unsafe {
89+
if let Some(origin) = self.origin {
90+
ffi::ada_free_owned_string(origin);
91+
}
92+
ffi::ada_free(self.url);
93+
}
94+
}
95+
}
96+
97+
impl Url {
98+
pub fn can_parse(input: &str, base: Option<&str>) -> bool {
99+
unsafe {
100+
ffi::ada_can_parse(
101+
input.as_ptr().cast(),
102+
base.unwrap_or_else(ptr::null()).as_ptr().cast(),
103+
)
104+
}
105+
}
106+
107+
pub fn origin(&mut self) -> &str {
108+
unsafe {
109+
self.origin = ffi::ada_get_origin(self.url);
110+
return self.origin.as_ref();
111+
}
112+
}
113+
114+
pub fn href(&self) -> &str {
115+
unsafe { ffi::ada_get_href(self.url).as_ref() }
116+
}
117+
118+
pub fn username(&self) -> &str {
119+
unsafe { ffi::ada_get_username(self.url).as_ref() }
120+
}
121+
122+
pub fn password(&self) -> &str {
123+
unsafe { ffi::ada_get_password(self.url).as_ref() }
124+
}
125+
126+
pub fn port(&self) -> &str {
127+
unsafe { ffi::ada_get_port(self.url).as_ref() }
128+
}
129+
130+
pub fn hash(&self) -> &str {
131+
unsafe { ffi::ada_get_hash(self.url).as_ref() }
132+
}
133+
134+
pub fn host(&self) -> &str {
135+
unsafe { ffi::ada_get_host(self.url).as_ref() }
136+
}
137+
138+
pub fn hostname(&self) -> &str {
139+
unsafe { ffi::ada_get_hostname(self.url).as_ref() }
140+
}
141+
142+
pub fn pathname(&self) -> &str {
143+
unsafe { ffi::ada_get_pathname(self.url).as_ref() }
144+
}
145+
146+
pub fn search(&self) -> &str {
147+
unsafe { ffi::ada_get_search(self.url).as_ref() }
148+
}
149+
150+
pub fn protocol(&self) -> &str {
151+
unsafe { ffi::ada_get_protocol(self.url).as_ref() }
152+
}
153+
}
154+
155+
pub fn parse<U: AsRef<str>>(url: U) -> Result<Url, Error> {
156+
unsafe {
157+
let url_aggregator = ffi::ada_parse(url.as_ref().as_ptr().cast());
158+
159+
if ffi::ada_is_valid(url_aggregator) {
160+
Ok(Url {
161+
origin: None,
162+
url: url_aggregator,
163+
})
164+
} else {
165+
Err(Error::ParseUrl(url.as_ref().to_owned()))
166+
}
167+
}
168+
}

0 commit comments

Comments
 (0)