Skip to content

Commit af70a3e

Browse files
authored
Add JSValue constructor for std::optional<T> (#6873)
* Add JSValue constructor for std::optional<T> * Change files
1 parent a188c30 commit af70a3e

File tree

3 files changed

+89
-0
lines changed

3 files changed

+89
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "Add JSValue constructor for std::optional<T>",
4+
"packageName": "react-native-windows",
5+
"email": "vmorozov@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}

vnext/Microsoft.ReactNative.Cxx.UnitTests/JSValueTest.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,76 @@ TEST_CLASS (JSValueTest) {
304304
TestCheckEqual(4.2, *value11.TryGetDouble());
305305
}
306306

307+
TEST_METHOD(TestJSValueStdOptionalConstructor) {
308+
auto value001 = JSValue{std::optional{nullptr}};
309+
auto value002 = JSValue{std::optional{JSValueObject{{"prop1", 3}}}};
310+
auto value003 = JSValue{std::optional{JSValueObject{}}};
311+
auto value004 = JSValue{std::optional{JSValueArray{1, 2}}};
312+
auto value005 = JSValue{std::optional{JSValueArray{}}};
313+
auto value006 = JSValue{std::optional{"Hello"}};
314+
auto value007 = JSValue{std::optional{true}};
315+
auto value008 = JSValue{std::optional{false}};
316+
auto value009 = JSValue{std::optional{0}};
317+
auto value010 = JSValue{std::optional{42}};
318+
auto value011 = JSValue{std::optional{4.2}};
319+
320+
TestCheckEqual(JSValueType::Null, value001.Type());
321+
TestCheckEqual(JSValueType::Object, value002.Type());
322+
TestCheckEqual(JSValueType::Object, value003.Type());
323+
TestCheckEqual(JSValueType::Array, value004.Type());
324+
TestCheckEqual(JSValueType::Array, value005.Type());
325+
TestCheckEqual(JSValueType::String, value006.Type());
326+
TestCheckEqual(JSValueType::Boolean, value007.Type());
327+
TestCheckEqual(JSValueType::Boolean, value008.Type());
328+
TestCheckEqual(JSValueType::Int64, value009.Type());
329+
TestCheckEqual(JSValueType::Int64, value010.Type());
330+
TestCheckEqual(JSValueType::Double, value011.Type());
331+
332+
TestCheck(value001.IsNull());
333+
TestCheckEqual(1u, value002.TryGetObject()->size());
334+
TestCheckEqual(0u, value003.TryGetObject()->size());
335+
TestCheckEqual(2u, value004.TryGetArray()->size());
336+
TestCheckEqual(0u, value005.TryGetArray()->size());
337+
TestCheckEqual("Hello", *value006.TryGetString());
338+
TestCheckEqual(true, *value007.TryGetBoolean());
339+
TestCheckEqual(false, *value008.TryGetBoolean());
340+
TestCheckEqual(0, *value009.TryGetInt64());
341+
TestCheckEqual(42, *value010.TryGetInt64());
342+
TestCheckEqual(4.2, *value011.TryGetDouble());
343+
344+
auto value101 = JSValue{std::nullopt};
345+
TestCheckEqual(JSValueType::Null, value101.Type());
346+
TestCheck(value101.IsNull());
347+
348+
auto value201 = JSValue{std::optional<std::nullptr_t>{std::nullopt}};
349+
auto value202 = JSValue{std::optional<JSValueObject>{std::nullopt}};
350+
auto value203 = JSValue{std::optional<JSValueArray>{std::nullopt}};
351+
auto value204 = JSValue{std::optional<const char *>{std::nullopt}};
352+
auto value205 = JSValue{std::optional<std::string>{std::nullopt}};
353+
auto value206 = JSValue{std::optional<std::string_view>{std::nullopt}};
354+
auto value207 = JSValue{std::optional<bool>{std::nullopt}};
355+
auto value208 = JSValue{std::optional<int32_t>{std::nullopt}};
356+
auto value209 = JSValue{std::optional<int64_t>{std::nullopt}};
357+
auto value210 = JSValue{std::optional<uint32_t>{std::nullopt}};
358+
auto value211 = JSValue{std::optional<uint64_t>{std::nullopt}};
359+
auto value212 = JSValue{std::optional<double>{std::nullopt}};
360+
auto value213 = JSValue{std::optional<float>{std::nullopt}};
361+
362+
TestCheckEqual(JSValueType::Null, value201.Type());
363+
TestCheckEqual(JSValueType::Null, value202.Type());
364+
TestCheckEqual(JSValueType::Null, value203.Type());
365+
TestCheckEqual(JSValueType::Null, value204.Type());
366+
TestCheckEqual(JSValueType::Null, value205.Type());
367+
TestCheckEqual(JSValueType::Null, value206.Type());
368+
TestCheckEqual(JSValueType::Null, value207.Type());
369+
TestCheckEqual(JSValueType::Null, value208.Type());
370+
TestCheckEqual(JSValueType::Null, value209.Type());
371+
TestCheckEqual(JSValueType::Null, value210.Type());
372+
TestCheckEqual(JSValueType::Null, value211.Type());
373+
TestCheckEqual(JSValueType::Null, value212.Type());
374+
TestCheckEqual(JSValueType::Null, value213.Type());
375+
}
376+
307377
TEST_METHOD(TestJSValueImplicitCast) {
308378
// We do not assign values directly here sbecause it would be an explicit constructor call.
309379
JSValue value01, value02, value03, value04, value05, value06, value07, value08, value09, value10, value11, value12,

vnext/Microsoft.ReactNative.Cxx/JSValue.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,14 @@ struct JSValue {
223223
//! Create a Double JSValue.
224224
JSValue(double value) noexcept;
225225

226+
//! Creates JSValue from std::optional<T>. The result type is defined by T.
227+
//! If std::optional does not have value, then the result is JSValue::Null.
228+
template <class T>
229+
explicit JSValue(std::optional<T> &&value) noexcept;
230+
231+
//! Creates a Null JSValue.
232+
explicit JSValue(std::nullopt_t) noexcept;
233+
226234
//! Delete the copy constructor to avoid unexpected copies. Use the Copy method instead.
227235
JSValue(const JSValue &other) = delete;
228236

@@ -607,6 +615,10 @@ inline JSValue::JSValue(TBool value) noexcept : m_type{JSValueType::Boolean}, m_
607615
template <class TInt, std::enable_if_t<std::is_integral_v<TInt> && !std::is_same_v<TInt, bool>, int>>
608616
inline JSValue::JSValue(TInt value) noexcept : m_type{JSValueType::Int64}, m_int64{static_cast<int64_t>(value)} {}
609617
inline JSValue::JSValue(double value) noexcept : m_type{JSValueType::Double}, m_double{value} {}
618+
template <class T>
619+
inline JSValue::JSValue(std::optional<T> &&value) noexcept
620+
: JSValue(value.has_value() ? JSValue(std::move(value).value()) : JSValue()) {}
621+
inline JSValue::JSValue(std::nullopt_t) noexcept : JSValue{} {}
610622
#pragma warning(pop)
611623

612624
inline JSValueType JSValue::Type() const noexcept {

0 commit comments

Comments
 (0)