diff --git a/bootstrap/include/js_bootstrap.h b/bootstrap/include/js_bootstrap.h index 3c98f6f..1f42689 100644 --- a/bootstrap/include/js_bootstrap.h +++ b/bootstrap/include/js_bootstrap.h @@ -19,83 +19,84 @@ template struct _js_ReadonlyArray; template struct _js_Promise; struct _js_console; -template using Array = jst::js_ref<_js_Array>; -template using ReadonlyArray = jst::js_ref<_js_ReadonlyArray>; -template using Promise = jst::js_ref<_js_Promise>; -using console = jst::js_ref<_js_console>; +template using Array = ::tc::jst::js_ref<_js_Array>; +template using ReadonlyArray = ::tc::jst::js_ref<_js_ReadonlyArray>; +template using Promise = ::tc::jst::js_ref<_js_Promise>; +using console = ::tc::jst::js_ref<_js_console>; template -struct _js_Array : virtual jst::IObject { - static_assert(jst::IsJsInteropable::value); +struct _js_Array : virtual ::tc::jst::IObject { + static_assert(::tc::jst::IsJsInteropable::value); struct _tcjs_definitions { using value_type = T; }; - auto length() noexcept { return tc::explicit_cast(_getProperty("length")); } + auto length() noexcept { return ::tc::explicit_cast(_getProperty("length")); } auto push(T const& item) noexcept { return _call("push", item); } - auto operator[](int i) && noexcept { return _getProperty(tc::as_dec(i)); } + auto operator[](int i) && noexcept { return _getProperty(::tc::as_dec(i)); } - void _setIndex(int i, T value) noexcept { _setProperty(tc::as_dec(i), tc_move(value)); } + void _setIndex(int i, T value) noexcept { _setProperty(::tc::as_dec(i), tc_move(value)); } // Generator range. This adds operator() to array interface (which did not exist before), but it's ok. template auto operator()(Fn fn) noexcept { - if (_call("some", jst::js_lambda_wrap([&](T value, jst::js_unknown, jst::js_unknown) noexcept { - return tc::break_ == tc::continue_if_not_break(fn, tc_move(value)); + if (_call("some", ::tc::jst::js_lambda_wrap([&](T value, ::tc::jst::js_unknown, ::tc::jst::js_unknown) noexcept { + return ::tc::break_ == tc::continue_if_not_break(fn, tc_move(value)); }))) - return tc::break_; + return ::tc::break_; else - return tc::continue_; + return ::tc::continue_; } static Array _tcjs_construct() noexcept { - return Array(emscripten::val::array()); + return Array(::emscripten::val::array()); } - template&&>::value>> + template>::value>> static Array _tcjs_construct(Rng&& rng) noexcept { - Array result(emscripten::val::array()); - tc::for_each(rng, [&](auto&& value) noexcept { - result->push(tc::explicit_cast(std::forward(value))); + Array result(::emscripten::val::array()); + ::tc::for_each(::std::forward(rng), [&](auto&& value) noexcept { + result->push(::tc::explicit_cast(::std::forward(value))); }); return result; } + }; template -struct _js_ReadonlyArray : virtual jst::IObject { - static_assert(jst::IsJsInteropable::value); +struct _js_ReadonlyArray : virtual ::tc::jst::IObject { + static_assert(::tc::jst::IsJsInteropable::value); struct _tcjs_definitions { using value_type = T; }; - auto length() noexcept { return tc::explicit_cast(_getProperty("length")); } + auto length() noexcept { return ::tc::explicit_cast(_getProperty("length")); } - auto operator[](int i) noexcept { return _getProperty(tc::as_dec(i)); } + auto operator[](int i) noexcept { return _getProperty(::tc::as_dec(i)); } // Generator range. This adds operator() to array interface (which did not exist before), but it's ok. template auto operator()(Fn fn) noexcept { - if (_call("some", jst::js_lambda_wrap([&](T value, jst::js_unknown, jst::js_unknown) noexcept { - return tc::break_ == tc::continue_if_not_break(fn, tc_move(value)); + if (_call("some", ::tc::jst::js_lambda_wrap([&](T value, ::tc::jst::js_unknown, ::tc::jst::js_unknown) noexcept { + return ::tc::break_ == ::tc::continue_if_not_break(fn, tc_move(value)); }))) - return tc::break_; + return ::tc::break_; else - return tc::continue_; + return ::tc::continue_; } static ReadonlyArray _tcjs_construct() noexcept { - return ReadonlyArray(emscripten::val::array()); + return ReadonlyArray(::emscripten::val::array()); } - template&&>::value>> + template>::value>> static ReadonlyArray _tcjs_construct(Rng&& rng) noexcept { return ReadonlyArray( - Array(jst::create_js_object, std::forward(rng)).getEmval() + Array(::tc::jst::create_js_object, ::std::forward(rng)).getEmval() ); } }; @@ -105,36 +106,54 @@ template struct RemovePromise> { using type = T; }; template using RemovePromise_t = typename RemovePromise::type; template -struct _js_Promise : virtual jst::IObject { - static_assert(jst::IsJsInteropable::value); +struct _js_Promise : virtual ::tc::jst::IObject { + static_assert(::tc::jst::IsJsInteropable::value); template - auto then(jst::js_function onfulfilled, jst::js_function onrejected) noexcept { + auto then(::tc::jst::js_function onfulfilled, ::tc::jst::js_function onrejected) noexcept { return _call>>("then", onfulfilled, onrejected); } template - auto then(jst::js_function onfulfilled) noexcept { + auto then(::tc::jst::js_function onfulfilled) noexcept { return _call>>("then", onfulfilled); } template - auto then(jst::js_function onfulfilled, jst::js_function onrejected) noexcept { - return _call, RemovePromise_t>>>("then", onfulfilled, onrejected); + auto then(::tc::jst::js_function onfulfilled, ::tc::jst::js_function onrejected) noexcept { + return _call, RemovePromise_t>>>("then", onfulfilled, onrejected); } }; template<> -struct _js_Promise : virtual _js_Promise { +struct _js_Promise : virtual _js_Promise<::tc::jst::js_undefined> { // JavaScript passes 'undefined' to what TypeScript calls 'void' promise. }; -struct _js_console : virtual jst::IObject { +struct _js_console : virtual ::tc::jst::IObject { struct _tcjs_definitions { template static void log(Args&&... args) noexcept { - static_assert((jst::IsJsInteropable>::value && ...)); - emscripten::val::global("console")["log"](std::forward(args)...); + static_assert((::tc::jst::IsJsInteropable<::tc::remove_cvref_t>::value && ...)); + ::emscripten::val::global("console")["log"](::std::forward(args)...); + } + + template + static void error(Args&&... args) noexcept { + static_assert((::tc::jst::IsJsInteropable<::tc::remove_cvref_t>::value && ...)); + ::emscripten::val::global("console")["error"](::std::forward(args)...); + } + + template + static void warn(Args&&... args) noexcept { + static_assert((::tc::jst::IsJsInteropable<::tc::remove_cvref_t>::value && ...)); + ::emscripten::val::global("console")["warn"](::std::forward(args)...); + } + + template + static void debug(Args&&... args) noexcept { + static_assert((::tc::jst::IsJsInteropable<::tc::remove_cvref_t>::value && ...)); + ::emscripten::val::global("console")["debug"](::std::forward(args)...); } }; }; diff --git a/bootstrap/include/js_callback.h b/bootstrap/include/js_callback.h index 49936d4..b51bddb 100644 --- a/bootstrap/include/js_callback.h +++ b/bootstrap/include/js_callback.h @@ -1,12 +1,6 @@ #pragma once -#include -#include -#include -#include -#include -#include - #include "casts.h" + #include "range_defines.h" #include "type_traits.h" #include "noncopyable.h" @@ -14,6 +8,14 @@ #include "tc_move.h" #include "type_list.h" #include + +#include +#include +#include +#include +#include +#include + #include "js_ref.h" namespace tc::jst { diff --git a/bootstrap/src/js_callback.cpp b/bootstrap/src/js_callback.cpp index e66d723..cadd0bf 100644 --- a/bootstrap/src/js_callback.cpp +++ b/bootstrap/src/js_callback.cpp @@ -1,5 +1,5 @@ -#include #include "js_callback.h" +#include namespace tc::jst { namespace callback_detail { @@ -9,8 +9,8 @@ void EnsureJsCallbackCppIsLinked() {} * [basic.compound] 6.7.2 * (3) The type of a pointer to cv void or a pointer to an object type is called an object pointer type. ... * ... The type of a pointer that can designate a function is called a function pointer type. A pointer to - * objects of type T is referred to as a “pointer to T”. ... Except for pointers to static members, text - * referring to “pointers” does not apply to pointers to members. + * objects of type T is referred to as a "pointer to T". ... Except for pointers to static members, text + * referring to "pointers" does not apply to pointers to members. * * [expr.reinterpret.cast] 8.5.1.10 * (1) ... Conversions that can be performed explicitly using reinterpret_cast are listed below. ... @@ -20,7 +20,7 @@ void EnsureJsCallbackCppIsLinked() {} * an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will * have its original value; mappings between pointers and integers are otherwise implementation-defined. [ Note: * Except as described in 6.6.4.4.3, the result of such a conversion will not be a safely-derived pointer value. - * — end note ] + * [end note] * * Hence, I conclude that converting between std::uintptr_t and non-member/static function pointers via reinterpret_cast * is safe as long as PointerNumber is "large enough", which is _hopefully_ checked by sizeof(). diff --git a/examples/BootstrapDemo/main.cpp b/examples/BootstrapDemo/main.cpp index 1683145..4dd61a4 100644 --- a/examples/BootstrapDemo/main.cpp +++ b/examples/BootstrapDemo/main.cpp @@ -62,6 +62,19 @@ int main() { _ASSERT(!tc::empty(arr)); } + { + constexpr char str[] = "Test"; + Array const arr(tc::jst::create_js_object, tc::single(str)); + _ASSERTEQUAL(arr->length(), 1); + _ASSERTEQUAL(arr[0].length(), 4); + } + { + constexpr char str[] = "Test"; + ReadonlyArray const arr(tc::jst::create_js_object, tc::single(str)); + _ASSERTEQUAL(arr->length(), 1); + _ASSERTEQUAL(arr[0].length(), 4); + } + auto const arr = tc::explicit_cast>(tc::jst::create_js_object, std::initializer_list{1, 2, 3}); static_assert(!tc::is_explicit_castable, double>::value); static_assert(std::is_same_v>, double>); diff --git a/stage1/build-make.sh b/stage1/build-make.sh old mode 100644 new mode 100755