/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include #include #include namespace facebook::react::bridging { // std::remove_cvref_t is not available until C++20. template using remove_cvref_t = std::remove_cv_t>; template inline constexpr bool is_jsi_v = std::is_same_v> || std::is_same_v> || std::is_base_of_v>; template struct is_optional : std::false_type {}; template struct is_optional> : std::true_type {}; template inline constexpr bool is_optional_v = is_optional::value; template struct Converter; template struct ConverterBase { using BaseT = remove_cvref_t; ConverterBase(jsi::Runtime &rt, T &&value) : rt_(rt), value_(std::forward(value)) {} operator BaseT() && { if constexpr (std::is_lvalue_reference_v) { // Copy the reference into a Value that then can be moved from. auto value = jsi::Value(rt_, value_); if constexpr (std::is_same_v) { return std::move(value); } else if constexpr (std::is_same_v) { return std::move(value).getString(rt_); } else if constexpr (std::is_same_v) { return std::move(value).getObject(rt_); } else if constexpr (std::is_same_v) { return std::move(value).getObject(rt_).getArray(rt_); } else if constexpr (std::is_same_v) { return std::move(value).getObject(rt_).getFunction(rt_); } } else { return std::move(value_); } } template < typename U, std::enable_if_t< std::is_lvalue_reference_v && // Ensure non-reference type can be converted to the desired type. std::is_convertible_v, U>, int> = 0> operator U() && { return Converter(rt_, std::move(*this).operator BaseT()); } template < typename U, std::enable_if_t && std::is_same_v, int> = 0> operator U() && = delete; // Prevent unwanted upcasting of JSI values. protected: jsi::Runtime &rt_; T value_; }; template struct Converter : public ConverterBase { using ConverterBase::ConverterBase; }; template <> struct Converter : public ConverterBase { using ConverterBase::ConverterBase; operator jsi::String() && { return std::move(value_).asString(rt_); } operator jsi::Object() && { return std::move(value_).asObject(rt_); } operator jsi::Array() && { return std::move(value_).asObject(rt_).asArray(rt_); } operator jsi::Function() && { return std::move(value_).asObject(rt_).asFunction(rt_); } }; template <> struct Converter : public ConverterBase { using ConverterBase::ConverterBase; operator jsi::Array() && { return std::move(value_).asArray(rt_); } operator jsi::Function() && { return std::move(value_).asFunction(rt_); } }; template struct Converter> : public ConverterBase { Converter(jsi::Runtime &rt, std::optional value) : ConverterBase(rt, value ? std::move(*value) : jsi::Value::null()) {} operator std::optional() && { if (value_.isNull() || value_.isUndefined()) { return {}; } return std::move(value_); } }; template , int> = 0> auto convert(jsi::Runtime &rt, T &&value) { return Converter(rt, std::forward(value)); } template < typename T, std::enable_if_t || std::is_scalar_v, int> = 0> auto convert(jsi::Runtime &rt, std::optional value) { return Converter>(rt, std::move(value)); } template , int> = 0> auto convert(jsi::Runtime &rt, T &&value) { return value; } template auto convert(jsi::Runtime &rt, Converter &&converter) { return std::move(converter); } } // namespace facebook::react::bridging