Skip to content

Minor fixes #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 58 additions & 39 deletions bootstrap/include/js_bootstrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,83 +19,84 @@ template<typename> struct _js_ReadonlyArray;
template<typename> struct _js_Promise;
struct _js_console;

template<typename T> using Array = jst::js_ref<_js_Array<T>>;
template<typename T> using ReadonlyArray = jst::js_ref<_js_ReadonlyArray<T>>;
template<typename T> using Promise = jst::js_ref<_js_Promise<T>>;
using console = jst::js_ref<_js_console>;
template<typename T> using Array = ::tc::jst::js_ref<_js_Array<T>>;
template<typename T> using ReadonlyArray = ::tc::jst::js_ref<_js_ReadonlyArray<T>>;
template<typename T> using Promise = ::tc::jst::js_ref<_js_Promise<T>>;
using console = ::tc::jst::js_ref<_js_console>;

template<typename T>
struct _js_Array : virtual jst::IObject {
static_assert(jst::IsJsInteropable<T>::value);
struct _js_Array : virtual ::tc::jst::IObject {
static_assert(::tc::jst::IsJsInteropable<T>::value);

struct _tcjs_definitions {
using value_type = T;
};

auto length() noexcept { return tc::explicit_cast<int>(_getProperty<double>("length")); }
auto length() noexcept { return ::tc::explicit_cast<int>(_getProperty<double>("length")); }

auto push(T const& item) noexcept { return _call<void>("push", item); }

auto operator[](int i) && noexcept { return _getProperty<T>(tc::as_dec(i)); }
auto operator[](int i) && noexcept { return _getProperty<T>(::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<typename Fn>
auto operator()(Fn fn) noexcept {
if (_call<bool>("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<bool>("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<T> _tcjs_construct() noexcept {
return Array<T>(emscripten::val::array());
return Array<T>(::emscripten::val::array());
}

template<typename Rng, typename = std::enable_if_t<tc::is_explicit_castable<T, tc::range_value_t<Rng>&&>::value>>
template<typename Rng, typename = ::std::enable_if_t<::tc::is_explicit_castable<T, ::tc::range_reference_t<Rng>>::value>>
static Array<T> _tcjs_construct(Rng&& rng) noexcept {
Array<T> result(emscripten::val::array());
tc::for_each(rng, [&](auto&& value) noexcept {
result->push(tc::explicit_cast<T>(std::forward<decltype(value)>(value)));
Array<T> result(::emscripten::val::array());
::tc::for_each(::std::forward<Rng>(rng), [&](auto&& value) noexcept {
result->push(::tc::explicit_cast<T>(::std::forward<decltype(value)>(value)));
});
return result;
}

};

template<typename T>
struct _js_ReadonlyArray : virtual jst::IObject {
static_assert(jst::IsJsInteropable<T>::value);
struct _js_ReadonlyArray : virtual ::tc::jst::IObject {
static_assert(::tc::jst::IsJsInteropable<T>::value);

struct _tcjs_definitions {
using value_type = T;
};

auto length() noexcept { return tc::explicit_cast<int>(_getProperty<double>("length")); }
auto length() noexcept { return ::tc::explicit_cast<int>(_getProperty<double>("length")); }

auto operator[](int i) noexcept { return _getProperty<T>(tc::as_dec(i)); }
auto operator[](int i) noexcept { return _getProperty<T>(::tc::as_dec(i)); }

// Generator range. This adds operator() to array interface (which did not exist before), but it's ok.
template<typename Fn>
auto operator()(Fn fn) noexcept {
if (_call<bool>("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<bool>("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<T> _tcjs_construct() noexcept {
return ReadonlyArray<T>(emscripten::val::array());
return ReadonlyArray<T>(::emscripten::val::array());
}

template<typename Rng, typename = std::enable_if_t<tc::is_explicit_castable<T, tc::range_value_t<Rng>&&>::value>>
template<typename Rng, typename = ::std::enable_if_t<::tc::is_explicit_castable<T, ::tc::range_reference_t<Rng>>::value>>
static ReadonlyArray<T> _tcjs_construct(Rng&& rng) noexcept {
return ReadonlyArray<T>(
Array<T>(jst::create_js_object, std::forward<Rng>(rng)).getEmval()
Array<T>(::tc::jst::create_js_object, ::std::forward<Rng>(rng)).getEmval()
);
}
};
Expand All @@ -105,36 +106,54 @@ template<typename T> struct RemovePromise<Promise<T>> { using type = T; };
template<typename T> using RemovePromise_t = typename RemovePromise<T>::type;

template<typename T>
struct _js_Promise : virtual jst::IObject {
static_assert(jst::IsJsInteropable<T>::value);
struct _js_Promise : virtual ::tc::jst::IObject {
static_assert(::tc::jst::IsJsInteropable<T>::value);

template<typename R>
auto then(jst::js_function<R(T)> onfulfilled, jst::js_function<R(jst::js_unknown)> onrejected) noexcept {
auto then(::tc::jst::js_function<R(T)> onfulfilled, ::tc::jst::js_function<R(::tc::jst::js_unknown)> onrejected) noexcept {
return _call<Promise<RemovePromise_t<R>>>("then", onfulfilled, onrejected);
}

template<typename R1>
auto then(jst::js_function<R1(T)> onfulfilled) noexcept {
auto then(::tc::jst::js_function<R1(T)> onfulfilled) noexcept {
return _call<Promise<RemovePromise_t<R1>>>("then", onfulfilled);
}

template<typename R1, typename R2>
auto then(jst::js_function<R1(T)> onfulfilled, jst::js_function<R2(jst::js_unknown)> onrejected) noexcept {
return _call<Promise<jst::js_union<RemovePromise_t<R1>, RemovePromise_t<R2>>>>("then", onfulfilled, onrejected);
auto then(::tc::jst::js_function<R1(T)> onfulfilled, ::tc::jst::js_function<R2(jst::js_unknown)> onrejected) noexcept {
return _call<Promise<::tc::jst::js_union<RemovePromise_t<R1>, RemovePromise_t<R2>>>>("then", onfulfilled, onrejected);
}
};

template<>
struct _js_Promise<void> : virtual _js_Promise<jst::js_undefined> {
struct _js_Promise<void> : 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<typename... Args>
static void log(Args&&... args) noexcept {
static_assert((jst::IsJsInteropable<tc::remove_cvref_t<Args>>::value && ...));
emscripten::val::global("console")["log"](std::forward<Args>(args)...);
static_assert((::tc::jst::IsJsInteropable<::tc::remove_cvref_t<Args>>::value && ...));
::emscripten::val::global("console")["log"](::std::forward<Args>(args)...);
}

template<typename... Args>
static void error(Args&&... args) noexcept {
static_assert((::tc::jst::IsJsInteropable<::tc::remove_cvref_t<Args>>::value && ...));
::emscripten::val::global("console")["error"](::std::forward<Args>(args)...);
}

template<typename... Args>
static void warn(Args&&... args) noexcept {
static_assert((::tc::jst::IsJsInteropable<::tc::remove_cvref_t<Args>>::value && ...));
::emscripten::val::global("console")["warn"](::std::forward<Args>(args)...);
}

template<typename... Args>
static void debug(Args&&... args) noexcept {
static_assert((::tc::jst::IsJsInteropable<::tc::remove_cvref_t<Args>>::value && ...));
::emscripten::val::global("console")["debug"](::std::forward<Args>(args)...);
}
};
};
Expand Down
16 changes: 9 additions & 7 deletions bootstrap/include/js_callback.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
#pragma once
#include <emscripten/val.h>
#include <emscripten/wire.h>
#include <cstdint>
#include <memory>
#include <utility>
#include <type_traits>

#include "casts.h"

#include "range_defines.h"
#include "type_traits.h"
#include "noncopyable.h"
#include "tag_type.h"
#include "tc_move.h"
#include "type_list.h"
#include <boost/callable_traits.hpp>

#include <emscripten/val.h>
#include <emscripten/wire.h>
#include <cstdint>
#include <memory>
#include <utility>
#include <type_traits>

#include "js_ref.h"

namespace tc::jst {
Expand Down
8 changes: 4 additions & 4 deletions bootstrap/src/js_callback.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <emscripten/bind.h>
#include "js_callback.h"
#include <emscripten/bind.h>

namespace tc::jst {
namespace callback_detail {
Expand All @@ -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. ...
Expand All @@ -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().
Expand Down
13 changes: 13 additions & 0 deletions examples/BootstrapDemo/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,19 @@ int main() {
_ASSERT(!tc::empty(arr));
}

{
constexpr char str[] = "Test";
Array<js_string> const arr(tc::jst::create_js_object, tc::single(str));
_ASSERTEQUAL(arr->length(), 1);
_ASSERTEQUAL(arr[0].length(), 4);
}
{
constexpr char str[] = "Test";
ReadonlyArray<js_string> 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<Array<double>>(tc::jst::create_js_object, std::initializer_list<double>{1, 2, 3});
static_assert(!tc::is_explicit_castable<Array<double>, double>::value);
static_assert(std::is_same_v<tc::range_value_t<Array<double>>, double>);
Expand Down
Empty file modified stage1/build-make.sh
100644 → 100755
Empty file.