1 /* 2 * Copyright 2025 Matheus C. França 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 module ada.c.wrapper; 17 18 /// Ada-URL low-level library. 19 private import ada.c.ada; 20 21 @safe: 22 23 /++ 24 + A struct representing a parsed URL, providing methods to access and manipulate URL components. 25 + Wraps the functionality of the Ada URL parsing library. 26 +/ 27 struct AdaUrl 28 { 29 /++ 30 + Constructs an AdaUrl instance with the given parsing options. 31 + Params: 32 + options = The parsing options containing the URL to parse. 33 +/ 34 this(ParseOptions options) @nogc nothrow 35 { 36 _url = options.url; 37 } 38 39 /++ 40 + Destructor that frees the underlying URL resources. 41 +/ 42 ~this() @nogc nothrow 43 { 44 ada_free(_url); 45 } 46 47 /++ 48 + Checks if the URL is valid. 49 + Returns: true if the URL is valid, false otherwise. 50 +/ 51 bool isValid() @nogc nothrow 52 { 53 return ada_is_valid(_url); 54 } 55 56 /++ 57 + Retrieves the origin of the URL (e.g., protocol + host + port). 58 + Returns: A string representing the URL's origin. 59 +/ 60 string getOrigin() @nogc nothrow 61 { 62 auto owned = ada_get_origin(_url); 63 scope (exit) 64 ada_free_owned_string(owned); 65 return str_convert(owned); 66 } 67 68 /++ 69 + Retrieves the full URL as a string (href). 70 + Returns: A string representing the complete URL. 71 +/ 72 string getHref() @nogc nothrow 73 { 74 auto str = ada_get_href(_url); 75 return str_convert(str); 76 } 77 78 /++ 79 + Retrieves the username component of the URL. 80 + Returns: A string representing the username, or empty if none. 81 +/ 82 string getUsername() @nogc nothrow 83 { 84 auto str = ada_get_username(_url); 85 return str_convert(str); 86 } 87 88 /++ 89 + Retrieves the password component of the URL. 90 + Returns: A string representing the password, or empty if none. 91 +/ 92 string getPassword() @nogc nothrow 93 { 94 auto str = ada_get_password(_url); 95 return str_convert(str); 96 } 97 98 /++ 99 + Retrieves the port component of the URL. 100 + Returns: A string representing the port, or empty if none. 101 +/ 102 string getPort() @nogc nothrow 103 { 104 auto str = ada_get_port(_url); 105 return str_convert(str); 106 } 107 108 /++ 109 + Retrieves the hash (fragment) component of the URL. 110 + Returns: A string representing the hash, or empty if none. 111 +/ 112 string getHash() @nogc nothrow 113 { 114 auto str = ada_get_hash(_url); 115 return str_convert(str); 116 } 117 118 /++ 119 + Retrieves the host component of the URL (hostname + port). 120 + Returns: A string representing the host. 121 +/ 122 string getHost() @nogc nothrow 123 { 124 auto str = ada_get_host(_url); 125 return str_convert(str); 126 } 127 128 /++ 129 + Retrieves the hostname component of the URL. 130 + Returns: A string representing the hostname. 131 +/ 132 string getHostname() @nogc nothrow 133 { 134 auto str = ada_get_hostname(_url); 135 return str_convert(str); 136 } 137 138 /++ 139 + Retrieves the pathname component of the URL. 140 + Returns: A string representing the pathname. 141 +/ 142 string getPathname() @nogc nothrow 143 { 144 auto str = ada_get_pathname(_url); 145 return str_convert(str); 146 } 147 148 /++ 149 + Retrieves the search (query) parameters of the URL. 150 + Returns: A SearchParams struct representing the query parameters. 151 +/ 152 SearchParams getSearch() @nogc nothrow 153 { 154 return SearchParams(ada_get_search(_url)); 155 } 156 157 /++ 158 + Converts the search parameters to a string. 159 + Params: 160 + search = The SearchParams object to convert. 161 + Returns: A string representing the query parameters. 162 +/ 163 string getSearchParams(SearchParams search) @nogc nothrow 164 { 165 auto str = search.toString(); 166 return str_convert(str); 167 } 168 169 /++ 170 + Retrieves the protocol component of the URL (e.g., "http:"). 171 + Returns: A string representing the protocol. 172 +/ 173 string getProtocol() @nogc nothrow 174 { 175 auto str = ada_get_protocol(_url); 176 return str_convert(str); 177 } 178 179 /++ 180 + Retrieves the host type of the URL. 181 + Returns: A ubyte representing the host type (as defined by the Ada library). 182 +/ 183 ubyte getHostType() @nogc nothrow 184 { 185 return ada_get_host_type(_url); 186 } 187 188 /++ 189 + Retrieves the scheme type of the URL. 190 + Returns: A ubyte representing the scheme type (as defined by the Ada library). 191 +/ 192 ubyte getSchemeType() @nogc nothrow 193 { 194 return ada_get_scheme_type(_url); 195 } 196 197 /++ 198 + Sets the full URL (href). 199 + Params: 200 + input = The new URL string to set. 201 + Returns: true if successful, false otherwise. 202 +/ 203 bool setHref(string input) @nogc nothrow 204 { 205 return ada_set_href(_url, &input[0], input.length); 206 } 207 208 /++ 209 + Sets the host component of the URL. 210 + Params: 211 + input = The new host string to set. 212 + Returns: true if successful, false otherwise. 213 +/ 214 bool setHost(string input) @nogc nothrow 215 { 216 return ada_set_host(_url, &input[0], input.length); 217 } 218 219 /++ 220 + Sets the hostname component of the URL. 221 + Params: 222 + input = The new hostname string to set. 223 + Returns: true if successful, false otherwise. 224 +/ 225 bool setHostname(string input) @nogc nothrow 226 { 227 return ada_set_hostname(_url, &input[0], input.length); 228 } 229 230 /++ 231 + Sets the protocol component of the URL. 232 + Params: 233 + input = The new protocol string to set (e.g., "http:"). 234 + Returns: true if successful, false otherwise. 235 +/ 236 bool setProtocol(string input) @nogc nothrow 237 { 238 return ada_set_protocol(_url, &input[0], input.length); 239 } 240 241 /++ 242 + Sets the username component of the URL. 243 + Params: 244 + input = The new username string to set. 245 + Returns: true if successful, false otherwise. 246 +/ 247 bool setUsername(string input) @nogc nothrow 248 { 249 return ada_set_username(_url, &input[0], input.length); 250 } 251 252 /++ 253 + Sets the password component of the URL. 254 + Params: 255 + input = The new password string to set. 256 + Returns: true if successful, false otherwise. 257 +/ 258 bool setPassword(string input) @nogc nothrow 259 { 260 return ada_set_password(_url, &input[0], input.length); 261 } 262 263 /++ 264 + Sets the port component of the URL. 265 + Params: 266 + input = The new port string to set. 267 + Returns: true if successful, false otherwise. 268 +/ 269 bool setPort(string input) @nogc nothrow 270 { 271 return ada_set_port(_url, &input[0], input.length); 272 } 273 274 /++ 275 + Sets the pathname component of the URL. 276 + Params: 277 + input = The new pathname string to set. 278 + Returns: true if successful, false otherwise. 279 +/ 280 bool setPathname(string input) @nogc nothrow 281 { 282 return ada_set_pathname(_url, &input[0], input.length); 283 } 284 285 /++ 286 + Sets the search (query) component of the URL. 287 + Params: 288 + input = The new query string to set. 289 +/ 290 void setSearch(string input) @nogc nothrow 291 { 292 ada_set_search(_url, &input[0], input.length); 293 } 294 295 /++ 296 + Sets the hash (fragment) component of the URL. 297 + Params: 298 + input = The new hash string to set. 299 +/ 300 void setHash(string input) @nogc nothrow 301 { 302 ada_set_hash(_url, &input[0], input.length); 303 } 304 305 /++ 306 + Clears the port component of the URL. 307 +/ 308 void clearPort() @nogc nothrow 309 { 310 ada_clear_port(_url); 311 } 312 313 /++ 314 + Clears the hash (fragment) component of the URL. 315 +/ 316 void clearHash() @nogc nothrow 317 { 318 ada_clear_hash(_url); 319 } 320 321 /++ 322 + Clears the search (query) component of the URL. 323 +/ 324 void clearSearch() @nogc nothrow 325 { 326 ada_clear_search(_url); 327 } 328 329 /++ 330 + Creates a copy of the URL. 331 + Returns: A new ada_url handle representing the copied URL. 332 +/ 333 ada_url copy() @nogc nothrow 334 { 335 return ada_copy(_url); 336 } 337 338 /++ 339 + Checks if the URL has credentials (username or password). 340 + Returns: true if credentials are present, false otherwise. 341 +/ 342 bool hasCredentials() @nogc nothrow 343 { 344 return ada_has_credentials(_url); 345 } 346 347 /++ 348 + Checks if the URL has an empty hostname. 349 + Returns: true if the hostname is empty, false otherwise. 350 +/ 351 bool hasEmptyHostname() @nogc nothrow 352 { 353 return ada_has_empty_hostname(_url); 354 } 355 356 /++ 357 + Checks if the URL has a hostname. 358 + Returns: true if a hostname is present, false otherwise. 359 +/ 360 bool hasHostname() @nogc nothrow 361 { 362 return ada_has_hostname(_url); 363 } 364 365 /++ 366 + Checks if the URL has a non-empty username. 367 + Returns: true if the username is non-empty, false otherwise. 368 +/ 369 bool hasNonEmptyUsername() @nogc nothrow 370 { 371 return ada_has_non_empty_username(_url); 372 } 373 374 /++ 375 + Checks if the URL has a non-empty password. 376 + Returns: true if the password is non-empty, false otherwise. 377 +/ 378 bool hasNonEmptyPassword() @nogc nothrow 379 { 380 return ada_has_non_empty_password(_url); 381 } 382 383 /++ 384 + Checks if the URL has a port. 385 + Returns: true if a port is present, false otherwise. 386 +/ 387 bool hasPort() @nogc nothrow 388 { 389 return ada_has_port(_url); 390 } 391 392 /++ 393 + Checks if the URL has a password. 394 + Returns: true if a password is present, false otherwise. 395 +/ 396 bool hasPassword() @nogc nothrow 397 { 398 return ada_has_password(_url); 399 } 400 401 /++ 402 + Checks if the URL has a hash (fragment). 403 + Returns: true if a hash is present, false otherwise. 404 +/ 405 bool hasHash() @nogc nothrow 406 { 407 return ada_has_hash(_url); 408 } 409 410 /++ 411 + Checks if the URL has a search (query) component. 412 + Returns: true if a query is present, false otherwise. 413 +/ 414 bool hasSearch() @nogc nothrow 415 { 416 return ada_has_search(_url); 417 } 418 419 /++ 420 + Retrieves the URL components (e.g., offsets for protocol, host, etc.). 421 + Returns: A pointer to the ada_url_components struct. 422 +/ 423 const(ada_url_components)* getComponents() @nogc nothrow 424 { 425 return ada_get_components(_url); 426 } 427 428 private ada_url _url; 429 } 430 431 /++ 432 + A struct for parsing URLs with optional base URL support. 433 +/ 434 struct ParseOptions 435 { 436 /++ 437 + Constructs a ParseOptions instance by parsing a URL string. 438 + Params: 439 + input = The URL string to parse. 440 +/ 441 this(string input) @nogc nothrow 442 { 443 _url = ada_parse(&input[0], input.length); 444 } 445 446 /++ 447 + Constructs a ParseOptions instance by parsing a URL with a base URL. 448 + Params: 449 + input = The URL string to parse. 450 + base = The base URL string for relative URL resolution. 451 +/ 452 this(string input, string base) @nogc nothrow 453 { 454 _url = ada_parse_with_base(&input[0], input.length, &base[0], base.length); 455 } 456 457 /++ 458 + Retrieves the parsed URL handle. 459 + Returns: The ada_url handle. 460 +/ 461 @property ada_url url() @nogc nothrow 462 { 463 return _url; 464 } 465 466 private ada_url _url; 467 } 468 469 /++ 470 + A struct for managing URL search (query) parameters. 471 +/ 472 struct SearchParams 473 { 474 /++ 475 + Constructs a SearchParams instance from a query string. 476 + Params: 477 + input = The query string to parse. 478 +/ 479 this(ref ada_string input) @nogc nothrow 480 { 481 _str = input; 482 _params = ada_parse_search_params(_str.data, _str.length); 483 } 484 485 /++ 486 + Destructor that frees the search parameters and associated iterators. 487 +/ 488 ~this() @nogc nothrow 489 { 490 ada_free_search_params_keys_iter(keys); 491 ada_free_search_params_values_iter(values); 492 ada_free_search_params_entries_iter(entries); 493 ada_free_search_params(_params); 494 } 495 496 /++ 497 + Appends a key-value pair to the search parameters. 498 + Params: 499 + key = The key to append. 500 + value = The value to append. 501 +/ 502 void append(ref string key, ref string value) @nogc nothrow 503 { 504 ada_search_params_append(_params, &key[0], key.length, &value[0], value.length); 505 } 506 507 /++ 508 + Converts the search parameters to a string. 509 + Returns: An ada_owned_string representing the query string. 510 +/ 511 ada_owned_string toString() @nogc nothrow 512 { 513 return ada_search_params_to_string(_params); 514 } 515 516 /++ 517 + Retrieves the value for a given key. 518 + Params: 519 + key = The key to look up. 520 + Returns: An ada_string containing the value, or empty if not found. 521 +/ 522 ada_string get(ref string key) @nogc nothrow 523 { 524 return ada_search_params_get(_params, &key[0], key.length); 525 } 526 527 /++ 528 + Retrieves an iterator for the keys in the search parameters. 529 + Returns: An ada_url_search_params_keys_iter for the keys. 530 +/ 531 @property ada_url_search_params_keys_iter keys() @nogc nothrow 532 { 533 return ada_search_params_get_keys(_params); 534 } 535 536 /++ 537 + Retrieves an iterator for the values in the search parameters. 538 + Returns: An ada_url_search_params_values_iter for the values. 539 +/ 540 @property ada_url_search_params_values_iter values() @nogc nothrow 541 { 542 return ada_search_params_get_values(_params); 543 } 544 545 /++ 546 + Retrieves an iterator for the key-value pairs in the search parameters. 547 + Returns: An ada_url_search_params_entries_iter for the entries. 548 +/ 549 @property ada_url_search_params_entries_iter entries() @nogc nothrow 550 { 551 return ada_search_params_get_entries(_params); 552 } 553 554 /++ 555 + Retrieves all values for a given key. 556 + Params: 557 + key = The key to look up. 558 + Returns: A Strings struct containing all values for the key. 559 +/ 560 Strings getAll(ref string key) @nogc nothrow 561 { 562 return Strings(ada_search_params_get_all(_params, &key[0], key.length)); 563 } 564 565 /++ 566 + Checks if a key exists in the search parameters. 567 + Params: 568 + key = The key to check. 569 + Returns: true if the key exists, false otherwise. 570 +/ 571 bool has(ref string key) @nogc nothrow 572 { 573 return ada_search_params_has(_params, &key[0], key.length); 574 } 575 576 /++ 577 + Checks if a key-value pair exists in the search parameters. 578 + Params: 579 + key = The key to check. 580 + value = The value to check. 581 + Returns: true if the key-value pair exists, false otherwise. 582 +/ 583 bool hasValue(ref string key, ref string value) @nogc nothrow 584 { 585 return ada_search_params_has_value(_params, &key[0], key.length, &value[0], value.length); 586 } 587 588 /++ 589 + Retrieves the number of key-value pairs in the search parameters. 590 + Returns: The number of pairs. 591 +/ 592 size_t length() @nogc nothrow 593 { 594 return ada_search_params_size(_params); 595 } 596 597 /++ 598 + Resets the search parameters to the original query string. 599 +/ 600 void reset() @nogc nothrow 601 { 602 ada_search_params_reset(_params, _str.data, _str.length); 603 } 604 605 /++ 606 + Removes all values for a given key. 607 + Params: 608 + key = The key to remove. 609 +/ 610 void remove(ref string key) @nogc nothrow 611 { 612 ada_search_params_remove(_params, &key[0], key.length); 613 } 614 615 /++ 616 + Removes a specific key-value pair. 617 + Params: 618 + key = The key to remove. 619 + value = The value to remove. 620 +/ 621 void removeValue(ref string key, ref string value) @nogc nothrow 622 { 623 ada_search_params_remove_value(_params, &key[0], key.length, &value[0], value.length); 624 } 625 626 /++ 627 + Sets a key-value pair, replacing any existing values for the key. 628 + Params: 629 + key = The key to set. 630 + value = The value to set. 631 +/ 632 void set(ref string key, ref string value) @nogc nothrow 633 { 634 ada_search_params_set(_params, &key[0], key.length, &value[0], value.length); 635 } 636 637 /++ 638 + Sorts the search parameters by key. 639 +/ 640 void sort() @nogc nothrow 641 { 642 ada_search_params_sort(_params); 643 } 644 645 /++ 646 + Gets the next key-value pair from a search parameters iterator. 647 + Params: 648 + it = The search parameters iterator to get the next pair from. 649 + Returns: The next key-value pair in the iterator, or an empty pair if iteration is complete. 650 +/ 651 ada_string_pair itNext(scope ada_url_search_params_entries_iter it) @nogc nothrow 652 { 653 return ada_search_params_entries_iter_next(it); 654 } 655 656 private 657 { 658 ada_url_search_params _params; 659 ada_string _str; 660 } 661 } 662 663 /++ 664 + A struct for managing a collection of strings, typically used for multiple values of a query parameter. 665 +/ 666 struct Strings 667 { 668 /++ 669 + Constructs a Strings instance from an ada_strings collection. 670 + Params: 671 + input = The ada_strings collection to manage. 672 +/ 673 this(ref ada_strings input) @nogc nothrow 674 { 675 _str = input; 676 } 677 678 /++ 679 + Destructor that frees the string collection. 680 +/ 681 ~this() @nogc nothrow 682 { 683 ada_free_strings(_str); 684 } 685 686 /++ 687 + Retrieves a string at the specified index. 688 + Params: 689 + index = The index of the string to retrieve. 690 + Returns: The string at the specified index. 691 +/ 692 string getStr(size_t index) @nogc nothrow 693 { 694 return str_convert(ada_strings_get(_str, index)); 695 } 696 697 /++ 698 + Retrieves the raw ada_string data at the specified index. 699 + Params: 700 + index = The index of the string to retrieve. 701 + Returns: The ada_string at the specified index. 702 +/ 703 ada_string getData(size_t index) @nogc nothrow 704 { 705 return ada_strings_get(_str, index); 706 } 707 708 /++ 709 + Retrieves the number of strings in the collection. 710 + Returns: The number of strings. 711 +/ 712 size_t length() @nogc nothrow 713 { 714 return ada_strings_size(_str); 715 } 716 717 private ada_strings _str; 718 } 719 720 /++ 721 + Converts an Ada string type (ada_string or ada_owned_string) to a D string. 722 + Params: 723 + str = The Ada string to convert. 724 + Returns: A D string representing the input. 725 +/ 726 string str_convert(T)(ref T str) @trusted @nogc nothrow 727 { 728 // pointer slicing not allowed in safe [checked] functions 729 static if (is(T == ada_string) || is(T == ada_owned_string)) 730 return cast(string)(str.data[0 .. str.length]); 731 else 732 return cast(string)(str); 733 }