| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_COMMON_PRIVACY_BUDGET_FIELD_TRIAL_PARAM_CONVERSIONS_H_ |
| #define CHROME_COMMON_PRIVACY_BUDGET_FIELD_TRIAL_PARAM_CONVERSIONS_H_ |
| |
| #include <iterator> |
| #include <type_traits> |
| #include <vector> |
| |
| #include "base/ranges/algorithm.h" |
| #include "base/strings/strcat.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_piece.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "third_party/blink/public/common/privacy_budget/identifiable_surface.h" |
| |
| // The Encode/Decode families of functions are meant to be used to encode |
| // various types so that they can be specified via field trial configurations |
| // and Prefs. |
| |
| namespace privacy_budget_internal { |
| |
| // DecodeIdentifiabilityType() overloads should not be called directly. Instead |
| // use either DecodeIdentifiabilityFieldTrialParam() or |
| // EncodeIdentifiabilityFieldTrialParam(). |
| // |
| // DecodeIdentifiabilityType(StringPiece s,V* v) decodes a element of type |
| // V serialized as a string and referred to via StringPiece s and stores it in |
| // *v. |
| bool DecodeIdentifiabilityType(const base::StringPiece, |
| blink::IdentifiableSurface*); |
| bool DecodeIdentifiabilityType(const base::StringPiece, |
| blink::IdentifiableSurface::Type*); |
| bool DecodeIdentifiabilityType(const base::StringPiece, int*); |
| bool DecodeIdentifiabilityType(const base::StringPiece, unsigned int*); |
| bool DecodeIdentifiabilityType(const base::StringPiece, double*); |
| bool DecodeIdentifiabilityType(const base::StringPiece, |
| std::vector<blink::IdentifiableSurface>*); |
| |
| // V is a std::pair<P,R> where P and R are types known to |
| // DecodeIdentifiabilityType(). |
| template < |
| typename V, |
| typename P = typename std::remove_const<typename V::first_type>::type, |
| typename R = typename std::remove_const<typename V::second_type>::type> |
| bool DecodeIdentifiabilityType(base::StringPiece s, V* result) { |
| auto pieces = |
| base::SplitStringPiece(s, ";", base::WhitespaceHandling::TRIM_WHITESPACE, |
| base::SplitResult::SPLIT_WANT_NONEMPTY); |
| if (pieces.size() != 2) |
| return false; |
| P first; |
| R second; |
| if (!DecodeIdentifiabilityType(pieces[0], &first) || |
| !DecodeIdentifiabilityType(pieces[1], &second)) |
| return false; |
| ::new (result) V(std::move(first), std::move(second)); |
| return true; |
| } |
| |
| std::string EncodeIdentifiabilityType(const blink::IdentifiableSurface&); |
| std::string EncodeIdentifiabilityType(const blink::IdentifiableSurface::Type&); |
| std::string EncodeIdentifiabilityType(const unsigned int&); |
| std::string EncodeIdentifiabilityType(const double&); |
| template <typename T, typename U> |
| std::string EncodeIdentifiabilityType(const std::pair<T, U>& v) { |
| return base::StrCat({EncodeIdentifiabilityType(v.first), ";", |
| base::NumberToString(v.second)}); |
| } |
| std::string EncodeIdentifiabilityType( |
| const std::vector<blink::IdentifiableSurface>& value); |
| |
| template <typename T> |
| struct NoOpFilter { |
| bool operator()(T t) { return true; } |
| }; |
| |
| // Instantiate with a type and inherit from std::true_type in order to sort the |
| // encoded elements of a container. The ordering is undefined but stable across |
| // versions of Chrome. |
| template <typename T> |
| struct SortWhenSerializing : std::false_type {}; |
| |
| } // namespace privacy_budget_internal |
| |
| // Decodes a field trial parameter containing a list of values. The result is |
| // returned in the form of a container type that must be specified at |
| // instantiation. There should be a valid DecodeIdentifiabilityType |
| // specialization for the container's value type. |
| template <typename T, |
| char Separator = ',', |
| typename V = typename T::value_type, |
| bool ElementDecoder(const base::StringPiece, V*) = |
| &privacy_budget_internal::DecodeIdentifiabilityType> |
| T DecodeIdentifiabilityFieldTrialParam(base::StringPiece encoded_value) { |
| T result; |
| auto pieces = |
| base::SplitStringPiece(encoded_value, std::string(1, Separator), |
| base::WhitespaceHandling::TRIM_WHITESPACE, |
| base::SplitResult::SPLIT_WANT_NONEMPTY); |
| auto inserter = std::inserter(result, result.end()); |
| for (const auto& piece : pieces) { |
| V v; |
| if (!ElementDecoder(piece, &v)) |
| continue; |
| inserter = v; |
| } |
| return result; |
| } |
| |
| // Encodes a field trial parameter that will contain a list of values taken from |
| // a container. The container must satisfy the named requirement Container. Its |
| // value_type must have a corresponding EncodeIdentifiabilityType |
| // specialization. |
| template <typename T, |
| std::string ElementEncoder(const typename T::value_type&) = |
| privacy_budget_internal::EncodeIdentifiabilityType> |
| std::string EncodeIdentifiabilityFieldTrialParam(const T& source) { |
| std::vector<std::string> encoded_elements; |
| encoded_elements.reserve(source.size()); |
| for (const auto& v : source) { |
| encoded_elements.emplace_back(ElementEncoder(v)); |
| } |
| if (privacy_budget_internal::SortWhenSerializing< |
| typename std::remove_cv<T>::type>::value) { |
| base::ranges::sort(encoded_elements); |
| } |
| return base::JoinString(encoded_elements, ","); |
| } |
| |
| #endif // CHROME_COMMON_PRIVACY_BUDGET_FIELD_TRIAL_PARAM_CONVERSIONS_H_ |