1use cxx::{type_id, ExternType};
6use std::fmt;
7use std::mem::MaybeUninit;
8
9#[cxx::bridge]
10mod ffi {
11 unsafe extern "C++" {
12 include!("cxx-qt-lib/qbytearray.h");
13 type QByteArray = crate::QByteArray;
14 include!("cxx-qt-lib/qstring.h");
15 type QString = crate::QString;
16 include!("cxx-qt-lib/qstringlist.h");
17 type QStringList = crate::QStringList;
18 include!("cxx-qt-lib/qurl.h");
19 type QUrl = super::QUrl;
20
21 fn clear(self: &mut QUrl);
24
25 #[rust_name = "error_string"]
28 fn errorString(self: &QUrl) -> QString;
29
30 #[rust_name = "has_fragment"]
32 fn hasFragment(self: &QUrl) -> bool;
33
34 #[rust_name = "has_query"]
36 fn hasQuery(self: &QUrl) -> bool;
37
38 #[rust_name = "is_empty"]
40 fn isEmpty(self: &QUrl) -> bool;
41
42 #[rust_name = "is_local_file"]
44 fn isLocalFile(self: &QUrl) -> bool;
45
46 #[rust_name = "is_parent_of"]
50 fn isParentOf(self: &QUrl, child_url: &QUrl) -> bool;
51
52 #[rust_name = "is_relative"]
56 fn isRelative(self: &QUrl) -> bool;
57
58 #[rust_name = "is_valid"]
60 fn isValid(self: &QUrl) -> bool;
61
62 #[rust_name = "port_or"]
64 fn port(self: &QUrl, port: i32) -> i32;
65
66 fn resolved(self: &QUrl, relative: &QUrl) -> QUrl;
68
69 #[rust_name = "scheme_or_default"]
76 fn scheme(self: &QUrl) -> QString;
77
78 #[rust_name = "set_port"]
82 fn setPort(self: &mut QUrl, port: i32);
83
84 #[rust_name = "to_local_file_or_default"]
87 fn toLocalFile(self: &QUrl) -> QString;
88 }
89
90 #[namespace = "rust::cxxqtlib1"]
92 unsafe extern "C++" {
93 #[doc(hidden)]
94 #[rust_name = "qurl_init_from_string"]
95 fn qurlInitFromString(string: &str) -> QUrl;
96 #[doc(hidden)]
97 #[rust_name = "qurl_to_rust_string"]
98 fn qurlToRustString(url: &QUrl) -> String;
99
100 #[rust_name = "qurl_authority"]
101 fn qurlAuthority(url: &QUrl) -> QString;
102 #[rust_name = "qurl_file_name"]
103 fn qurlFileName(url: &QUrl) -> QString;
104 #[rust_name = "qurl_fragment"]
105 fn qurlFragment(url: &QUrl) -> QString;
106 #[rust_name = "qurl_from_encoded"]
107 fn qurlFromEncoded(input: &QByteArray) -> QUrl;
108 #[rust_name = "qurl_from_local_file"]
109 fn qurlFromLocalFile(local_file: &QString) -> QUrl;
110 #[rust_name = "qurl_from_percent_encoding"]
111 fn qurlFromPercentEncoding(input: &QByteArray) -> QString;
112 #[rust_name = "qurl_from_user_input"]
113 fn qurlFromUserInput(user_input: &QString, working_directory: &QString) -> QUrl;
114 #[rust_name = "qurl_host"]
115 fn qurlHost(url: &QUrl) -> QString;
116 #[rust_name = "qurl_idn_whitelist"]
117 fn qurlIdnWhitelist() -> QStringList;
118 #[rust_name = "qurl_path"]
119 fn qurlPath(url: &QUrl) -> QString;
120 #[rust_name = "qurl_password"]
121 fn qurlPassword(url: &QUrl) -> QString;
122 #[rust_name = "qurl_query"]
123 fn qurlQuery(url: &QUrl) -> QString;
124 #[rust_name = "qurl_set_authority"]
125 fn qurlSetAuthority(url: &mut QUrl, authority: &QString);
126 #[rust_name = "qurl_set_fragment"]
127 fn qurlSetFragment(url: &mut QUrl, fragment: &QString);
128 #[rust_name = "qurl_set_host"]
129 fn qurlSetHost(url: &mut QUrl, host: &QString);
130 #[rust_name = "qurl_set_idn_whitelist"]
131 fn qurlSetIdnWhitelist(list: &QStringList);
132 #[rust_name = "qurl_set_password"]
133 fn qurlSetPassword(url: &mut QUrl, password: &QString);
134 #[rust_name = "qurl_set_path"]
135 fn qurlSetPath(url: &mut QUrl, path: &QString);
136 #[rust_name = "qurl_set_query"]
137 fn qurlSetQuery(url: &mut QUrl, query: &QString);
138 #[rust_name = "qurl_set_scheme"]
139 fn qurlSetScheme(url: &mut QUrl, scheme: &QString);
140 #[rust_name = "qurl_set_url"]
141 fn qurlSetUrl(url: &mut QUrl, new_url: &QString);
142 #[rust_name = "qurl_set_user_info"]
143 fn qurlSetUserInfo(url: &mut QUrl, user_info: &QString);
144 #[rust_name = "qurl_set_user_name"]
145 fn qurlSetUserName(url: &mut QUrl, user_name: &QString);
146 #[rust_name = "qurl_to_display_string"]
147 fn qurlToDisplayString(url: &QUrl) -> QString;
148 #[rust_name = "qurl_to_encoded"]
149 fn qurlToEncoded(url: &QUrl) -> QByteArray;
150 #[rust_name = "qurl_to_percent_encoding"]
151 fn qurlToPercentEncoding(
152 input: &QString,
153 exclude: &QByteArray,
154 include: &QByteArray,
155 ) -> QByteArray;
156 #[doc(hidden)]
157 #[rust_name = "qurl_to_qstring"]
158 fn qurlToQString(url: &QUrl) -> QString;
159 #[rust_name = "qurl_user_info"]
160 fn qurlUserInfo(url: &QUrl) -> QString;
161 #[rust_name = "qurl_user_name"]
162 fn qurlUserName(url: &QUrl) -> QString;
163 }
164
165 #[namespace = "rust::cxxqtlib1"]
166 unsafe extern "C++" {
167 include!("cxx-qt-lib/common.h");
168
169 #[doc(hidden)]
170 #[rust_name = "qurl_drop"]
171 fn drop(url: &mut QUrl);
172
173 #[doc(hidden)]
174 #[rust_name = "qurl_init_default"]
175 fn construct() -> QUrl;
176 #[doc(hidden)]
177 #[rust_name = "qurl_init_from_qstring"]
178 fn construct(string: &QString) -> QUrl;
179 #[doc(hidden)]
180 #[rust_name = "qurl_init_from_qurl"]
181 fn construct(url: &QUrl) -> QUrl;
182
183 #[doc(hidden)]
184 #[rust_name = "qurl_eq"]
185 fn operatorEq(a: &QUrl, b: &QUrl) -> bool;
186
187 #[doc(hidden)]
188 #[rust_name = "qurl_debug"]
189 fn toQString(url: &QUrl) -> QString;
190 }
191}
192
193#[repr(C)]
195pub struct QUrl {
196 _space: MaybeUninit<usize>,
197}
198
199impl QUrl {
200 pub fn authority_or_default(&self) -> ffi::QString {
202 ffi::qurl_authority(self)
203 }
204
205 pub fn file_name(&self) -> ffi::QString {
211 ffi::qurl_file_name(self)
212 }
213
214 pub fn fragment(&self) -> Option<ffi::QString> {
216 if self.has_fragment() {
217 Some(self.fragment_or_default())
218 } else {
219 None
220 }
221 }
222
223 pub fn fragment_or_default(&self) -> ffi::QString {
225 ffi::qurl_fragment(self)
226 }
227
228 pub fn from_encoded(input: &ffi::QByteArray) -> Self {
230 ffi::qurl_from_encoded(input)
231 }
232
233 pub fn from_local_file(local_file: &ffi::QString) -> Self {
236 ffi::qurl_from_local_file(local_file)
237 }
238
239 pub fn from_percent_encoding(input: &ffi::QByteArray) -> ffi::QString {
242 ffi::qurl_from_percent_encoding(input)
243 }
244
245 pub fn from_user_input(user_input: &ffi::QString, working_directory: &ffi::QString) -> Self {
248 ffi::qurl_from_user_input(user_input, working_directory)
249 }
250
251 pub fn host_or_default(&self) -> ffi::QString {
253 ffi::qurl_host(self)
254 }
255
256 pub fn idn_whitelist() -> ffi::QStringList {
258 ffi::qurl_idn_whitelist()
259 }
260
261 pub fn password_or_default(&self) -> ffi::QString {
263 ffi::qurl_password(self)
264 }
265
266 pub fn path(&self) -> ffi::QString {
268 ffi::qurl_path(self)
269 }
270
271 pub fn query(&self) -> Option<ffi::QString> {
273 if self.has_query() {
274 Some(self.query_or_default())
275 } else {
276 None
277 }
278 }
279
280 pub fn query_or_default(&self) -> ffi::QString {
282 ffi::qurl_query(self)
283 }
284
285 pub fn scheme(&self) -> Option<ffi::QString> {
292 let scheme = self.scheme_or_default();
293 if scheme.is_empty() {
294 None
295 } else {
296 Some(scheme)
297 }
298 }
299
300 pub fn set_authority(&mut self, authority: &ffi::QString) {
302 ffi::qurl_set_authority(self, authority)
303 }
304
305 pub fn set_fragment(&mut self, fragment: &ffi::QString) {
308 ffi::qurl_set_fragment(self, fragment)
309 }
310
311 pub fn set_host(&mut self, host: &ffi::QString) {
313 ffi::qurl_set_host(self, host)
314 }
315
316 pub fn set_idn_whitelist(list: &ffi::QStringList) {
318 ffi::qurl_set_idn_whitelist(list)
319 }
320
321 pub fn set_password(&mut self, password: &ffi::QString) {
323 ffi::qurl_set_password(self, password)
324 }
325
326 pub fn set_path(&mut self, path: &ffi::QString) {
329 ffi::qurl_set_path(self, path)
330 }
331
332 pub fn set_query(&mut self, query: &ffi::QString) {
334 ffi::qurl_set_query(self, query)
335 }
336
337 pub fn set_scheme(&mut self, scheme: &ffi::QString) {
340 ffi::qurl_set_scheme(self, scheme)
341 }
342
343 pub fn set_url(&mut self, url: &ffi::QString) {
349 ffi::qurl_set_url(self, url)
350 }
351
352 pub fn set_user_info(&mut self, user_info: &ffi::QString) {
354 ffi::qurl_set_user_info(self, user_info)
355 }
356
357 pub fn set_user_name(&mut self, user_name: &ffi::QString) {
359 ffi::qurl_set_user_name(self, user_name)
360 }
361
362 pub fn to_display_string(&self) -> ffi::QString {
365 ffi::qurl_to_display_string(self)
366 }
367
368 pub fn to_encoded(&self) -> ffi::QByteArray {
370 ffi::qurl_to_encoded(self)
371 }
372
373 pub fn to_local_file(&self) -> Option<ffi::QString> {
376 if self.is_local_file() {
377 Some(self.to_local_file_or_default())
378 } else {
379 None
380 }
381 }
382
383 pub fn to_percent_encoding(
388 input: &ffi::QString,
389 exclude: &ffi::QByteArray,
390 include: &ffi::QByteArray,
391 ) -> ffi::QByteArray {
392 ffi::qurl_to_percent_encoding(input, exclude, include)
393 }
394
395 pub fn to_qstring(&self) -> ffi::QString {
397 ffi::qurl_to_qstring(self)
398 }
399
400 pub fn user_info_or_default(&self) -> ffi::QString {
402 ffi::qurl_user_info(self)
403 }
404
405 pub fn user_name_or_default(&self) -> ffi::QString {
407 ffi::qurl_user_name(self)
408 }
409}
410
411impl Clone for QUrl {
412 fn clone(&self) -> Self {
414 ffi::qurl_init_from_qurl(self)
415 }
416}
417
418impl Default for QUrl {
419 fn default() -> Self {
421 ffi::qurl_init_default()
422 }
423}
424
425impl std::cmp::PartialEq for QUrl {
426 fn eq(&self, other: &Self) -> bool {
427 ffi::qurl_eq(self, other)
428 }
429}
430
431impl std::cmp::Eq for QUrl {}
432
433impl fmt::Display for QUrl {
434 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
438 write!(f, "{}", ffi::qurl_to_rust_string(self))
439 }
440}
441
442impl fmt::Debug for QUrl {
443 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
444 write!(f, "{}", ffi::qurl_debug(self))
445 }
446}
447
448impl Drop for QUrl {
449 fn drop(&mut self) {
451 ffi::qurl_drop(self)
452 }
453}
454
455impl From<&ffi::QString> for QUrl {
456 fn from(str: &ffi::QString) -> Self {
458 ffi::qurl_init_from_qstring(str)
459 }
460}
461
462impl From<&str> for QUrl {
463 fn from(str: &str) -> Self {
467 ffi::qurl_init_from_string(str)
468 }
469}
470
471impl From<&String> for QUrl {
472 fn from(str: &String) -> Self {
476 ffi::qurl_init_from_string(str)
477 }
478}
479
480#[cfg(feature = "http")]
481impl From<&http::Uri> for QUrl {
482 fn from(value: &http::Uri) -> Self {
483 QUrl::from(&value.to_string())
484 }
485}
486
487#[cfg(feature = "http")]
488impl TryFrom<&QUrl> for http::Uri {
489 type Error = http::uri::InvalidUri;
490
491 fn try_from(value: &QUrl) -> Result<Self, Self::Error> {
492 value.to_string().parse::<http::Uri>()
493 }
494}
495
496#[cfg(feature = "url")]
497impl From<&url::Url> for QUrl {
498 fn from(value: &url::Url) -> Self {
499 QUrl::from(&value.to_string())
500 }
501}
502
503#[cfg(feature = "url")]
504impl TryFrom<&QUrl> for url::Url {
505 type Error = url::ParseError;
506
507 fn try_from(value: &QUrl) -> Result<Self, Self::Error> {
508 url::Url::parse(value.to_string().as_str())
509 }
510}
511
512unsafe impl ExternType for QUrl {
516 type Id = type_id!("QUrl");
517 type Kind = cxx::kind::Trivial;
518}
519
520#[cfg(test)]
521mod tests {
522 #[cfg(any(feature = "http", feature = "url"))]
523 use super::*;
524
525 #[cfg(feature = "http")]
526 #[test]
527 fn test_http() {
528 let uri = "https://github.com/kdab/cxx-qt"
529 .parse::<http::Uri>()
530 .unwrap();
531 let qurl = QUrl::from(&uri);
532 assert_eq!(uri.to_string(), qurl.to_string());
533
534 let http_uri = http::Uri::try_from(&qurl).unwrap();
535 assert_eq!(http_uri, uri);
536 }
537
538 #[cfg(feature = "url")]
539 #[test]
540 fn test_url() {
541 let url = url::Url::parse("https://github.com/kdab/cxx-qt").unwrap();
542 let qurl = QUrl::from(&url);
543 assert_eq!(url.to_string(), qurl.to_string());
544
545 let url_url = url::Url::try_from(&qurl).unwrap();
546 assert_eq!(url_url, url);
547 }
548}