ada_url/
ffi.rs

1#![allow(non_camel_case_types)]
2use core::ffi::{c_char, c_uint};
3
4#[cfg(feature = "std")]
5extern crate std;
6
7#[cfg(feature = "std")]
8use std::fmt::Display;
9
10#[repr(C)]
11pub struct ada_url {
12    _unused: [u8; 0],
13    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
14}
15
16#[repr(C)]
17pub struct ada_url_search_params {
18    _unused: [u8; 0],
19    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
20}
21
22#[repr(C)]
23pub struct ada_string {
24    pub data: *const c_char,
25    pub length: usize,
26}
27
28impl ada_string {
29    #[must_use]
30    pub const fn as_str(&self) -> &'static str {
31        // We need to handle length 0 since data will be `nullptr`
32        // Not handling will result in a panic due to core::slice::from_raw_parts
33        // implementation
34        if self.length == 0 {
35            return "";
36        }
37        unsafe {
38            let slice = core::slice::from_raw_parts(self.data.cast(), self.length);
39            core::str::from_utf8_unchecked(slice)
40        }
41    }
42}
43
44#[repr(C)]
45pub struct ada_owned_string {
46    pub data: *const c_char,
47    pub length: usize,
48}
49
50impl AsRef<str> for ada_owned_string {
51    fn as_ref(&self) -> &str {
52        // We need to handle length 0 since data will be `nullptr`
53        // Not handling will result in a panic due to core::slice::from_raw_parts
54        // implementation
55        if self.length == 0 {
56            return "";
57        }
58        unsafe {
59            let slice = core::slice::from_raw_parts(self.data.cast(), self.length);
60            core::str::from_utf8_unchecked(slice)
61        }
62    }
63}
64
65#[cfg(feature = "std")]
66impl Display for ada_owned_string {
67    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
68        write!(f, "{}", self.as_ref().to_owned())
69    }
70}
71
72impl Drop for ada_owned_string {
73    fn drop(&mut self) {
74        // @note This is needed because ada_free_owned_string accepts by value
75        let copy = ada_owned_string {
76            data: self.data,
77            length: self.length,
78        };
79        unsafe {
80            ada_free_owned_string(copy);
81        };
82    }
83}
84
85/// Represents an std::vector<std::string>
86#[repr(C)]
87pub struct ada_strings {
88    _unused: [u8; 0],
89    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
90}
91
92#[repr(C)]
93pub struct ada_url_search_params_keys_iter {
94    _unused: [u8; 0],
95    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
96}
97
98#[repr(C)]
99pub struct ada_url_search_params_values_iter {
100    _unused: [u8; 0],
101    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
102}
103
104#[repr(C)]
105pub struct ada_url_search_params_entries_iter {
106    _unused: [u8; 0],
107    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
108}
109
110/// Represents a key/value pair of strings
111#[repr(C)]
112pub struct ada_string_pair {
113    pub key: ada_string,
114    pub value: ada_string,
115}
116
117#[repr(C)]
118pub struct ada_url_components {
119    pub protocol_end: u32,
120    pub username_end: u32,
121    pub host_start: u32,
122    pub host_end: u32,
123    pub port: u32,
124    pub pathname_start: u32,
125    pub search_start: u32,
126    pub hash_start: u32,
127}
128
129unsafe extern "C" {
130    pub fn ada_parse(input: *const c_char, length: usize) -> *mut ada_url;
131    pub fn ada_parse_with_base(
132        input: *const c_char,
133        input_length: usize,
134        base: *const c_char,
135        base_length: usize,
136    ) -> *mut ada_url;
137    pub fn ada_free(url: *mut ada_url);
138    pub fn ada_free_owned_string(url: ada_owned_string);
139    pub fn ada_copy(url: *mut ada_url) -> *mut ada_url;
140    pub fn ada_is_valid(url: *mut ada_url) -> bool;
141    pub fn ada_can_parse(url: *const c_char, length: usize) -> bool;
142    pub fn ada_can_parse_with_base(
143        input: *const c_char,
144        input_length: usize,
145        base: *const c_char,
146        base_length: usize,
147    ) -> bool;
148    pub fn ada_get_components(url: *mut ada_url) -> *mut ada_url_components;
149
150    // Getters
151    pub fn ada_get_origin(url: *mut ada_url) -> ada_owned_string;
152    pub fn ada_get_href(url: *mut ada_url) -> ada_string;
153    pub fn ada_get_username(url: *mut ada_url) -> ada_string;
154    pub fn ada_get_password(url: *mut ada_url) -> ada_string;
155    pub fn ada_get_port(url: *mut ada_url) -> ada_string;
156    pub fn ada_get_hash(url: *mut ada_url) -> ada_string;
157    pub fn ada_get_host(url: *mut ada_url) -> ada_string;
158    pub fn ada_get_hostname(url: *mut ada_url) -> ada_string;
159    pub fn ada_get_pathname(url: *mut ada_url) -> ada_string;
160    pub fn ada_get_search(url: *mut ada_url) -> ada_string;
161    pub fn ada_get_protocol(url: *mut ada_url) -> ada_string;
162    pub fn ada_get_host_type(url: *mut ada_url) -> c_uint;
163    pub fn ada_get_scheme_type(url: *mut ada_url) -> c_uint;
164
165    // Setters
166    pub fn ada_set_href(url: *mut ada_url, input: *const c_char, length: usize) -> bool;
167    pub fn ada_set_username(url: *mut ada_url, input: *const c_char, length: usize) -> bool;
168    pub fn ada_set_password(url: *mut ada_url, input: *const c_char, length: usize) -> bool;
169    pub fn ada_set_port(url: *mut ada_url, input: *const c_char, length: usize) -> bool;
170    pub fn ada_set_hash(url: *mut ada_url, input: *const c_char, length: usize);
171    pub fn ada_set_host(url: *mut ada_url, input: *const c_char, length: usize) -> bool;
172    pub fn ada_set_hostname(url: *mut ada_url, input: *const c_char, length: usize) -> bool;
173    pub fn ada_set_pathname(url: *mut ada_url, input: *const c_char, length: usize) -> bool;
174    pub fn ada_set_search(url: *mut ada_url, input: *const c_char, length: usize);
175    pub fn ada_set_protocol(url: *mut ada_url, input: *const c_char, length: usize) -> bool;
176
177    // Clear methods
178    pub fn ada_clear_search(url: *mut ada_url);
179    pub fn ada_clear_hash(url: *mut ada_url);
180    pub fn ada_clear_port(url: *mut ada_url);
181
182    // Validators
183    pub fn ada_has_credentials(url: *mut ada_url) -> bool;
184    pub fn ada_has_empty_hostname(url: *mut ada_url) -> bool;
185    pub fn ada_has_hostname(url: *mut ada_url) -> bool;
186    pub fn ada_has_non_empty_username(url: *mut ada_url) -> bool;
187    pub fn ada_has_non_empty_password(url: *mut ada_url) -> bool;
188    pub fn ada_has_port(url: *mut ada_url) -> bool;
189    pub fn ada_has_password(url: *mut ada_url) -> bool;
190    pub fn ada_has_hash(url: *mut ada_url) -> bool;
191    pub fn ada_has_search(url: *mut ada_url) -> bool;
192
193    // IDNA methods
194    pub fn ada_idna_to_unicode(input: *const c_char, length: usize) -> ada_owned_string;
195    pub fn ada_idna_to_ascii(input: *const c_char, length: usize) -> ada_owned_string;
196
197    // URLSearchParams
198    pub fn ada_parse_search_params(
199        input: *const c_char,
200        length: usize,
201    ) -> *mut ada_url_search_params;
202    pub fn ada_free_search_params(search_params: *mut ada_url_search_params);
203    pub fn ada_search_params_size(search_params: *mut ada_url_search_params) -> usize;
204    pub fn ada_search_params_sort(search_params: *mut ada_url_search_params);
205    pub fn ada_search_params_to_string(
206        search_params: *mut ada_url_search_params,
207    ) -> ada_owned_string;
208    pub fn ada_search_params_append(
209        search_params: *mut ada_url_search_params,
210        name: *const c_char,
211        name_length: usize,
212        value: *const c_char,
213        value_length: usize,
214    );
215    pub fn ada_search_params_set(
216        search_params: *mut ada_url_search_params,
217        name: *const c_char,
218        name_length: usize,
219        value: *const c_char,
220        value_length: usize,
221    );
222    pub fn ada_search_params_remove(
223        search_params: *mut ada_url_search_params,
224        name: *const c_char,
225        name_length: usize,
226    );
227    pub fn ada_search_params_remove_value(
228        search_params: *mut ada_url_search_params,
229        name: *const c_char,
230        name_length: usize,
231        value: *const c_char,
232        value_length: usize,
233    );
234    pub fn ada_search_params_has(
235        search_params: *mut ada_url_search_params,
236        name: *const c_char,
237        name_length: usize,
238    ) -> bool;
239    pub fn ada_search_params_has_value(
240        search_params: *mut ada_url_search_params,
241        name: *const c_char,
242        name_length: usize,
243        value: *const c_char,
244        value_length: usize,
245    ) -> bool;
246    pub fn ada_search_params_get(
247        search_params: *mut ada_url_search_params,
248        key: *const c_char,
249        key_length: usize,
250    ) -> ada_string;
251    pub fn ada_search_params_get_all(
252        // not implemented
253        search_params: *mut ada_url_search_params,
254        key: *const c_char,
255        key_length: usize,
256    ) -> *mut ada_strings;
257    pub fn ada_search_params_get_keys(
258        search_params: *mut ada_url_search_params,
259    ) -> *mut ada_url_search_params_keys_iter;
260    pub fn ada_search_params_get_values(
261        search_params: *mut ada_url_search_params,
262    ) -> *mut ada_url_search_params_values_iter;
263    pub fn ada_search_params_get_entries(
264        search_params: *mut ada_url_search_params,
265    ) -> *mut ada_url_search_params_entries_iter;
266
267    pub fn ada_free_strings(strings: *mut ada_strings);
268    pub fn ada_strings_size(strings: *mut ada_strings) -> usize;
269    pub fn ada_strings_get(strings: *mut ada_strings, index: usize) -> ada_string;
270    pub fn ada_free_search_params_keys_iter(iter: *mut ada_url_search_params_keys_iter);
271    pub fn ada_search_params_keys_iter_next(
272        iter: *mut ada_url_search_params_keys_iter,
273    ) -> ada_string;
274    pub fn ada_search_params_keys_iter_has_next(iter: *mut ada_url_search_params_keys_iter)
275    -> bool;
276
277    pub fn ada_free_search_params_values_iter(iter: *mut ada_url_search_params_values_iter);
278    pub fn ada_search_params_values_iter_next(
279        iter: *mut ada_url_search_params_values_iter,
280    ) -> ada_string;
281    pub fn ada_search_params_values_iter_has_next(
282        iter: *mut ada_url_search_params_values_iter,
283    ) -> bool;
284
285    pub fn ada_free_search_params_entries_iter(iter: *mut ada_url_search_params_entries_iter);
286    pub fn ada_search_params_entries_iter_next(
287        iter: *mut ada_url_search_params_entries_iter,
288    ) -> ada_string_pair;
289    pub fn ada_search_params_entries_iter_has_next(
290        iter: *mut ada_url_search_params_entries_iter,
291    ) -> bool;
292}
293
294#[cfg(test)]
295mod tests {
296    use crate::ffi;
297
298    #[test]
299    fn ada_free_owned_string_works() {
300        let str = "meßagefactory.ca";
301        let result = unsafe { ffi::ada_idna_to_ascii(str.as_ptr().cast(), str.len()) };
302        assert_eq!(result.as_ref(), "xn--meagefactory-m9a.ca");
303        unsafe { ffi::ada_free_owned_string(result) };
304    }
305}