/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include namespace apache { namespace thrift { namespace op { namespace detail { template struct PatchType {}; template <> struct PatchType { using type = op::BoolPatch; }; template <> struct PatchType { using type = op::BytePatch; }; template <> struct PatchType { using type = op::I16Patch; }; template <> struct PatchType { using type = op::I32Patch; }; template <> struct PatchType { using type = op::I64Patch; }; template <> struct PatchType { using type = op::FloatPatch; }; template <> struct PatchType { using type = op::DoublePatch; }; template <> struct PatchType { using type = op::StringPatch; }; template <> struct PatchType { using type = op::BinaryPatch; }; template struct PatchType> { using type = StructPatch< ::apache::thrift::detail::st::private_access::patch_struct>; }; template struct PatchType> { using type = UnionPatch<::apache::thrift::detail::st::private_access::patch_struct>; }; template struct SafePatchType {}; template struct SafePatchType> { using type = ::apache::thrift::detail::st::private_access::safe_patch; }; template struct SafePatchType> { using type = ::apache::thrift::detail::st::private_access::safe_patch; }; } // namespace detail /// The safe patch represenations for the base thrift types. /// /// Safe patch provides versioning to indicate the minimum Thrift Patch version /// required to safely and successfully process that patch as well as opaque /// storage that is resilient to Thrift schema compatibility. template using safe_patch_type = typename detail::SafePatchType>::type; /// The patch represenations for the base thrift types. /// /// All patch types support the following methods: /// - empty() - Returns true iff the patch is a noop. /// - reset() - Makes the patch a noop. /// - apply(T&& value) - Applies the patch to the given value, in place. /// - merge(P&& next) - Merges the 'next' patch into this one, such that the /// result is equivalent to applying this and next in sequence. /// - assign(U&& value) - Updates the patch to assign the given value. /// - operator=(U&& value) - An alias for assign. /// - get() - Returns the underlying Thrift representation for the patch. /// /// For example: /// * int32_t value = 1; /// * I32Patch patch; /// * patch = 2; // Equivalent to calling patch.assign(2). /// * patch.apply(value); // Sets value to 2; template using patch_type = typename detail::PatchType>::type; template inline constexpr bool is_patch_v = false; template inline constexpr bool is_patch_v> = std::is_base_of_v, T>; template inline constexpr bool is_assign_only_patch_v = false; template inline constexpr bool is_assign_only_patch_v> = true; template std::string prettyPrintPatch( const T& obj, DebugProtocolWriter::Options options = DebugProtocolWriter::Options::simple()) { static_assert(is_patch_v, "Argument must be a Patch."); return debugStringViaEncode(obj, std::move(options)); } /** * Returns a Thrift Patch instance corresponding to the (decoded) `SafePatch`. * * @throws std::runtime_error if the given `SafePatch` cannot be successfully * decoded or safely applied in this process (eg. if the version of the Thrift * Patch library in this process is not compatible with the minimum version * required by `SafePatch`). */ template > op::patch_type fromSafePatch(const op::safe_patch_type& safePatch) { if (safePatch.version() == 0) { throw std::runtime_error("Invalid Safe Patch"); } if (safePatch.version() > detail::kThriftStaticPatchVersion) { throw std::runtime_error( fmt::format("Unsupported patch version: {}", *safePatch.version())); } op::patch_type patch; CompactProtocolReader reader; reader.setInput(safePatch.data()->get()); op::decode>>(reader, patch); return patch; } /** * Returns a `SafePatch` instance corresponding to the encoded Thrift Patch. */ template > op::safe_patch_type toSafePatch(const op::patch_type& patch) { folly::IOBufQueue queue; CompactProtocolWriter writer; writer.setOutput(&queue); op::encode>>(writer, patch); op::safe_patch_type safePatch; safePatch.data() = queue.move(); safePatch.version() = detail::kThriftStaticPatchVersion; return safePatch; } } // namespace op } // namespace thrift } // namespace apache