blob: 9d2a8fe25f04da5e021650ea80c84e7d9ef253db [file] [log] [blame]
François Degros899487c2019-07-12 11:57:52 +10001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CROS_DISKS_QUOTE_H_
6#define CROS_DISKS_QUOTE_H_
7
8#include <ostream>
9#include <string>
10#include <utility>
11
12#include <base/files/file_path.h>
François Degrosca450862021-01-14 14:40:02 +110013#include <base/logging.h>
François Degros899487c2019-07-12 11:57:52 +100014
15namespace cros_disks {
16
17// Helper struct that holds a non-owning const reference to a T and allows to
18// print a quoted version of it to an output stream.
19//
20// Don't use it directly. Call quote() instead.
21template <typename T>
22struct Quoter {
23 const T& ref;
François Degrosca450862021-01-14 14:40:02 +110024 const bool redacted = false;
François Degros899487c2019-07-12 11:57:52 +100025};
26
27// Allows to print a quoted version of its argument to an output stream for
28// logging purpose.
29//
30// T must be a quotable type, ie a string, a FilePath or a vector of quotable
31// elements.
32//
33// The returned Quoter should be streamed directly without being stored.
34// The typical usage pattern is:
35//
36// LOG(ERROR) << "Cannot do something with " << quote(stuff) << ": Reason why";
37template <typename T>
38Quoter<T> quote(const T& ref) {
39 return {ref};
40}
41
François Degrosca450862021-01-14 14:40:02 +110042// Allows to print a quoted version of its argument to an output stream for
43// logging purpose, or a redacted version if the current log level is less than
44// INFO.
45//
46// T must be a quotable type, ie a string, a FilePath or a vector of quotable
47// elements.
48//
49// The returned Quoter should be streamed directly without being stored.
50// The typical usage pattern is:
51//
52// LOG(ERROR) << "Cannot do something with " << redact(stuff) << ": Reason why";
53template <typename T>
54Quoter<T> redact(const T& ref, const bool redacted = !LOG_IS_ON(INFO)) {
55 return {ref, redacted};
56}
57
François Degros899487c2019-07-12 11:57:52 +100058// Outputs a quoted C-style string, or (null) for a null pointer.
59std::ostream& operator<<(std::ostream& out, Quoter<const char*> quoter);
60
61// Outputs a quoted standard string.
62std::ostream& operator<<(std::ostream& out, Quoter<std::string> quoter);
63
64// Outputs a quoted file path.
65std::ostream& operator<<(std::ostream& out, Quoter<base::FilePath> quoter);
66
67// Outputs a quoted string literal.
68// This is needed because quote("some string literal") doesn't decay the passed
69// string literal to a const char* but keeps it as a reference to a const
70// char[N].
71template <size_t N>
72std::ostream& operator<<(std::ostream& out, Quoter<char[N]> quoter) {
73 const char* const s = quoter.ref;
François Degrosca450862021-01-14 14:40:02 +110074 return out << redact(s, quoter.redacted);
François Degros899487c2019-07-12 11:57:52 +100075}
76
77// Outputs a sequence of quoted items.
78template <typename T, typename = decltype(std::declval<const T&>().begin())>
79std::ostream& operator<<(std::ostream& out, Quoter<T> quoter) {
80 out << '[';
81 const char* sep = "";
82 for (const auto& item : quoter.ref) {
François Degrosca450862021-01-14 14:40:02 +110083 out << std::exchange(sep, ", ") << redact(item, quoter.redacted);
François Degros899487c2019-07-12 11:57:52 +100084 }
85 return out << ']';
86}
87
88} // namespace cros_disks
89
90#endif // CROS_DISKS_QUOTE_H_