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
161  
format(
161  
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(
166  
        fmt, detail::make_format_args(
166  
        fmt, detail::make_format_args(
167  
            std::forward<Args>(args)...));
167  
            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
245  
format_to(
245  
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  
{
250  
    detail::vformat_to(
250  
    detail::vformat_to(
251  
        u, fmt, detail::make_format_args(
251  
        u, fmt, detail::make_format_args(
252  
            std::forward<Args>(args)...));
252  
            std::forward<Args>(args)...));
253  
}
253  
}
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
340  
format(
340  
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(
346  
            args.begin(), args.end()));
346  
            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
437  
format_to(
437  
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  
{
442  
    detail::vformat_to(
442  
    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()));
445  
}
445  
}
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>
478  
arg(core::string_view name, T const& arg)
478  
arg(core::string_view name, T const& arg)
479  
{
479  
{
480  
    return {name, arg};
480  
    return {name, arg};
481  
}
481  
}
482  

482  

483  
} // url
483  
} // url
484  
} // boost
484  
} // boost
485  

485  

486  
#endif
486  
#endif