]> git.proxmox.com Git - ceph.git/blame - ceph/src/fmt/doc/api.rst
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / fmt / doc / api.rst
CommitLineData
11fdf7f2
TL
1.. _string-formatting-api:
2
3*************
4API Reference
5*************
6
7The {fmt} library API consists of the following parts:
8
20effc67 9* :ref:`fmt/core.h <core-api>`: the core API providing main formatting functions
1e59de90 10 for ``char``/UTF-8 with C++20 compile-time checks and minimal dependencies
20effc67
TL
11* :ref:`fmt/format.h <format-api>`: the full format API providing additional
12 formatting functions and locale support
13* :ref:`fmt/ranges.h <ranges-api>`: formatting of ranges and tuples
f67539c2 14* :ref:`fmt/chrono.h <chrono-api>`: date and time formatting
1e59de90 15* :ref:`fmt/std.h <std-api>`: formatters for standard library types
20effc67
TL
16* :ref:`fmt/compile.h <compile-api>`: format string compilation
17* :ref:`fmt/color.h <color-api>`: terminal color and text style
18* :ref:`fmt/os.h <os-api>`: system APIs
11fdf7f2
TL
19* :ref:`fmt/ostream.h <ostream-api>`: ``std::ostream`` support
20* :ref:`fmt/printf.h <printf-api>`: ``printf`` formatting
20effc67 21* :ref:`fmt/xchar.h <xchar-api>`: optional ``wchar_t`` support
11fdf7f2
TL
22
23All functions and types provided by the library reside in namespace ``fmt`` and
f67539c2 24macros have prefix ``FMT_``.
11fdf7f2
TL
25
26.. _core-api:
27
28Core API
29========
30
1e59de90
TL
31``fmt/core.h`` defines the core API which provides main formatting functions
32for ``char``/UTF-8 with C++20 compile-time checks. It has minimal include
33dependencies for better compile times. This header is only beneficial when
34using {fmt} as a library and not in the header-only mode.
11fdf7f2
TL
35
36The following functions use :ref:`format string syntax <syntax>`
eafe8130 37similar to that of Python's `str.format
20effc67
TL
38<https://docs.python.org/3/library/stdtypes.html#str.format>`_.
39They take *fmt* and *args* as arguments.
11fdf7f2 40
1e59de90
TL
41*fmt* is a format string that contains literal text and replacement fields
42surrounded by braces ``{}``. The fields are replaced with formatted arguments
43in the resulting string. `~fmt::format_string` is a format string which can be
44implicitly constructed from a string literal or a ``constexpr`` string and is
45checked at compile time in C++20. To pass a runtime format string wrap it in
46`fmt::runtime`.
11fdf7f2
TL
47
48*args* is an argument list representing objects to be formatted.
49
50.. _format:
51
20effc67
TL
52.. doxygenfunction:: format(format_string<T...> fmt, T&&... args) -> std::string
53.. doxygenfunction:: vformat(string_view fmt, format_args args) -> std::string
54
55.. doxygenfunction:: format_to(OutputIt out, format_string<T...> fmt, T&&... args) -> OutputIt
1e59de90 56.. doxygenfunction:: format_to_n(OutputIt out, size_t n, format_string<T...> fmt, T&&... args) -> format_to_n_result<OutputIt>
20effc67
TL
57.. doxygenfunction:: formatted_size(format_string<T...> fmt, T&&... args) -> size_t
58
59.. doxygenstruct:: fmt::format_to_n_result
60 :members:
11fdf7f2
TL
61
62.. _print:
63
20effc67 64.. doxygenfunction:: fmt::print(format_string<T...> fmt, T&&... args)
1e59de90 65.. doxygenfunction:: fmt::vprint(string_view fmt, format_args args)
11fdf7f2 66
20effc67
TL
67.. doxygenfunction:: print(std::FILE *f, format_string<T...> fmt, T&&... args)
68.. doxygenfunction:: vprint(std::FILE *f, string_view fmt, format_args args)
69
1e59de90 70Compile-Time Format String Checks
20effc67
TL
71---------------------------------
72
1e59de90
TL
73Compile-time checks are enabled by default on compilers that support C++20
74``consteval``. On older compilers you can use the ``FMT_STRING`` macro defined
75in ``fmt/format.h`` instead. It requires C++14 and is a no-op in C++11.
20effc67
TL
76
77.. doxygendefine:: FMT_STRING
78
1e59de90 79To force the use of legacy compile-time checks, define the preprocessor variable
20effc67 80``FMT_ENFORCE_COMPILE_STRING``. When set, functions accepting ``FMT_STRING``
1e59de90
TL
81will fail to compile with regular strings. Runtime-checked formatting is still
82possible using ``fmt::vformat``, ``fmt::vprint``, etc.
83
84.. doxygenclass:: fmt::basic_format_string
85 :members:
86
87.. doxygentypedef:: fmt::format_string
88
89.. doxygenfunction:: fmt::runtime(string_view) -> basic_runtime<char>
11fdf7f2 90
f67539c2 91Named Arguments
11fdf7f2
TL
92---------------
93
9f95a23c
TL
94.. doxygenfunction:: fmt::arg(const S&, const T&)
95
96Named arguments are not supported in compile-time checks at the moment.
11fdf7f2 97
f67539c2 98Argument Lists
11fdf7f2
TL
99--------------
100
20effc67
TL
101You can create your own formatting function with compile-time checks and small
102binary footprint, for example (https://godbolt.org/z/oba4Mc):
103
104.. code:: c++
105
106 #include <fmt/format.h>
107
108 void vlog(const char* file, int line, fmt::string_view format,
109 fmt::format_args args) {
110 fmt::print("{}: {}: ", file, line);
111 fmt::vprint(format, args);
112 }
113
114 template <typename S, typename... Args>
115 void log(const char* file, int line, const S& format, Args&&... args) {
1e59de90 116 vlog(file, line, format, fmt::make_format_args(args...));
20effc67
TL
117 }
118
119 #define MY_LOG(format, ...) \
120 log(__FILE__, __LINE__, FMT_STRING(format), __VA_ARGS__)
121
122 MY_LOG("invalid squishiness: {}", 42);
123
124Note that ``vlog`` is not parameterized on argument types which improves compile
125times and reduces binary code size compared to a fully parameterized version.
126
11fdf7f2
TL
127.. doxygenfunction:: fmt::make_format_args(const Args&...)
128
129.. doxygenclass:: fmt::format_arg_store
130 :members:
131
f67539c2
TL
132.. doxygenclass:: fmt::dynamic_format_arg_store
133 :members:
134
11fdf7f2
TL
135.. doxygenclass:: fmt::basic_format_args
136 :members:
137
1e59de90 138.. doxygentypedef:: fmt::format_args
11fdf7f2
TL
139
140.. doxygenclass:: fmt::basic_format_arg
141 :members:
142
1e59de90
TL
143.. doxygenclass:: fmt::basic_format_parse_context
144 :members:
145
20effc67
TL
146.. doxygenclass:: fmt::basic_format_context
147 :members:
148
149.. doxygentypedef:: fmt::format_context
150
11fdf7f2
TL
151Compatibility
152-------------
153
154.. doxygenclass:: fmt::basic_string_view
155 :members:
156
157.. doxygentypedef:: fmt::string_view
11fdf7f2 158
f67539c2
TL
159Locale
160------
161
20effc67 162All formatting is locale-independent by default. Use the ``'L'`` format
f67539c2
TL
163specifier to insert the appropriate number separator characters from the
164locale::
165
166 #include <fmt/core.h>
167 #include <locale>
168
169 std::locale::global(std::locale("en_US.UTF-8"));
170 auto s = fmt::format("{:L}", 1000000); // s == "1,000,000"
171
11fdf7f2
TL
172.. _format-api:
173
174Format API
175==========
176
20effc67
TL
177``fmt/format.h`` defines the full format API providing additional formatting
178functions and locale support.
f67539c2 179
20effc67 180.. _udt:
11fdf7f2 181
1e59de90 182Formatting User-Defined Types
11fdf7f2
TL
183-----------------------------
184
1e59de90
TL
185The {fmt} library provides formatters for many standard C++ types.
186See :ref:`fmt/ranges.h <ranges-api>` for ranges and tuples including standard
187containers such as ``std::vector``, :ref:`fmt/chrono.h <chrono-api>` for date
188and time formatting and :ref:`fmt/std.h <std-api>` for path and variant
189formatting.
190
11fdf7f2
TL
191To make a user-defined type formattable, specialize the ``formatter<T>`` struct
192template and implement ``parse`` and ``format`` methods::
193
194 #include <fmt/format.h>
195
1e59de90
TL
196 struct point {
197 double x, y;
198 };
11fdf7f2 199
20effc67 200 template <> struct fmt::formatter<point> {
f67539c2
TL
201 // Presentation format: 'f' - fixed, 'e' - exponential.
202 char presentation = 'f';
203
204 // Parses format specifications of the form ['f' | 'e'].
20effc67 205 constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
f67539c2
TL
206 // [ctx.begin(), ctx.end()) is a character range that contains a part of
207 // the format string starting from the format specifications to be parsed,
208 // e.g. in
209 //
210 // fmt::format("{:f} - point of interest", point{1, 2});
211 //
212 // the range will contain "f} - point of interest". The formatter should
213 // parse specifiers until '}' or the end of the range. In this example
214 // the formatter should parse the 'f' specifier and return an iterator
215 // pointing to '}'.
1e59de90
TL
216
217 // Please also note that this character range may be empty, in case of
218 // the "{}" format string, so therefore you should check ctx.begin()
219 // for equality with ctx.end().
f67539c2
TL
220
221 // Parse the presentation format and store it in the formatter:
222 auto it = ctx.begin(), end = ctx.end();
223 if (it != end && (*it == 'f' || *it == 'e')) presentation = *it++;
224
225 // Check if reached the end of the range:
1e59de90 226 if (it != end && *it != '}') throw format_error("invalid format");
f67539c2
TL
227
228 // Return an iterator past the end of the parsed range:
229 return it;
230 }
11fdf7f2 231
f67539c2
TL
232 // Formats the point p using the parsed format specification (presentation)
233 // stored in this formatter.
11fdf7f2 234 template <typename FormatContext>
1e59de90 235 auto format(const point& p, FormatContext& ctx) const -> decltype(ctx.out()) {
f67539c2 236 // ctx.out() is an output iterator to write to.
1e59de90
TL
237 return presentation == 'f'
238 ? fmt::format_to(ctx.out(), "({:.1f}, {:.1f})", p.x, p.y)
239 : fmt::format_to(ctx.out(), "({:.1e}, {:.1e})", p.x, p.y);
11fdf7f2
TL
240 }
241 };
11fdf7f2
TL
242
243Then you can pass objects of type ``point`` to any formatting function::
244
245 point p = {1, 2};
f67539c2 246 std::string s = fmt::format("{:f}", p);
11fdf7f2
TL
247 // s == "(1.0, 2.0)"
248
f67539c2
TL
249You can also reuse existing formatters via inheritance or composition, for
250example::
11fdf7f2
TL
251
252 enum class color {red, green, blue};
253
f67539c2 254 template <> struct fmt::formatter<color>: formatter<string_view> {
11fdf7f2
TL
255 // parse is inherited from formatter<string_view>.
256 template <typename FormatContext>
1e59de90 257 auto format(color c, FormatContext& ctx) const {
11fdf7f2
TL
258 string_view name = "unknown";
259 switch (c) {
260 case color::red: name = "red"; break;
261 case color::green: name = "green"; break;
262 case color::blue: name = "blue"; break;
263 }
264 return formatter<string_view>::format(name, ctx);
265 }
266 };
267
f67539c2
TL
268Since ``parse`` is inherited from ``formatter<string_view>`` it will recognize
269all string format specifications, for example
270
271.. code-block:: c++
272
273 fmt::format("{:>10}", color::blue)
274
275will return ``" blue"``.
276
eafe8130
TL
277You can also write a formatter for a hierarchy of classes::
278
279 #include <type_traits>
280 #include <fmt/format.h>
281
282 struct A {
283 virtual ~A() {}
284 virtual std::string name() const { return "A"; }
285 };
286
287 struct B : A {
288 virtual std::string name() const { return "B"; }
289 };
290
291 template <typename T>
292 struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
293 fmt::formatter<std::string> {
294 template <typename FormatCtx>
1e59de90 295 auto format(const A& a, FormatCtx& ctx) const {
eafe8130
TL
296 return fmt::formatter<std::string>::format(a.name(), ctx);
297 }
298 };
299
300 int main() {
301 B b;
302 A& a = b;
303 fmt::print("{}", a); // prints "B"
304 }
305
20effc67
TL
306If a type provides both a ``formatter`` specialization and an implicit
307conversion to a formattable type, the specialization takes precedence over the
308conversion.
11fdf7f2 309
1e59de90
TL
310For enums {fmt} also provides the ``format_as`` extension API. To format an enum
311via this API define ``format_as`` that takes this enum and converts it to the
312underlying type. ``format_as`` should be defined in the same namespace as the
313enum.
314
315Example (https://godbolt.org/z/r7vvGE1v7)::
316
317 #include <fmt/format.h>
318
319 namespace kevin_namespacy {
320 enum class film {
321 house_of_cards, american_beauty, se7en = 7
322 };
323 auto format_as(film f) { return fmt::underlying(f); }
324 }
325
326 int main() {
327 fmt::print("{}\n", kevin_namespacy::film::se7en); // prints "7"
328 }
11fdf7f2 329
1e59de90 330Literal-Based API
11fdf7f2
TL
331-----------------
332
333The following user-defined literals are defined in ``fmt/format.h``.
334
1e59de90 335.. doxygenfunction:: operator""_a()
11fdf7f2
TL
336
337Utilities
338---------
339
20effc67
TL
340.. doxygenfunction:: fmt::ptr(T p) -> const void*
341.. doxygenfunction:: fmt::ptr(const std::unique_ptr<T> &p) -> const void*
342.. doxygenfunction:: fmt::ptr(const std::shared_ptr<T> &p) -> const void*
11fdf7f2 343
1e59de90 344.. doxygenfunction:: fmt::underlying(Enum e) -> typename std::underlying_type<Enum>::type
11fdf7f2 345
1e59de90 346.. doxygenfunction:: fmt::to_string(const T &value) -> std::string
f67539c2 347
20effc67 348.. doxygenfunction:: fmt::join(Range &&range, string_view sep) -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>>
f67539c2 349
20effc67 350.. doxygenfunction:: fmt::join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel>
f67539c2 351
1e59de90
TL
352.. doxygenfunction:: fmt::group_digits(T value) -> group_digits_view<T>
353
f67539c2
TL
354.. doxygenclass:: fmt::detail::buffer
355 :members:
9f95a23c 356
11fdf7f2
TL
357.. doxygenclass:: fmt::basic_memory_buffer
358 :protected-members:
359 :members:
360
f67539c2 361System Errors
11fdf7f2
TL
362-------------
363
20effc67
TL
364{fmt} does not use ``errno`` to communicate errors to the user, but it may call
365system functions which set ``errno``. Users should not make any assumptions
366about the value of ``errno`` being preserved by library functions.
11fdf7f2 367
20effc67 368.. doxygenfunction:: fmt::system_error
11fdf7f2
TL
369
370.. doxygenfunction:: fmt::format_system_error
371
f67539c2 372Custom Allocators
11fdf7f2
TL
373-----------------
374
375The {fmt} library supports custom dynamic memory allocators.
376A custom allocator class can be specified as a template argument to
377:class:`fmt::basic_memory_buffer`::
378
379 using custom_memory_buffer =
380 fmt::basic_memory_buffer<char, fmt::inline_buffer_size, custom_allocator>;
381
382It is also possible to write a formatting function that uses a custom
383allocator::
384
385 using custom_string =
386 std::basic_string<char, std::char_traits<char>, custom_allocator>;
387
388 custom_string vformat(custom_allocator alloc, fmt::string_view format_str,
389 fmt::format_args args) {
1e59de90
TL
390 auto buf = custom_memory_buffer(alloc);
391 fmt::vformat_to(std::back_inserter(buf), format_str, args);
11fdf7f2
TL
392 return custom_string(buf.data(), buf.size(), alloc);
393 }
394
395 template <typename ...Args>
396 inline custom_string format(custom_allocator alloc,
397 fmt::string_view format_str,
f67539c2 398 const Args& ... args) {
11fdf7f2
TL
399 return vformat(alloc, format_str, fmt::make_format_args(args...));
400 }
401
20effc67
TL
402The allocator will be used for the output container only. Formatting functions
403normally don't do any allocations for built-in and string types except for
404non-default floating-point formatting that occasionally falls back on
405``sprintf``.
11fdf7f2 406
f67539c2
TL
407.. _ranges-api:
408
1e59de90
TL
409Range and Tuple Formatting
410==========================
f67539c2
TL
411
412The library also supports convenient formatting of ranges and tuples::
413
414 #include <fmt/ranges.h>
415
416 std::tuple<char, int, float> t{'a', 1, 2.0f};
417 // Prints "('a', 1, 2.0)"
418 fmt::print("{}", t);
419
420
421NOTE: currently, the overload of ``fmt::join`` for iterables exists in the main
422``format.h`` header, but expect this to change in the future.
423
424Using ``fmt::join``, you can separate tuple elements with a custom separator::
425
426 #include <fmt/ranges.h>
427
428 std::tuple<int, char> t = {1, 'a'};
429 // Prints "1, a"
430 fmt::print("{}", fmt::join(t, ", "));
431
432.. _chrono-api:
11fdf7f2 433
f67539c2 434Date and Time Formatting
11fdf7f2
TL
435========================
436
20effc67
TL
437``fmt/chrono.h`` provides formatters for
438
439* `std::chrono::duration <https://en.cppreference.com/w/cpp/chrono/duration>`_
440* `std::chrono::time_point
441 <https://en.cppreference.com/w/cpp/chrono/time_point>`_
442* `std::tm <https://en.cppreference.com/w/cpp/chrono/c/tm>`_
443
444The format syntax is described in :ref:`chrono-specs`.
445
446**Example**::
11fdf7f2 447
f67539c2 448 #include <fmt/chrono.h>
11fdf7f2 449
20effc67
TL
450 int main() {
451 std::time_t t = std::time(nullptr);
452
453 // Prints "The date is 2020-11-07." (with the current date):
454 fmt::print("The date is {:%Y-%m-%d}.", fmt::localtime(t));
455
456 using namespace std::literals::chrono_literals;
457
458 // Prints "Default format: 42s 100ms":
459 fmt::print("Default format: {} {}\n", 42s, 100ms);
460
461 // Prints "strftime-like format: 03:15:30":
462 fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
463 }
464
465.. doxygenfunction:: localtime(std::time_t time)
466
467.. doxygenfunction:: gmtime(std::time_t time)
468
1e59de90
TL
469.. _std-api:
470
471Standard Library Types Formatting
472=================================
473
474``fmt/std.h`` provides formatters for:
475
476* `std::filesystem::path <https://en.cppreference.com/w/cpp/filesystem/path>`_
477* `std::thread::id <https://en.cppreference.com/w/cpp/thread/thread/id>`_
478* `std::monostate <https://en.cppreference.com/w/cpp/utility/variant/monostate>`_
479* `std::variant <https://en.cppreference.com/w/cpp/utility/variant/variant>`_
480
481Formatting Variants
482-------------------
483
484A ``std::variant`` is only formattable if every variant alternative is formattable, and requires the
485``__cpp_lib_variant`` `library feature <https://en.cppreference.com/w/cpp/feature_test>`_.
486
487**Example**::
488
489 #include <fmt/std.h>
490
491 std::variant<char, float> v0{'x'};
492 // Prints "variant('x')"
493 fmt::print("{}", v0);
494
495 std::variant<std::monostate, char> v1;
496 // Prints "variant(monostate)"
497
20effc67
TL
498.. _compile-api:
499
1e59de90 500Format String Compilation
20effc67
TL
501=========================
502
1e59de90
TL
503``fmt/compile.h`` provides format string compilation enabled via the
504``FMT_COMPILE`` macro or the ``_cf`` user-defined literal. Format strings
505marked with ``FMT_COMPILE`` or ``_cf`` are parsed, checked and converted into
506efficient formatting code at compile-time. This supports arguments of built-in
507and string types as well as user-defined types with ``constexpr`` ``parse``
508functions in their ``formatter`` specializations. Format string compilation can
509generate more binary code compared to the default API and is only recommended in
510places where formatting is a performance bottleneck.
11fdf7f2 511
20effc67
TL
512.. doxygendefine:: FMT_COMPILE
513
1e59de90
TL
514.. doxygenfunction:: operator""_cf()
515
20effc67
TL
516.. _color-api:
517
1e59de90 518Terminal Color and Text Style
20effc67
TL
519=============================
520
521``fmt/color.h`` provides support for terminal color and text style output.
522
523.. doxygenfunction:: print(const text_style &ts, const S &format_str, const Args&... args)
524
525.. doxygenfunction:: fg(detail::color_type)
526
527.. doxygenfunction:: bg(detail::color_type)
528
1e59de90
TL
529.. doxygenfunction:: styled(const T& value, text_style ts)
530
20effc67
TL
531.. _os-api:
532
533System APIs
534===========
535
536.. doxygenclass:: fmt::ostream
537 :members:
538
539.. doxygenfunction:: fmt::windows_error
540 :members:
11fdf7f2
TL
541
542.. _ostream-api:
543
f67539c2 544``std::ostream`` Support
11fdf7f2
TL
545========================
546
547``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
1e59de90
TL
548user-defined types that have an overloaded insertion operator (``operator<<``).
549In order to make a type formattable via ``std::ostream`` you should provide a
550``formatter`` specialization inherited from ``ostream_formatter``::
11fdf7f2
TL
551
552 #include <fmt/ostream.h>
553
1e59de90
TL
554 struct date {
555 int year, month, day;
11fdf7f2 556
f67539c2 557 friend std::ostream& operator<<(std::ostream& os, const date& d) {
1e59de90 558 return os << d.year << '-' << d.month << '-' << d.day;
11fdf7f2
TL
559 }
560 };
561
1e59de90
TL
562 template <> struct fmt::formatter<date> : ostream_formatter {};
563
564 std::string s = fmt::format("The date is {}", date{2012, 12, 9});
11fdf7f2
TL
565 // s == "The date is 2012-12-9"
566
1e59de90 567.. doxygenfunction:: streamed(const T &)
20effc67 568
1e59de90 569.. doxygenfunction:: print(std::ostream &os, format_string<T...> fmt, T&&... args)
11fdf7f2
TL
570
571.. _printf-api:
572
f67539c2 573``printf`` Formatting
11fdf7f2
TL
574=====================
575
576The header ``fmt/printf.h`` provides ``printf``-like formatting functionality.
577The following functions use `printf format string syntax
20effc67 578<https://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>`_ with
11fdf7f2
TL
579the POSIX extension for positional arguments. Unlike their standard
580counterparts, the ``fmt`` functions are type-safe and throw an exception if an
581argument type doesn't match its format specification.
582
20effc67
TL
583.. doxygenfunction:: printf(const S &format_str, const T&... args)
584
585.. doxygenfunction:: fprintf(std::FILE *f, const S &fmt, const T&... args) -> int
586
587.. doxygenfunction:: sprintf(const S&, const T&...)
588
589.. _xchar-api:
590
591``wchar_t`` Support
592===================
593
1e59de90
TL
594The optional header ``fmt/xchar.h`` provides support for ``wchar_t`` and exotic
595character types.
20effc67
TL
596
597.. doxygenstruct:: fmt::is_char
598
599.. doxygentypedef:: fmt::wstring_view
600
601.. doxygentypedef:: fmt::wformat_context
602
603.. doxygenfunction:: fmt::to_wstring(const T &value)
11fdf7f2 604
20effc67
TL
605Compatibility with C++20 ``std::format``
606========================================
11fdf7f2 607
20effc67
TL
608{fmt} implements nearly all of the `C++20 formatting library
609<https://en.cppreference.com/w/cpp/utility/format>`_ with the following
610differences:
11fdf7f2 611
20effc67
TL
612* Names are defined in the ``fmt`` namespace instead of ``std`` to avoid
613 collisions with standard library implementations.
614* Width calculation doesn't use grapheme clusterization. The latter has been
615 implemented in a separate branch but hasn't been integrated yet.
616* Most C++20 chrono types are not supported yet.