/* * 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 #include #include namespace apache { namespace thrift { namespace op { namespace detail { // If the given field is absent/unset/void. template type::if_optional_or_union_field_ref isAbsent(const T& opt) { return !opt.has_value(); } template constexpr bool isAbsent(union_field_ref opt) { return !opt.has_value(); } template constexpr bool isAbsent(field_ref) { return false; } template constexpr bool isAbsent(terse_field_ref) { return false; } template constexpr bool isAbsent(terse_intern_boxed_field_ref) { return false; } template [[deprecated]] constexpr bool isAbsent(required_field_ref) { return false; } template constexpr bool isAbsent(std::unique_ptr& ptr) { return ptr == nullptr; } template constexpr bool isAbsent(std::shared_ptr& ptr) { return ptr == nullptr; } template > auto ensureValue(T&& opt) -> decltype(opt.value()) { if (isAbsent(opt)) { opt.emplace(); } return opt.value(); } template decltype(auto) ensureValue(union_field_ref val) { return val.ensure(); } template decltype(auto) ensureValue(field_ref val) { return val.ensure(); } template decltype(auto) ensureValue(terse_field_ref val) { // A terse field doesn't have a set or unset state, so ensure is a noop. return *val; } template decltype(auto) ensureValue(terse_intern_boxed_field_ref val) { // A terse field doesn't have a set or unset state, so ensure is a noop. return *val; } template [[deprecated]] decltype(auto) ensureValue(required_field_ref val) { // A required field doesn't have a set or unset state, so ensure is a noop. return *val; } template T& ensureValue(std::unique_ptr& ptr) { if (ptr == nullptr) { ptr = std::make_unique(); } return *ptr; } template T& ensureValue(std::shared_ptr& ptr) { if (ptr == nullptr) { ptr = std::make_shared(); } return *ptr; } template struct Create { static_assert(type::is_concrete_v, ""); template > constexpr T operator()() const { return T{}; } }; // TODO: Support adapted field, smart pointers with custom allocators. // TODO: Optionally accept a custom default. template struct Ensure { template constexpr decltype(auto) operator()(T& obj) const { return ensureValue(op::get(obj)); } }; template struct Ensure { template constexpr decltype(auto) operator()(T& obj) const { return Ensure>{}(obj); } }; template <> struct Ensure { template constexpr decltype(auto) operator()(Id, T& obj) const { return Ensure{}(obj); } }; template struct Create> { using adapted_tag = type::adapted; static_assert(type::is_concrete_v, ""); template > constexpr T operator()() const { // Note, we use op::create to create the intrinsic default of underlying // type since the underlying type might be another adapted type is not // default constructible. return Adapter::fromThrift(Create{}()); } }; // TODO(dokwon): Support field_ref types. template struct Create> : Create {}; template struct Create< type::field, FieldContext>> { using field_adapted_tag = type::field, FieldContext>; static_assert(type::is_concrete_v, ""); template constexpr adapt_detail:: if_not_field_adapter, Struct> operator()(Struct&) const { return AdapterT::fromThrift(Create{}()); } template constexpr adapt_detail:: if_field_adapter, Struct> operator()(Struct& object) const { auto obj = AdapterT::fromThriftField( Create{}(), FieldContext{object}); adapt_detail::construct(obj, object); return obj; } }; // TODO(afuller): Migrate all usage and remove. template struct Ensure> { using field_tag = type::field; static_assert(type::is_concrete_v, ""); template decltype(auto) operator()(T&& val, Struct&) const { return ensureValue(std::forward(val)); } }; } // namespace detail } // namespace op } // namespace thrift } // namespace apache