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 : namespace boost {
20 : namespace urls {
21 :
22 : /** Format arguments into a URL
23 :
24 : Format arguments according to the format
25 : URL string into a @ref url.
26 :
27 : The rules for a format URL string are the same
28 : as for a `std::format_string`, where replacement
29 : fields are delimited by curly braces.
30 :
31 : The URL components to which replacement fields
32 : belong are identified before replacement is
33 : applied and any invalid characters for that
34 : formatted argument are percent-escaped.
35 :
36 : Hence, the delimiters between URL components,
37 : such as `:`, `//`, `?`, and `#`, should be
38 : included in the URL format string. Likewise,
39 : a format string with a single `"{}"` is
40 : interpreted as a path and any replacement
41 : characters invalid in this component will be
42 : encoded to form a valid URL.
43 :
44 : @par Example
45 : @code
46 : assert(format("{}", "Hello world!").buffer() == "Hello%20world%21");
47 : @endcode
48 :
49 : @par Preconditions
50 : All replacement fields must be valid and the
51 : resulting URL should be valid after arguments
52 : are formatted into the URL.
53 :
54 : Because any invalid characters for a URL
55 : component are encoded by this function, only
56 : replacements in the scheme and port components
57 : might be invalid, as these components do not
58 : allow percent-encoding of arbitrary
59 : characters.
60 :
61 : @return A URL holding the formatted result.
62 :
63 : @param fmt The format URL string.
64 : @param args Arguments to be formatted.
65 :
66 : @throws system_error
67 : `fmt` contains an invalid format string and
68 : the result contains an invalid URL after
69 : replacements are applied.
70 :
71 : @par BNF
72 : @code
73 : replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
74 : arg_id ::= integer | identifier
75 : integer ::= digit+
76 : digit ::= "0"..."9"
77 : identifier ::= id_start id_continue*
78 : id_start ::= "a"..."z" | "A"..."Z" | "_"
79 : id_continue ::= id_start | digit
80 : @endcode
81 :
82 : @par Specification
83 : @li <a href="https://fmt.dev/latest/syntax.html"
84 : >Format String Syntax</a>
85 :
86 : @see
87 : @ref format_to.
88 :
89 : */
90 : template <class... Args>
91 : url
92 141 : format(
93 : core::string_view fmt,
94 : Args&&... args)
95 : {
96 : return detail::vformat(
97 141 : fmt, detail::make_format_args(
98 141 : std::forward<Args>(args)...));
99 : }
100 :
101 : /** Format arguments into a URL
102 :
103 : Format arguments according to the format
104 : URL string into a @ref url_base.
105 :
106 : The rules for a format URL string are the same
107 : as for a `std::format_string`, where replacement
108 : fields are delimited by curly braces.
109 :
110 : The URL components to which replacement fields
111 : belong are identified before replacement is
112 : applied and any invalid characters for that
113 : formatted argument are percent-escaped.
114 :
115 : Hence, the delimiters between URL components,
116 : such as `:`, `//`, `?`, and `#`, should be
117 : included in the URL format string. Likewise,
118 : a format string with a single `"{}"` is
119 : interpreted as a path and any replacement
120 : characters invalid in this component will be
121 : encoded to form a valid URL.
122 :
123 : @par Example
124 : @code
125 : static_url<30> u;
126 : format(u, "{}", "Hello world!");
127 : assert(u.buffer() == "Hello%20world%21");
128 : @endcode
129 :
130 : @par Preconditions
131 : All replacement fields must be valid and the
132 : resulting URL should be valid after arguments
133 : are formatted into the URL.
134 :
135 : Because any invalid characters for a URL
136 : component are encoded by this function, only
137 : replacements in the scheme and port components
138 : might be invalid, as these components do not
139 : allow percent-encoding of arbitrary
140 : characters.
141 :
142 : @par Exception Safety
143 : Strong guarantee.
144 :
145 : @param u An object that derives from @ref url_base.
146 : @param fmt The format URL string.
147 : @param args Arguments to be formatted.
148 :
149 : @throws system_error
150 : `fmt` contains an invalid format string and
151 : `u` contains an invalid URL after replacements
152 : are applied.
153 :
154 : @par BNF
155 : @code
156 : replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
157 : arg_id ::= integer | identifier
158 : integer ::= digit+
159 : digit ::= "0"..."9"
160 : identifier ::= id_start id_continue*
161 : id_start ::= "a"..."z" | "A"..."Z" | "_"
162 : id_continue ::= id_start | digit
163 : @endcode
164 :
165 : @par Specification
166 : @li <a href="https://fmt.dev/latest/syntax.html"
167 : >Format String Syntax</a>
168 :
169 : @see
170 : @ref format.
171 :
172 : */
173 : template <class... Args>
174 : void
175 3 : format_to(
176 : url_base& u,
177 : core::string_view fmt,
178 : Args&&... args)
179 : {
180 3 : detail::vformat_to(
181 3 : u, fmt, detail::make_format_args(
182 : std::forward<Args>(args)...));
183 2 : }
184 :
185 : /** Format arguments into a URL
186 :
187 : Format arguments according to the format
188 : URL string into a @ref url.
189 :
190 : This overload allows type-erased arguments
191 : to be passed as an initializer_list, which
192 : is mostly convenient for named parameters.
193 :
194 : All arguments must be convertible to a
195 : implementation defined type able to store a
196 : type-erased reference to any valid format
197 : argument.
198 :
199 : The rules for a format URL string are the same
200 : as for a `std::format_string`, where replacement
201 : fields are delimited by curly braces.
202 :
203 : The URL components to which replacement fields
204 : belong are identified before replacement is
205 : applied and any invalid characters for that
206 : formatted argument are percent-escaped.
207 :
208 : Hence, the delimiters between URL components,
209 : such as `:`, `//`, `?`, and `#`, should be
210 : included in the URL format string. Likewise,
211 : a format string with a single `"{}"` is
212 : interpreted as a path and any replacement
213 : characters invalid in this component will be
214 : encoded to form a valid URL.
215 :
216 : @par Example
217 : @code
218 : assert(format("user/{id}", {{"id", 1}}).buffer() == "user/1");
219 : @endcode
220 :
221 : @par Preconditions
222 : All replacement fields must be valid and the
223 : resulting URL should be valid after arguments
224 : are formatted into the URL.
225 :
226 : Because any invalid characters for a URL
227 : component are encoded by this function, only
228 : replacements in the scheme and port components
229 : might be invalid, as these components do not
230 : allow percent-encoding of arbitrary
231 : characters.
232 :
233 : @return A URL holding the formatted result.
234 :
235 : @param fmt The format URL string.
236 : @param args Arguments to be formatted.
237 :
238 : @throws system_error
239 : `fmt` contains an invalid format string and
240 : the result contains an invalid URL after
241 : replacements are applied.
242 :
243 : @par BNF
244 : @code
245 : replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
246 : arg_id ::= integer | identifier
247 : integer ::= digit+
248 : digit ::= "0"..."9"
249 : identifier ::= id_start id_continue*
250 : id_start ::= "a"..."z" | "A"..."Z" | "_"
251 : id_continue ::= id_start | digit
252 : @endcode
253 :
254 : @par Specification
255 : @li <a href="https://fmt.dev/latest/syntax.html"
256 : >Format String Syntax</a>
257 :
258 : @see
259 : @ref format_to.
260 :
261 : */
262 : inline
263 : url
264 2 : format(
265 : core::string_view fmt,
266 : #ifdef BOOST_URL_DOCS
267 : std::initializer_list<__see_below__> args
268 : #else
269 : std::initializer_list<see_below::format_arg> args
270 : #endif
271 : )
272 : {
273 : return detail::vformat(
274 : fmt, detail::format_args(
275 2 : args.begin(), args.end()));
276 : }
277 :
278 : /** Format arguments into a URL
279 :
280 : Format arguments according to the format
281 : URL string into a @ref url_base.
282 :
283 : This overload allows type-erased arguments
284 : to be passed as an initializer_list, which
285 : is mostly convenient for named parameters.
286 :
287 : All arguments must be convertible to a
288 : implementation defined type able to store a
289 : type-erased reference to any valid format
290 : argument.
291 :
292 : The rules for a format URL string are the same
293 : as for a `std::format_string`, where replacement
294 : fields are delimited by curly braces.
295 :
296 : The URL components to which replacement fields
297 : belong are identified before replacement is
298 : applied and any invalid characters for that
299 : formatted argument are percent-escaped.
300 :
301 : Hence, the delimiters between URL components,
302 : such as `:`, `//`, `?`, and `#`, should be
303 : included in the URL format string. Likewise,
304 : a format string with a single `"{}"` is
305 : interpreted as a path and any replacement
306 : characters invalid in this component will be
307 : encoded to form a valid URL.
308 :
309 : @par Example
310 : @code
311 : static_url<30> u;
312 : format_to(u, "user/{id}", {{"id", 1}})
313 : assert(u.buffer() == "user/1");
314 : @endcode
315 :
316 : @par Preconditions
317 : All replacement fields must be valid and the
318 : resulting URL should be valid after arguments
319 : are formatted into the URL.
320 :
321 : Because any invalid characters for a URL
322 : component are encoded by this function, only
323 : replacements in the scheme and port components
324 : might be invalid, as these components do not
325 : allow percent-encoding of arbitrary
326 : characters.
327 :
328 : @par Exception Safety
329 : Strong guarantee.
330 :
331 : @param u An object that derives from @ref url_base.
332 : @param fmt The format URL string.
333 : @param args Arguments to be formatted.
334 :
335 : @throws system_error
336 : `fmt` contains an invalid format string and
337 : `u` contains an invalid URL after replacements
338 : are applied.
339 :
340 : @par BNF
341 : @code
342 : replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
343 : arg_id ::= integer | identifier
344 : integer ::= digit+
345 : digit ::= "0"..."9"
346 : identifier ::= id_start id_continue*
347 : id_start ::= "a"..."z" | "A"..."Z" | "_"
348 : id_continue ::= id_start | digit
349 : @endcode
350 :
351 : @par Specification
352 : @li <a href="https://fmt.dev/latest/syntax.html"
353 : >Format String Syntax</a>
354 :
355 : @see
356 : @ref format.
357 :
358 : */
359 : inline
360 : void
361 1 : format_to(
362 : url_base& u,
363 : core::string_view fmt,
364 : #ifdef BOOST_URL_DOCS
365 : std::initializer_list<__see_below__> args
366 : #else
367 : std::initializer_list<see_below::format_arg> args
368 : #endif
369 : )
370 : {
371 1 : detail::vformat_to(
372 : u, fmt, detail::format_args(
373 : args.begin(), args.end()));
374 1 : }
375 :
376 : /** Designate a named argument for a replacement field
377 :
378 : Construct a named argument for a format URL
379 : string that contains named replacement fields.
380 :
381 : The function parameters should be convertible
382 : to an implementation defined type able to
383 : store the name and a reference to any type
384 : potentially used as a format argument.
385 :
386 : @par Example
387 : @code
388 : assert(format("user/{id}", arg("id", 1)).buffer() == "user/1");
389 : @endcode
390 :
391 : @return An temporary object with reference
392 : semantics for a named argument
393 :
394 : @param name The argument name
395 : @param arg The argument value
396 :
397 : @see
398 : @ref format,
399 : @ref format_to.
400 :
401 : */
402 : template <class T>
403 : BOOST_URL_IMPLEMENTATION_DEFINED(implementation_defined::named_arg<T>)
404 19 : arg(core::string_view name, T const& arg)
405 : {
406 19 : return {name, arg};
407 : }
408 :
409 : } // url
410 : } // boost
411 :
412 : #endif
|