1 // Copyright 2019 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 // Provides the ToString function, which outputs string representations of
17 // arbitrary types to a buffer.
18 //
19 // ToString returns the number of characters written, excluding the null
20 // terminator, and a status. A null terminator is always written if the output
21 // buffer has room.
22 //
23 // ToString functions may be defined for any type. This is done by providing a
24 // ToString template specialization in the pw namespace. The specialization must
25 // follow ToString's semantics:
26 //
27 // 1. Always null terminate if the output buffer has room.
28 // 2. Return the number of characters written, excluding the null terminator,
29 // as a StatusWithSize.
30 // 3. If the buffer is too small to fit the output, return a StatusWithSize
31 // with the number of characters written and a status of
32 // RESOURCE_EXHAUSTED. Other status codes may be used for different errors.
33 //
34 // For example, providing the following specialization would allow ToString, and
35 // any classes that use it, to print instances of a custom type:
36 //
37 // namespace pw {
38 //
39 // template <>
40 // StatusWithSize ToString<SomeCustomType>(const SomeCustomType& value,
41 // std::span<char> buffer) {
42 // return /* ... implementation ... */;
43 // }
44 //
45 // } // namespace pw
46 //
47 // Note that none of the functions in this module use std::snprintf. ToString
48 // overloads may use snprintf if needed, but the ToString semantics must be
49 // maintained.
50 //
51 // ToString is a low-level function. To write complex objects to string, a
52 // StringBuilder may be easier to work with. StringBuilder's operator<< may be
53 // overloaded for custom types.
54
55 #include <span>
56 #include <string_view>
57 #include <type_traits>
58
59 #include "pw_status/status.h"
60 #include "pw_string/type_to_string.h"
61
62 namespace pw {
63
64 // This function provides string printing numeric types, enums, and anything
65 // that convertible to a std::string_view, such as std::string.
66 template <typename T>
ToString(const T & value,std::span<char> buffer)67 StatusWithSize ToString(const T& value, std::span<char> buffer) {
68 if constexpr (std::is_same_v<std::remove_cv_t<T>, bool>) {
69 return string::BoolToString(value, buffer);
70 } else if constexpr (std::is_same_v<std::remove_cv_t<T>, char>) {
71 return string::CopyString(std::string_view(&value, 1), buffer);
72 } else if constexpr (std::is_integral_v<T>) {
73 return string::IntToString(value, buffer);
74 } else if constexpr (std::is_enum_v<T>) {
75 return string::IntToString(std::underlying_type_t<T>(value), buffer);
76 } else if constexpr (std::is_floating_point_v<T>) {
77 return string::FloatAsIntToString(value, buffer);
78 } else if constexpr (std::is_convertible_v<T, std::string_view>) {
79 return string::CopyString(value, buffer);
80 } else if constexpr (std::is_pointer_v<std::remove_cv_t<T>> ||
81 std::is_null_pointer_v<T>) {
82 return string::PointerToString(value, buffer);
83 } else {
84 // By default, no definition of UnknownTypeToString is provided.
85 return string::UnknownTypeToString(value, buffer);
86 }
87 }
88
89 // ToString overloads for Pigweed types. To override ToString for a custom type,
90 // specialize the ToString template function.
ToString(Status status,std::span<char> buffer)91 inline StatusWithSize ToString(Status status, std::span<char> buffer) {
92 return string::CopyString(status.str(), buffer);
93 }
94
ToString(pw_Status status,std::span<char> buffer)95 inline StatusWithSize ToString(pw_Status status, std::span<char> buffer) {
96 return ToString(Status(status), buffer);
97 }
98
ToString(std::byte byte,std::span<char> buffer)99 inline StatusWithSize ToString(std::byte byte, std::span<char> buffer) {
100 return string::IntToHexString(static_cast<unsigned>(byte), buffer);
101 }
102
103 } // namespace pw
104