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-25 21:00:01 Functions: 100.0 % 71 71

           TLA  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 HIT         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