userver: userver/ugrpc/field_mask.hpp Source File
Loading...
Searching...
No Matches
field_mask.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/ugrpc/field_mask.hpp
4/// @brief @copybrief ugrpc::FieldMask
5
6#include <stdexcept>
7#include <string>
8#include <string_view>
9#include <vector>
10
11#include <userver/utils/fast_pimpl.hpp>
12#include <userver/utils/impl/projecting_view.hpp>
13#include <userver/utils/impl/transparent_hash.hpp>
14#include <userver/utils/optional_ref.hpp>
15#include <userver/utils/str_icase.hpp>
16
17namespace google::protobuf {
18
19class Descriptor;
20class FieldMask;
21class Message;
22
23} // namespace google::protobuf
24
25USERVER_NAMESPACE_BEGIN
26
27namespace ugrpc {
28
29/// @brief Utilities to process the field masks. Respects Google's AIP-161: https://google.aip.dev/161.
30///
31/// 1. An empty mask is treated as a mask with all fields.
32/// 2. Map masks (i.e. `reviews` and `reviews.smith` for `map<string, string> reviews`).
33/// 3. Wildcard masks for repeated and map fields (i.e. `authors`, `authors.*`, `authors.*.name`).
34/// 4. Backticks (`) are separation charaters for problematic keys and may not appear in paths.
35class FieldMask {
36public:
37 class BadPathError : public std::runtime_error {
38 public:
39 explicit BadPathError(const std::string& msg) : std::runtime_error(msg) {}
40 };
41
42 /// @brief Construct an empty field-mask
43 FieldMask() = default;
44
45 FieldMask(FieldMask&&) = default;
46 FieldMask(const FieldMask&) = default;
47
48 FieldMask& operator=(FieldMask& other) = default;
49 FieldMask& operator=(FieldMask&& other) = default;
50
51 /// @brief Constructs the field-mask from a raw gRPC field-mask
52 explicit FieldMask(const google::protobuf::FieldMask& field_mask);
53
54 enum class Encoding { kCommaSeparated = 0, kWebSafeBase64 = 1 };
55
56 /// @brief Constructs the field-mask from its string representation
57 FieldMask(std::string_view string, Encoding encoding);
58
59 /// @brief Constructs a human-readable string representation of the field-mask
60 std::string ToString() const;
61
62 /// @brief Constructs a string representation of the field-mask suitable to transfer over the Internet
63 std::string ToWebSafeBase64() const;
64
65 /// @brief Adds a dot-separated path to the field mask.
66 /// Backtick (`) is treated as a separation character according to AIP-161
67 /// and may not appear in the path.
68 ///
69 /// @throws BadPathError if the path is malformed.
70 /// In this case, the state of the field mask is undefined.
71 /// You must not continue using the instance after encountering the exception.
72 void AddPath(std::string_view path);
73
74 /// @brief Check if the field mask is valid for this message.
75 ///
76 /// @throws BadPathError if the field mask contains invalid paths.
77 void CheckValidity(const google::protobuf::Descriptor* descriptor) const;
78
79 /// @brief Does this field-mask fully contain the given path.
80 /// @throws BadPathError if the path is malformed.
81 bool IsPathFullyIn(std::string_view path) const;
82
83 /// @brief Does this field-mask contain the given path or any of its child paths.
84 /// @throws BadPathError if the path is malformed.
85 bool IsPathPartiallyIn(std::string_view path) const;
86
87 /// @brief Remove all fields not present in the field-mask from the message.
88 /// The mask must be valid for this to work. Use @ref IsValid to check.
89 ///
90 /// @throws BadPathError if the field mask contains invalid paths.
91 ///
92 /// @warning This causes a segmentation fault for messages that contain
93 /// optional fields in protobuf versions prior to 3.13.
94 /// See https://github.com/protocolbuffers/protobuf/issues/7801
95 void Trim(google::protobuf::Message& message) const;
96
97 /// @brief Same as @ref Trim but does not perform pre-validation of the mask.
98 /// You should not catch any errors generated by this method.
99 /// Use this only if you are absolutely sure the mask is valid.
100 ///
101 /// @warning This causes a segmentation fault for messages that contain
102 /// optional fields in protobuf versions prior to 3.13.
103 /// See https://github.com/protocolbuffers/protobuf/issues/7801
104 void TrimNoValidate(google::protobuf::Message& message) const;
105
106 /// @brief Checks if there are any nested masks inside this mask
107 bool IsLeaf() const;
108
109 /// @brief Gets the names of all masked fields inside this mask.
110 /// Returns an std::ranges::transform_view containing std::string_view.
111 auto GetFieldNames() const {
112 return utils::impl::ProjectingView(*children_, [](const auto& e) -> std::string_view { return e.first; });
113 }
114
115 /// @brief Gets the names of all masked fields inside this mask. Returns an std::vector.
117
118 /// @brief Checks if the specified field is in the mask
119 bool HasFieldName(std::string_view field) const;
120
121 /// @brief Gets the nested mask or returns nullopt if the field is not in the mask
122 utils::OptionalRef<const FieldMask> GetMaskForField(std::string_view field) const;
123
124private:
125 google::protobuf::FieldMask ToRawMask() const;
126
127 void ToRawMaskImpl(std::vector<std::string>& stack, google::protobuf::FieldMask& out) const;
128
130 bool is_leaf_{false};
131};
132
133} // namespace ugrpc
134
135USERVER_NAMESPACE_END