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