1//
2// Copyright 2019 The Abseil Authors.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// https://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16// -----------------------------------------------------------------------------
17// File: marshalling.h
18// -----------------------------------------------------------------------------
19//
20// This header file defines the API for extending Abseil flag support to
21// custom types, and defines the set of overloads for fundamental types.
22//
23// Out of the box, the Abseil flags library supports the following types:
24//
25// * `bool`
26// * `int16_t`
27// * `uint16_t`
28// * `int32_t`
29// * `uint32_t`
30// * `int64_t`
31// * `uint64_t`
32// * `float`
33// * `double`
34// * `std::string`
35// * `std::vector<std::string>`
36//
37// Note that support for integral types is implemented using overloads for
38// variable-width fundamental types (`short`, `int`, `long`, etc.). However,
39// you should prefer the fixed-width integral types (`int32_t`, `uint64_t`,
40// etc.) we've noted above within flag definitions.
41
42//
43// In addition, several Abseil libraries provide their own custom support for
44// Abseil flags.
45//
46// The Abseil time library provides the following support for civil time values:
47//
48// * `absl::CivilSecond`
49// * `absl::CivilMinute`
50// * `absl::CivilHour`
51// * `absl::CivilDay`
52// * `absl::CivilMonth`
53// * `absl::CivilYear`
54//
55// and also provides support for the following absolute time values:
56//
57// * `absl::Duration`
58// * `absl::Time`
59//
60// Additional support for Abseil types will be noted here as it is added.
61//
62// You can also provide your own custom flags by adding overloads for
63// `AbslParseFlag()` and `AbslUnparseFlag()` to your type definitions. (See
64// below.)
65//
66// -----------------------------------------------------------------------------
67// Adding Type Support for Abseil Flags
68// -----------------------------------------------------------------------------
69//
70// To add support for your user-defined type, add overloads of `AbslParseFlag()`
71// and `AbslUnparseFlag()` as free (non-member) functions to your type. If `T`
72// is a class type, these functions can be friend function definitions. These
73// overloads must be added to the same namespace where the type is defined, so
74// that they can be discovered by Argument-Dependent Lookup (ADL).
75//
76// Example:
77//
78// namespace foo {
79//
80// enum OutputMode { kPlainText, kHtml };
81//
82// // AbslParseFlag converts from a string to OutputMode.
83// // Must be in same namespace as OutputMode.
84//
85// // Parses an OutputMode from the command line flag value `text. Returns
86// // `true` and sets `*mode` on success; returns `false` and sets `*error`
87// // on failure.
88// bool AbslParseFlag(absl::string_view text,
89// OutputMode* mode,
90// std::string* error) {
91// if (text == "plaintext") {
92// *mode = kPlainText;
93// return true;
94// }
95// if (text == "html") {
96// *mode = kHtml;
97// return true;
98// }
99// *error = "unknown value for enumeration";
100// return false;
101// }
102//
103// // AbslUnparseFlag converts from an OutputMode to a string.
104// // Must be in same namespace as OutputMode.
105//
106// // Returns a textual flag value corresponding to the OutputMode `mode`.
107// std::string AbslUnparseFlag(OutputMode mode) {
108// switch (mode) {
109// case kPlainText: return "plaintext";
110// case kHtml: return "html";
111// }
112// return absl::StrCat(mode);
113// }
114//
115// Notice that neither `AbslParseFlag()` nor `AbslUnparseFlag()` are class
116// members, but free functions. `AbslParseFlag/AbslUnparseFlag()` overloads
117// for a type should only be declared in the same file and namespace as said
118// type. The proper `AbslParseFlag/AbslUnparseFlag()` implementations for a
119// given type will be discovered via Argument-Dependent Lookup (ADL).
120//
121// `AbslParseFlag()` may need, in turn, to parse simpler constituent types
122// using `absl::ParseFlag()`. For example, a custom struct `MyFlagType`
123// consisting of a `std::pair<int, std::string>` would add an `AbslParseFlag()`
124// overload for its `MyFlagType` like so:
125//
126// Example:
127//
128// namespace my_flag_type {
129//
130// struct MyFlagType {
131// std::pair<int, std::string> my_flag_data;
132// };
133//
134// bool AbslParseFlag(absl::string_view text, MyFlagType* flag,
135// std::string* err);
136//
137// std::string AbslUnparseFlag(const MyFlagType&);
138//
139// // Within the implementation, `AbslParseFlag()` will, in turn invoke
140// // `absl::ParseFlag()` on its constituent `int` and `std::string` types
141// // (which have built-in Abseil flag support.
142//
143// bool AbslParseFlag(absl::string_view text, MyFlagType* flag,
144// std::string* err) {
145// std::pair<absl::string_view, absl::string_view> tokens =
146// absl::StrSplit(text, ',');
147// if (!absl::ParseFlag(tokens.first, &flag->my_flag_data.first, err))
148// return false;
149// if (!absl::ParseFlag(tokens.second, &flag->my_flag_data.second, err))
150// return false;
151// return true;
152// }
153//
154// // Similarly, for unparsing, we can simply invoke `absl::UnparseFlag()` on
155// // the constituent types.
156// std::string AbslUnparseFlag(const MyFlagType& flag) {
157// return absl::StrCat(absl::UnparseFlag(flag.my_flag_data.first),
158// ",",
159// absl::UnparseFlag(flag.my_flag_data.second));
160// }
161#ifndef ABSL_FLAGS_MARSHALLING_H_
162#define ABSL_FLAGS_MARSHALLING_H_
163
164#include <string>
165#include <vector>
166
167#include "absl/strings/string_view.h"
168
169namespace absl {
170namespace flags_internal {
171
172// Overloads of `AbslParseFlag()` and `AbslUnparseFlag()` for fundamental types.
173bool AbslParseFlag(absl::string_view, bool*, std::string*);
174bool AbslParseFlag(absl::string_view, short*, std::string*); // NOLINT
175bool AbslParseFlag(absl::string_view, unsigned short*, std::string*); // NOLINT
176bool AbslParseFlag(absl::string_view, int*, std::string*); // NOLINT
177bool AbslParseFlag(absl::string_view, unsigned int*, std::string*); // NOLINT
178bool AbslParseFlag(absl::string_view, long*, std::string*); // NOLINT
179bool AbslParseFlag(absl::string_view, unsigned long*, std::string*); // NOLINT
180bool AbslParseFlag(absl::string_view, long long*, std::string*); // NOLINT
181bool AbslParseFlag(absl::string_view, unsigned long long*,
182 std::string*); // NOLINT
183bool AbslParseFlag(absl::string_view, float*, std::string*);
184bool AbslParseFlag(absl::string_view, double*, std::string*);
185bool AbslParseFlag(absl::string_view, std::string*, std::string*);
186bool AbslParseFlag(absl::string_view, std::vector<std::string>*, std::string*);
187
188template <typename T>
189bool InvokeParseFlag(absl::string_view input, T* dst, std::string* err) {
190 // Comment on next line provides a good compiler error message if T
191 // does not have AbslParseFlag(absl::string_view, T*, std::string*).
192 return AbslParseFlag(input, dst, err); // Is T missing AbslParseFlag?
193}
194
195// Strings and std:: containers do not have the same overload resolution
196// considerations as fundamental types. Naming these 'AbslUnparseFlag' means we
197// can avoid the need for additional specializations of Unparse (below).
198std::string AbslUnparseFlag(absl::string_view v);
199std::string AbslUnparseFlag(const std::vector<std::string>&);
200
201template <typename T>
202std::string Unparse(const T& v) {
203 // Comment on next line provides a good compiler error message if T does not
204 // have UnparseFlag.
205 return AbslUnparseFlag(v); // Is T missing AbslUnparseFlag?
206}
207
208// Overloads for builtin types.
209std::string Unparse(bool v);
210std::string Unparse(short v); // NOLINT
211std::string Unparse(unsigned short v); // NOLINT
212std::string Unparse(int v); // NOLINT
213std::string Unparse(unsigned int v); // NOLINT
214std::string Unparse(long v); // NOLINT
215std::string Unparse(unsigned long v); // NOLINT
216std::string Unparse(long long v); // NOLINT
217std::string Unparse(unsigned long long v); // NOLINT
218std::string Unparse(float v);
219std::string Unparse(double v);
220
221} // namespace flags_internal
222
223// ParseFlag()
224//
225// Parses a string value into a flag value of type `T`. Do not add overloads of
226// this function for your type directly; instead, add an `AbslParseFlag()`
227// free function as documented above.
228//
229// Some implementations of `AbslParseFlag()` for types which consist of other,
230// constituent types which already have Abseil flag support, may need to call
231// `absl::ParseFlag()` on those consituent string values. (See above.)
232template <typename T>
233inline bool ParseFlag(absl::string_view input, T* dst, std::string* error) {
234 return flags_internal::InvokeParseFlag(input, dst, error);
235}
236
237// UnparseFlag()
238//
239// Unparses a flag value of type `T` into a string value. Do not add overloads
240// of this function for your type directly; instead, add an `AbslUnparseFlag()`
241// free function as documented above.
242//
243// Some implementations of `AbslUnparseFlag()` for types which consist of other,
244// constituent types which already have Abseil flag support, may want to call
245// `absl::UnparseFlag()` on those constituent types. (See above.)
246template <typename T>
247inline std::string UnparseFlag(const T& v) {
248 return flags_internal::Unparse(v);
249}
250
251} // namespace absl
252
253#endif // ABSL_FLAGS_MARSHALLING_H_
254