LCOV - code coverage report
Current view: top level - url - format.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 14 14
Test Date: 2026-02-13 15:53:22 Functions: 100.0 % 71 71

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/boostorg/url
       8              : //
       9              : 
      10              : #ifndef BOOST_URL_FORMAT_HPP
      11              : #define BOOST_URL_FORMAT_HPP
      12              : 
      13              : #include <boost/url/detail/config.hpp>
      14              : #include <boost/core/detail/string_view.hpp>
      15              : #include <boost/url/url.hpp>
      16              : #include <boost/url/detail/vformat.hpp>
      17              : #include <initializer_list>
      18              : 
      19              : #ifdef BOOST_URL_HAS_CONCEPTS
      20              : #include <concepts>
      21              : #endif
      22              : 
      23              : namespace boost {
      24              : namespace urls {
      25              : 
      26              : /** A temporary reference to a named formatting argument
      27              : 
      28              :     This class represents a temporary reference
      29              :     to a named formatting argument used by the
      30              :     @ref format function.
      31              : 
      32              :     Named arguments should always be created
      33              :     with the @ref arg function.
      34              : 
      35              :     Any type that can be formatted into a URL
      36              :     with the @ref format function can also be used
      37              :     in a named argument. All named arguments
      38              :     are convertible to @ref format_arg and
      39              :     can be used in the @ref format function.
      40              : 
      41              :     @see
      42              :         @ref arg,
      43              :         @ref format,
      44              :         @ref format_to,
      45              :         @ref format_arg.
      46              :   */
      47              : template <class T>
      48              : using named_arg = detail::named_arg<T>;
      49              : 
      50              : /** A temporary reference to a formatting argument
      51              : 
      52              :     This class represents a temporary reference
      53              :     to a formatting argument used by the
      54              :     @ref format function.
      55              : 
      56              :     A @ref format argument should always be
      57              :     created by passing the argument to be
      58              :     formatted directly to the @ref format function.
      59              : 
      60              :     Any type that can be formatted into a URL
      61              :     with the @ref format function is convertible
      62              :     to this type.
      63              : 
      64              :     This includes basic types, types convertible
      65              :     to `core::string_view`, and @ref named_arg.
      66              : 
      67              :     @see
      68              :         @ref format,
      69              :         @ref format_to,
      70              :         @ref arg.
      71              :   */
      72              : using format_arg = detail::format_arg;
      73              : 
      74              : /** Format arguments into a URL
      75              : 
      76              :     Format arguments according to the format
      77              :     URL string into a @ref url.
      78              : 
      79              :     The rules for a format URL string are the same
      80              :     as for a `std::format_string`, where replacement
      81              :     fields are delimited by curly braces.
      82              : 
      83              :     The URL components to which replacement fields
      84              :     belong are identified before replacement is
      85              :     applied and any invalid characters for that
      86              :     formatted argument are percent-escaped.
      87              : 
      88              :     Hence, the delimiters between URL components,
      89              :     such as `:`, `//`, `?`, and `#`, should be
      90              :     included in the URL format string. Likewise,
      91              :     a format string with a single `"{}"` is
      92              :     interpreted as a path and any replacement
      93              :     characters invalid in this component will be
      94              :     encoded to form a valid URL.
      95              : 
      96              :     @par Example
      97              :     @code
      98              :     assert(format("{}://{}:{}/rfc/{}",
      99              :         "https", "www.ietf.org", 80, "rfc2396.txt"
     100              :         ).buffer() == "https://www.ietf.org:80/rfc/rfc2396.txt");
     101              :     @endcode
     102              : 
     103              :     Arguments that contain special characters are
     104              :     automatically percent-encoded for the URL
     105              :     component where they appear:
     106              : 
     107              :     @code
     108              :     assert(format("https://example.com/~{}",
     109              :         "John Doe"
     110              :         ).buffer() == "https://example.com/~John%20Doe");
     111              :     @endcode
     112              : 
     113              :     @note
     114              :     The formatting machinery relies on language and library
     115              :     features that are broken on GCC 4.8 and GCC 5.x, so this
     116              :     function is not supported on those compilers.
     117              : 
     118              :     @par Preconditions
     119              :     All replacement fields must be valid and the
     120              :     resulting URL should be valid after arguments
     121              :     are formatted into the URL.
     122              : 
     123              :     Because any invalid characters for a URL
     124              :     component are encoded by this function, only
     125              :     replacements in the scheme and port components
     126              :     might be invalid, as these components do not
     127              :     allow percent-encoding of arbitrary
     128              :     characters.
     129              : 
     130              :     @return A URL holding the formatted result.
     131              : 
     132              :     @param fmt The format URL string.
     133              :     @param args Arguments to be formatted.
     134              : 
     135              :     @throws system_error
     136              :     `fmt` contains an invalid format string and
     137              :     the result contains an invalid URL after
     138              :     replacements are applied.
     139              : 
     140              :     @par BNF
     141              :     @code
     142              :     replacement_field ::=  "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
     143              :     arg_id            ::=  integer | identifier
     144              :     integer           ::=  digit+
     145              :     digit             ::=  "0"..."9"
     146              :     identifier        ::=  id_start id_continue*
     147              :     id_start          ::=  "a"..."z" | "A"..."Z" | "_"
     148              :     id_continue       ::=  id_start | digit
     149              :     @endcode
     150              : 
     151              :     @par Specification
     152              :     @li <a href="https://fmt.dev/latest/syntax.html"
     153              :         >Format String Syntax</a>
     154              : 
     155              :     @see
     156              :         @ref format_to,
     157              :         @ref arg.
     158              : */
     159              : template <BOOST_URL_CONSTRAINT(std::convertible_to<format_arg>)... Args>
     160              : url
     161          150 : format(
     162              :     core::string_view fmt,
     163              :     Args&&... args)
     164              : {
     165              :     return detail::vformat(
     166          160 :         fmt, detail::make_format_args(
     167          290 :             std::forward<Args>(args)...));
     168              : }
     169              : 
     170              : /** Format arguments into a URL
     171              : 
     172              :     Format arguments according to the format
     173              :     URL string into a @ref url_base.
     174              : 
     175              :     The rules for a format URL string are the same
     176              :     as for a `std::format_string`, where replacement
     177              :     fields are delimited by curly braces.
     178              : 
     179              :     The URL components to which replacement fields
     180              :     belong are identified before replacement is
     181              :     applied and any invalid characters for that
     182              :     formatted argument are percent-escaped.
     183              : 
     184              :     Hence, the delimiters between URL components,
     185              :     such as `:`, `//`, `?`, and `#`, should be
     186              :     included in the URL format string. Likewise,
     187              :     a format string with a single `"{}"` is
     188              :     interpreted as a path and any replacement
     189              :     characters invalid in this component will be
     190              :     encoded to form a valid URL.
     191              : 
     192              :     @par Example
     193              :     @code
     194              :     static_url<50> u;
     195              :     format_to(u, "{}://{}:{}/rfc/{}",
     196              :         "https", "www.ietf.org", 80, "rfc2396.txt");
     197              :     assert(u.buffer() == "https://www.ietf.org:80/rfc/rfc2396.txt");
     198              :     @endcode
     199              : 
     200              :     @par Preconditions
     201              :     All replacement fields must be valid and the
     202              :     resulting URL should be valid after arguments
     203              :     are formatted into the URL.
     204              : 
     205              :     Because any invalid characters for a URL
     206              :     component are encoded by this function, only
     207              :     replacements in the scheme and port components
     208              :     might be invalid, as these components do not
     209              :     allow percent-encoding of arbitrary
     210              :     characters.
     211              : 
     212              :     @par Exception Safety
     213              :     Strong guarantee.
     214              : 
     215              :     @param u An object that derives from @ref url_base.
     216              :     @param fmt The format URL string.
     217              :     @param args Arguments to be formatted.
     218              : 
     219              :     @throws system_error
     220              :     `fmt` contains an invalid format string and
     221              :     `u` contains an invalid URL after replacements
     222              :     are applied.
     223              : 
     224              :     @par BNF
     225              :     @code
     226              :     replacement_field ::=  "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
     227              :     arg_id            ::=  integer | identifier
     228              :     integer           ::=  digit+
     229              :     digit             ::=  "0"..."9"
     230              :     identifier        ::=  id_start id_continue*
     231              :     id_start          ::=  "a"..."z" | "A"..."Z" | "_"
     232              :     id_continue       ::=  id_start | digit
     233              :     @endcode
     234              : 
     235              :     @par Specification
     236              :     @li <a href="https://fmt.dev/latest/syntax.html"
     237              :         >Format String Syntax</a>
     238              : 
     239              :     @see
     240              :         @ref format.
     241              : 
     242              : */
     243              : template <BOOST_URL_CONSTRAINT(std::convertible_to<format_arg>)... Args>
     244              : void
     245            5 : format_to(
     246              :     url_base& u,
     247              :     core::string_view fmt,
     248              :     Args&&... args)
     249              : {
     250            5 :     detail::vformat_to(
     251            6 :         u, fmt, detail::make_format_args(
     252              :             std::forward<Args>(args)...));
     253            4 : }
     254              : 
     255              : /** Format arguments into a URL
     256              : 
     257              :     Format arguments according to the format
     258              :     URL string into a @ref url.
     259              : 
     260              :     This overload allows type-erased arguments
     261              :     to be passed as an initializer_list, which
     262              :     is mostly convenient for named parameters.
     263              : 
     264              :     All arguments must be convertible to a
     265              :     implementation defined type able to store a
     266              :     type-erased reference to any valid format
     267              :     argument.
     268              : 
     269              :     The rules for a format URL string are the same
     270              :     as for a `std::format_string`, where replacement
     271              :     fields are delimited by curly braces.
     272              : 
     273              :     The URL components to which replacement fields
     274              :     belong are identified before replacement is
     275              :     applied and any invalid characters for that
     276              :     formatted argument are percent-escaped.
     277              : 
     278              :     Hence, the delimiters between URL components,
     279              :     such as `:`, `//`, `?`, and `#`, should be
     280              :     included in the URL format string. Likewise,
     281              :     a format string with a single `"{}"` is
     282              :     interpreted as a path and any replacement
     283              :     characters invalid in this component will be
     284              :     encoded to form a valid URL.
     285              : 
     286              :     @par Example
     287              :     @code
     288              :     assert(format(
     289              :         "{scheme}://{host}:{port}/{dir}/{file}",
     290              :         {{"scheme", "https"}, {"port", 80},
     291              :          {"host", "example.com"},
     292              :          {"dir", "path/to"},
     293              :          {"file", "file.txt"}}
     294              :         ).buffer() == "https://example.com:80/path/to/file.txt");
     295              :     @endcode
     296              : 
     297              :     @par Preconditions
     298              :     All replacement fields must be valid and the
     299              :     resulting URL should be valid after arguments
     300              :     are formatted into the URL.
     301              : 
     302              :     Because any invalid characters for a URL
     303              :     component are encoded by this function, only
     304              :     replacements in the scheme and port components
     305              :     might be invalid, as these components do not
     306              :     allow percent-encoding of arbitrary
     307              :     characters.
     308              : 
     309              :     @return A URL holding the formatted result.
     310              : 
     311              :     @param fmt The format URL string.
     312              :     @param args Arguments to be formatted.
     313              : 
     314              :     @throws system_error
     315              :     `fmt` contains an invalid format string and
     316              :     the result contains an invalid URL after
     317              :     replacements are applied.
     318              : 
     319              :     @par BNF
     320              :     @code
     321              :     replacement_field ::=  "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
     322              :     arg_id            ::=  integer | identifier
     323              :     integer           ::=  digit+
     324              :     digit             ::=  "0"..."9"
     325              :     identifier        ::=  id_start id_continue*
     326              :     id_start          ::=  "a"..."z" | "A"..."Z" | "_"
     327              :     id_continue       ::=  id_start | digit
     328              :     @endcode
     329              : 
     330              :     @par Specification
     331              :     @li <a href="https://fmt.dev/latest/syntax.html"
     332              :         >Format String Syntax</a>
     333              : 
     334              :     @see
     335              :         @ref format_to.
     336              : 
     337              : */
     338              : inline
     339              : url
     340            4 : format(
     341              :     core::string_view fmt,
     342              :     std::initializer_list<format_arg> args)
     343              : {
     344              :     return detail::vformat(
     345              :         fmt, detail::format_args(
     346            4 :             args.begin(), args.end()));
     347              : }
     348              : 
     349              : /** Format arguments into a URL
     350              : 
     351              :     Format arguments according to the format
     352              :     URL string into a @ref url_base.
     353              : 
     354              :     This overload allows type-erased arguments
     355              :     to be passed as an initializer_list, which
     356              :     is mostly convenient for named parameters.
     357              : 
     358              :     All arguments must be convertible to a
     359              :     implementation defined type able to store a
     360              :     type-erased reference to any valid format
     361              :     argument.
     362              : 
     363              :     The rules for a format URL string are the same
     364              :     as for a `std::format_string`, where replacement
     365              :     fields are delimited by curly braces.
     366              : 
     367              :     The URL components to which replacement fields
     368              :     belong are identified before replacement is
     369              :     applied and any invalid characters for that
     370              :     formatted argument are percent-escaped.
     371              : 
     372              :     Hence, the delimiters between URL components,
     373              :     such as `:`, `//`, `?`, and `#`, should be
     374              :     included in the URL format string. Likewise,
     375              :     a format string with a single `"{}"` is
     376              :     interpreted as a path and any replacement
     377              :     characters invalid in this component will be
     378              :     encoded to form a valid URL.
     379              : 
     380              :     @par Example
     381              :     @code
     382              :     url u;
     383              :     format_to(u,
     384              :         "{scheme}://{host}:{port}/{dir}/{file}",
     385              :         {{"scheme", "https"}, {"port", 80},
     386              :          {"host", "example.com"},
     387              :          {"dir", "path/to"},
     388              :          {"file", "file.txt"}});
     389              :     assert(u.buffer() == "https://example.com:80/path/to/file.txt");
     390              :     @endcode
     391              : 
     392              :     @par Preconditions
     393              :     All replacement fields must be valid and the
     394              :     resulting URL should be valid after arguments
     395              :     are formatted into the URL.
     396              : 
     397              :     Because any invalid characters for a URL
     398              :     component are encoded by this function, only
     399              :     replacements in the scheme and port components
     400              :     might be invalid, as these components do not
     401              :     allow percent-encoding of arbitrary
     402              :     characters.
     403              : 
     404              :     @par Exception Safety
     405              :     Strong guarantee.
     406              : 
     407              :     @param u An object that derives from @ref url_base.
     408              :     @param fmt The format URL string.
     409              :     @param args Arguments to be formatted.
     410              : 
     411              :     @throws system_error
     412              :     `fmt` contains an invalid format string and
     413              :     `u` contains an invalid URL after replacements
     414              :     are applied.
     415              : 
     416              :     @par BNF
     417              :     @code
     418              :     replacement_field ::=  "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
     419              :     arg_id            ::=  integer | identifier
     420              :     integer           ::=  digit+
     421              :     digit             ::=  "0"..."9"
     422              :     identifier        ::=  id_start id_continue*
     423              :     id_start          ::=  "a"..."z" | "A"..."Z" | "_"
     424              :     id_continue       ::=  id_start | digit
     425              :     @endcode
     426              : 
     427              :     @par Specification
     428              :     @li <a href="https://fmt.dev/latest/syntax.html"
     429              :         >Format String Syntax</a>
     430              : 
     431              :     @see
     432              :         @ref format.
     433              : 
     434              : */
     435              : inline
     436              : void
     437            2 : format_to(
     438              :     url_base& u,
     439              :     core::string_view fmt,
     440              :     std::initializer_list<format_arg> args)
     441              : {
     442            2 :     detail::vformat_to(
     443              :         u, fmt, detail::format_args(
     444              :             args.begin(), args.end()));
     445            2 : }
     446              : 
     447              : /** Designate a named argument for a replacement field
     448              : 
     449              :     Construct a named argument for a format URL
     450              :     string that contains named replacement fields.
     451              : 
     452              :     The function parameters should be convertible
     453              :     to an implementation defined type able to
     454              :     store the name and a reference to any type
     455              :     potentially used as a format argument.
     456              : 
     457              :     @par Example
     458              :     @code
     459              :     assert(format(
     460              :         "https://example.com/~{username}",
     461              :         arg("username", "mark")
     462              :         ).buffer() == "https://example.com/~mark");
     463              :     @endcode
     464              : 
     465              :     @return A temporary object with reference
     466              :     semantics for a named argument
     467              : 
     468              :     @param name The format argument name
     469              :     @param arg The format argument value
     470              : 
     471              :     @see
     472              :         @ref format,
     473              :         @ref format_to.
     474              : 
     475              : */
     476              : template <class T>
     477              : named_arg<T>
     478           21 : arg(core::string_view name, T const& arg)
     479              : {
     480           21 :     return {name, arg};
     481              : }
     482              : 
     483              : } // url
     484              : } // boost
     485              : 
     486              : #endif
        

Generated by: LCOV version 2.3