7#pragma push_macro("None")
10#include <Ultralight/CAPI/CAPI_JSAPI.h>
11#include <Ultralight/CAPI/CAPI_JSValue.h>
12#include <Ultralight/CAPI/CAPI_String.h>
13#include <Ultralight/detail/Exceptions.h>
34template <
typename T,
typename =
void>
73 None = kULJSPropertyAttributes_None,
85 return static_cast<PropertyAttributes>(
static_cast<unsigned>(a) |
static_cast<unsigned>(b));
95enum class Type :
unsigned {
100 Number = kULJSType_Number,
104 Object = kULJSType_Object,
107static_assert(kULJSType_Count == 9,
"js::Type must list every ULJSType");
221 : handle_(other.handle_ ? ulCreateJSValueRef(other.handle_) : nullptr) {}
226 Value(
Value&& other) noexcept : handle_(other.handle_) { other.handle_ =
nullptr; }
232 std::swap(handle_, other.handle_);
244 explicit operator bool()
const {
return IsAlive(); }
249 bool IsEmpty()
const {
return handle_ ==
nullptr; }
257 bool IsAlive()
const {
return handle_ && ulJSValueIsAlive(handle_); }
265 Type type()
const {
return static_cast<Type>(ulJSValueGetType(handle_)); }
312 bool IsArray()
const {
return handle_ && ulJSValueIsArray(handle_); }
317 bool IsCallable()
const {
return handle_ && ulJSValueIsCallable(handle_); }
325 bool IsFunction()
const {
return handle_ && ulJSValueIsFunction(handle_); }
332 bool IsPromise()
const {
return handle_ && ulJSValueIsPromise(handle_); }
341 return detail::EmptyHandleError();
343 if (!ulJSValueToBoolean(handle_, &result))
356 return detail::EmptyHandleError();
358 ULJSValue exception =
nullptr;
359 if (!ulJSValueToNumber(handle_, &result, &exception)) {
375 return detail::EmptyHandleError();
376 ULJSValue exception =
nullptr;
377 if (ulJSValueGetType(handle_) == kULJSType_String) {
379 char stack_buffer[256];
381 if (ulJSValueGetUTF8(handle_, stack_buffer,
sizeof(stack_buffer), &length, &exception))
382 return std::string(stack_buffer, length);
383 if (!exception && length >
sizeof(stack_buffer)) {
384 std::string heap(length,
'\0');
385 if (ulJSValueGetUTF8(handle_, heap.data(), heap.size(), &length, &exception))
392 ULString s = ulJSValueToString(handle_, &exception);
398 std::string result(ulStringGetData(s), ulStringGetLength(s));
415 return detail::EmptyHandleError();
416 ULJSValue exception =
nullptr;
417 ULString s = ulJSValueToJSON(handle_, indent, &exception);
423 if (ulJSValueIsAlive(handle_))
424 return Unexpected<Error>(
Error::TypeError(
"The value has no JSON representation."));
427 std::string result(ulStringGetData(s), ulStringGetLength(s));
442 return detail::EmptyHandleError();
443 ULJSValue exception =
nullptr;
444 ULJSValue result = ulJSObjectGetProperty(handle_, name ? name :
"", &exception);
450 return Adopt(result);
463 bool Has(
const char* name)
const {
464 return handle_ && ulJSObjectHasProperty(handle_, name ? name :
"",
nullptr);
477 return detail::EmptyHandleError();
478 ULJSValue exception =
nullptr;
479 bool present = ulJSObjectHasProperty(handle_, name ? name :
"", &exception);
508 const char* name,
const Value& value,
511 return detail::EmptyHandleError();
512 ULJSValue exception =
nullptr;
513 if (ulJSObjectSetProperty(handle_, name ? name :
"", value.handle_,
514 static_cast<unsigned>(attributes), &exception))
536 return detail::EmptyHandleError();
537 ULJSValue raw_args[8];
538 ULJSValue* arg_ptr = raw_args;
541 arg_ptr =
new ULJSValue[argc];
543 for (
size_t i = 0; i < argc; i++)
544 arg_ptr[i] = args[i].handle_;
545 ULJSValue exception =
nullptr;
546 ULJSValue result = ulJSFunctionCall(handle_, this_value.handle_, arg_ptr, argc, &exception);
547 if (arg_ptr != raw_args)
554 return Adopt(result);
569 std::span<const Value> args)
const {
570 return Call(this_value, args.data(), args.size());
597 template <
typename T>
605 template <
typename T>
606 [[nodiscard]] std::optional<T>
Maybe()
const;
618 template <
typename T>
619 [[nodiscard]] T
Or(T fallback)
const;
628 [[nodiscard]] std::string
Or(
const char* fallback)
const;
648 template <
typename R =
Value,
typename... A>
664 template <
typename R =
Value,
typename... A>
674 template <
typename... A>
715 template <
typename F>
716 [[nodiscard]]
bool Then(F&& on_settled)
const {
717 using Fn = std::decay_t<F>;
718 static_assert(std::is_invocable_v<Fn&, Result<Value>>,
719 "js::Value::Then takes a callable invocable with js::Result<js::Value>");
720 auto* fn =
new Fn(std::forward<F>(on_settled));
722 return ulJSPromiseThen(handle_, &ThenThunk<Fn>, fn, &DeleteThenCallable<Fn>);
741 template <
typename T,
typename F>
742 requires(!std::is_same_v<T, Value>)
743 [[nodiscard]]
bool Then(F&& on_settled)
const {
744 using Fn = std::decay_t<F>;
745 static_assert(std::is_invocable_v<Fn&, Result<T>>,
746 "js::Value::Then<T> takes a callable invocable with js::Result<T>");
747 return Then(TypedSettleAdapter<T, Fn> { std::forward<F>(on_settled) });
781 template <
typename I>
782 requires(std::is_integral_v<I> && !std::is_same_v<I, bool>)
783 Ref
operator[](I index)
const;
812 return Value(handle ? ulCreateJSValueRef(handle) :
nullptr);
820 ULJSValue
raw()
const {
return handle_; }
828 ULJSValue handle = handle_;
834 explicit Value(ULJSValue handle) : handle_(handle) {}
842 static IndexKey MakeIndexKey(
long long value) {
844 snprintf(key.text,
sizeof(key.text),
"%lld", value);
848 static IndexKey MakeIndexKey(
unsigned long long value) {
850 snprintf(key.text,
sizeof(key.text),
"%llu", value);
854 template <
typename I>
855 Ref MakeIndexRef(I index)
const;
859 template <
typename T,
typename Fn>
860 struct TypedSettleAdapter {
864 fn(
Result<T>(Unexpected<Error>(std::move(settled).error())));
866 fn(settled.value().To<T>());
870 template <
typename Fn>
871 static void ThenThunk(
void* user_data,
ULJSContext, ULJSValue result,
bool rejected) {
872 Fn& fn = *
static_cast<Fn*
>(user_data);
874 ultralight::detail::CallCatchingExceptions(
884 [](
const char* what) { detail::LogNativeException(
"js::Value::Then", what); });
887 template <
typename Fn>
888 static void DeleteThenCallable(
void* user_data) {
889 delete static_cast<Fn*
>(user_data);
915 detail::SwallowedException swallow;
918 object_.raw() ? ulJSObjectGetPropertyAtIndex(object_.raw(), index_, swallow.out())
921 object_.raw() ? ulJSObjectGetProperty(object_.raw(), name_.c_str(), swallow.out())
940 template <
typename T>
952 return Chained(value, value[name]);
954 template <
typename I>
955 requires(std::is_integral_v<I> && !std::is_same_v<I, bool>)
956 Ref operator[](I index)
const {
958 return Chained(value, value[index]);
974 template <
typename R =
Value,
typename... A>
984 template <
typename... A>
994 template <
typename T>
1002 template <
typename T>
1003 [[nodiscard]] std::optional<T>
Maybe()
const;
1012 template <
typename T>
1013 [[nodiscard]] T
Or(T fallback)
const;
1022 [[nodiscard]] std::string
Or(
const char* fallback)
const {
return Get().
Or(fallback); }
1044 Ref(
Value object,
const char* name)
1045 : object_(
std::move(object)), name_(name ? name :
""), by_index_(false), index_(0) {}
1047 : object_(
std::move(object)), by_index_(true), index_(index) {}
1051 bool SourceGone()
const {
return source_gone_ || (object_.
raw() && !object_.
IsAlive()); }
1056 next.source_gone_ = value.IsEmpty() && SourceGone();
1064 bool source_gone_ =
false;
1068 return Ref(*
this, name);
1071template <
typename I>
1072Value::Ref Value::MakeIndexRef(I index)
const {
1073 if constexpr (std::is_signed_v<I>) {
1075 return Ref(*
this, MakeIndexKey(
static_cast<long long>(index)).text);
1077 unsigned long long wide =
static_cast<unsigned long long>(index);
1078 if (wide > SIZE_MAX)
1079 return Ref(*
this, MakeIndexKey(wide).text);
1080 return Ref(*
this,
static_cast<size_t>(wide));
1083template <
typename I>
1084 requires(std::is_integral_v<I> && !std::is_same_v<I, bool>)
1086 return MakeIndexRef(index);
1127 explicit Arg(ULJSValue borrowed) : borrowed_(borrowed) {}
1136 bool IsEmpty()
const {
return borrowed_ ==
nullptr; }
1141 Type type()
const {
return static_cast<Type>(ulJSValueGetType(borrowed_)); }
1150 template <
typename T>
1158 template <
typename T>
1159 [[nodiscard]] std::optional<T>
Maybe()
const;
1168 template <
typename T>
1169 [[nodiscard]] T
Or(T fallback)
const;
1178 [[nodiscard]] std::string
Or(
const char* fallback)
const;
1192 ULJSValue
raw()
const {
return borrowed_; }
1195 ULJSValue borrowed_;
1219template <
typename T>
1220[[nodiscard]] T
Or(
const Value& value, T fallback) {
1221 return value.
Or(std::move(fallback));
1233[[nodiscard]]
inline std::string
Or(
const Value& value,
const char* fallback) {
1234 return value.
Or(fallback);
1246template <
typename T>
1247[[nodiscard]] T
Or(
const Arg& arg, T fallback) {
1248 return arg.
Or(std::move(fallback));
1260[[nodiscard]]
inline std::string
Or(
const Arg& arg,
const char* fallback) {
1261 return arg.
Or(fallback);
1273template <
typename R,
typename T>
1274 requires std::is_same_v<std::remove_cvref_t<R>,
Result<Value>>
1275[[nodiscard]] T
Or(
const R& result, T fallback) {
1276 return result ? result.value().Or(std::move(fallback)) : fallback;
1288template <
typename R>
1289 requires std::is_same_v<std::remove_cvref_t<R>,
Result<Value>>
1290[[nodiscard]] std::string
Or(
const R& result,
const char* fallback) {
1291 return result ? result.value().Or(fallback) : std::string(fallback ? fallback :
"");
1306template <
typename T,
typename U>
1307 requires(!std::is_same_v<T, Value>)
1309 return result.value_or(std::forward<U>(fallback));
1333#pragma pop_macro("None")
struct C_JSContext * ULJSContext
Opaque handle to a JavaScript execution context (one page's script world in one View).
Definition View.h:25
Unicode string container with conversions for UTF-8, UTF-16, and UTF-32.
Definition String.h:31
An argument passed to a bound function.
Definition Value.h:1118
std::string Or(const char *fallback) const
Convert to a std::string like To() but with a string-literal fallback.
T Or(T fallback) const
Convert to a C++ type like To() but with a fallback.
bool IsEmpty() const
Whether or not the argument is absent (the call passed fewer arguments than the index given to CallIn...
Definition Value.h:1136
Result< T > To() const
Convert to a C++ type (see Value::To()).
std::optional< T > Maybe() const
Convert to a C++ type like To() but without the failure reason.
Type type() const
Get the argument's type (Type::Invalid if the argument is absent).
Definition Value.h:1141
Arg(ULJSValue borrowed)
Wrap a borrowed handle.
Definition Value.h:1127
Value ToValue() const
Get a Value that keeps the argument after the callback returns.
Definition Value.h:1185
ULJSValue raw() const
Get the C API handle.
Definition Value.h:1192
An error from a JavaScript operation.
Definition Error.h:115
static Error AdoptException(ULJSValue exception)
Create an error from a JavaScript exception, taking ownership of the handle.
Definition Error.h:131
static Error TypeError(std::string message)
Create a native TypeError.
Definition Error.h:144
static Error PageGone()
Create a page-gone error (is_page_gone() returns true).
Definition Error.h:122
ULJSValue exception() const
Get the JavaScript exception (NULL if is_exception() is false).
Definition Error.h:268
A reference to a property of a Value (returned by Value::operator[]).
Definition Value.h:906
Ref operator[](const char *name) const
Read this property and access a property of its value.
Definition Value.h:950
Ref & operator=(const Ref &other)
Set this property to the value of another Ref's property.
Definition Value.h:1039
Ref(const Ref &)=default
Copy constructor (refers to the same property).
std::string Or(const char *fallback) const
Read the property and convert it to a std::string with a string-literal fallback.
Definition Value.h:1022
T Or(T fallback) const
Read the property and convert it to a C++ type with a fallback.
Ref & operator=(T &&value)
Set the property to value (converted through js::TypeTraits).
Value Get() const
Read the property.
Definition Value.h:914
Result< R > Invoke(A &&... args) const
Call the property as a method of its object (otherwise the same as Value::Invoke()).
Result< Value > operator()(A &&... args) const
Call the property as a method: obj["save"](path) is the same as obj["save"].Invoke(path).
Definition Value.h:985
Result< T > To() const
Read the property and convert it to a C++ type (see Value::To()).
friend class Context
Definition Value.h:1043
std::optional< T > Maybe() const
Read the property and convert it to a C++ type like To() but without the failure reason.
friend class Value
Definition Value.h:1042
A handle to a live JavaScript value.
Definition Value.h:210
bool Has(const char *name) const
Whether or not this object has a property (own or inherited).
Definition Value.h:463
Ref operator[](const char *name) const
Access a property to read, assign, or call it.
Definition Value.h:1067
Value(Value &&other) noexcept
Move constructor (other becomes empty).
Definition Value.h:226
Value & operator=(Value other) noexcept
Assignment (copies or moves other into this Value).
Definition Value.h:231
std::string Or(const char *fallback) const
Convert to a std::string like To() but with a string-literal fallback.
static Value Adopt(ULJSValue handle)
Take ownership of a handle from the C API without adding a reference.
Definition Value.h:799
bool IsCallable() const
Whether or not the value can be called (see Call() and Invoke()).
Definition Value.h:317
static Value FromBorrowed(ULJSValue handle)
Add a reference to a handle the library owns (eg, a callback argument) so it can outlive the callback...
Definition Value.h:811
Result< double > ToNumber() const
Convert to a number using JavaScript's rules.
Definition Value.h:354
Result< std::string > ToString() const
Convert to a UTF-8 string using JavaScript's rules.
Definition Value.h:373
ULJSValue LeakRef()
Give up ownership of the C API handle and return it (like RefPtr::LeakRef()).
Definition Value.h:827
T Or(T fallback) const
Convert to a C++ type like To() but with a fallback.
Value(const Value &other)
Copy constructor (adds a reference to the same JavaScript value).
Definition Value.h:220
Result< R > InvokeOn(const Value &this_value, A &&... args) const
Call this value as a function with an explicit this (otherwise the same as Invoke()).
Result< bool > HasProperty(const char *name) const
Whether or not this object has a property (like Has(), but reports failures).
Definition Value.h:475
bool IsNumber() const
Whether or not the value is a number.
Definition Value.h:290
Result< bool > ToBoolean() const
Convert to a boolean using JavaScript's rules (this never runs script).
Definition Value.h:339
bool IsObject() const
Whether or not the value is an object.
Definition Value.h:307
bool IsPromise() const
Whether or not the value is a Promise.
Definition Value.h:332
bool IsString() const
Whether or not the value is a string.
Definition Value.h:300
bool Then(F &&on_settled) const
Wait for this promise to settle and convert its value to a C++ type.
Definition Value.h:743
bool IsEmpty() const
Whether or not this Value holds nothing (see "Handle States" above).
Definition Value.h:249
bool IsAlive() const
Whether or not this Value's page is still alive (the same test as operator bool).
Definition Value.h:257
~Value()
Destructor (releases this handle).
Definition Value.h:239
Result< std::string > ToJSON(unsigned indent=0) const
Convert to JSON text like JSON.stringify() does.
Definition Value.h:413
Result< R > Invoke(A &&... args) const
Call this value as a function with typed arguments and result.
Result< Value > operator()(A &&... args) const
Call this value as a function: on_save(path) is the same as on_save.Invoke(path).
Definition Value.h:675
Result< Value > GetProperty(const char *name) const
Get a property of this object (own or inherited).
Definition Value.h:440
Result< T > To() const
Convert to a C++ type.
Value(ULJSValue handle)
Definition Value.h:834
bool IsNullish() const
Whether or not the value is null or undefined.
Definition Value.h:280
Value()
Create an empty Value.
Definition Value.h:215
Result< void > SetProperty(const char *name, const Value &value, PropertyAttributes attributes=PropertyAttributes::None) const
Set a property of this object.
Definition Value.h:507
bool IsBigInt() const
Whether or not the value is a BigInt (eg, 10n).
Definition Value.h:295
bool IsNull() const
Whether or not the value is null.
Definition Value.h:275
bool IsBoolean() const
Whether or not the value is a boolean.
Definition Value.h:285
Result< Value > Call(const Value &this_value, std::span< const Value > args) const
Call this value as a function with the arguments in a range (eg, a std::vector<js::Value>).
Definition Value.h:568
std::optional< T > Maybe() const
Convert to a C++ type like To() but without the failure reason.
Type type() const
Get the type of the value.
Definition Value.h:265
bool IsUndefined() const
Whether or not the value is undefined.
Definition Value.h:270
bool Then(F &&on_settled) const
Wait for this promise to settle without a coroutine.
Definition Value.h:716
Result< Value > Call(const Value &this_value, const Value *args, size_t argc) const
Call this value as a function.
Definition Value.h:533
bool IsFunction() const
Whether or not the value is a function.
Definition Value.h:325
bool IsArray() const
Whether or not the value is an Array.
Definition Value.h:312
ULJSValue raw() const
Get the C API handle without transferring ownership.
Definition Value.h:820
Definition StringSTL.h:166
Type-checked JavaScript bridge between C++ and web pages.
Definition JSInterop.h:141
constexpr UndefinedType undefined
The JavaScript undefined value.
Definition Value.h:58
T Or(const Value &value, T fallback)
Convert a value to a C++ type with a fallback (the free-function form of Value::Or()).
Definition Value.h:1220
Type
The type of a JavaScript value.
Definition Value.h:95
@ Symbol
Definition Value.h:102
@ String
Definition Value.h:101
@ Boolean
Definition Value.h:99
@ Object
Definition Value.h:104
@ Invalid
An empty Value, or one whose page is gone.
Definition Value.h:96
@ BigInt
Definition Value.h:103
@ Number
Definition Value.h:100
@ Null
Definition Value.h:98
@ Undefined
Definition Value.h:97
constexpr NullType null
The JavaScript null value.
Definition Value.h:48
Value ExceptionValue(const Error &error)
Get the value a JavaScript exception threw, to keep it or pass it back to the page.
Definition Value.h:1326
constexpr AttachFlags operator|(AttachFlags a, AttachFlags b)
Combine attach flags.
Definition API.h:56
PropertyAttributes
Attribute flags for a property created by Value::SetProperty().
Definition Value.h:72
@ DontDelete
Script can't delete it.
Definition Value.h:76
@ ReadOnly
Script can't change its value.
Definition Value.h:74
@ DontEnum
Hidden from for...in and Object.keys.
Definition Value.h:75
@ None
No flags (a normal property).
Definition Value.h:73
bool operator==(const Value &value, NullType)
Compare against the JavaScript null literal: if (v == js::null).
Definition Value.h:1094
Expected< T, Error > Result
The result of a JavaScript operation that can fail: a T or a js::Error.
Definition Error.h:520
Root namespace for every public Ultralight type, function, and enumeration.
@ None
Definition Anchor.h:36
Tag type for the JavaScript null value (see js::null).
Definition Value.h:40
Type conversions between C++ and JavaScript across the bridge.
Definition TypeTraits.h:240
Tag type for the JavaScript undefined value (see js::undefined).
Definition Value.h:53