Skip to content

Commit

Permalink
implement conversions for up to uint64_t
Browse files Browse the repository at this point in the history
  • Loading branch information
cubicap committed Jul 7, 2024
1 parent 15bf370 commit 141466b
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 48 deletions.
91 changes: 52 additions & 39 deletions src/jac/machine/traits.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <type_traits>
#include <vector>

#include "context.h"
Expand Down Expand Up @@ -33,59 +34,71 @@ struct ConvTraits<bool> {
};

namespace detail {
template<typename T>
struct IntConvBase {
static T from(ContextRef ctx, ValueWeak val) {
int32_t res;
int ex = JS_ToInt32(ctx, &res, val.getVal());
if (ex < 0) {
throw Exception::create(Exception::Type::TypeError, "Failed to convert to int");
}
return res;
}

static Value to(ContextRef ctx, T val) {
return Value(ctx, JS_NewInt32(ctx, val));
}
};

template<typename T>
struct FloatConvBase {
static T from(ContextRef ctx, ValueWeak val) {
double res;
int ex = JS_ToFloat64(ctx, &res, val.getVal());
if (ex < 0) {
throw Exception::create(Exception::Type::TypeError, "Failed to convert to double");
}
return res;
}
constexpr bool is_leq_i32 = (std::is_signed_v<T> && sizeof(T) <= sizeof(int32_t))
|| (std::is_unsigned_v<T> && sizeof(T) < sizeof(int32_t));

static Value to(ContextRef ctx, T val) {
return Value(ctx, JS_NewFloat64(ctx, val));
}
};
} // namespace detail


template<typename T>
struct ConvTraits<T, std::enable_if_t<
std::is_integral_v<T>
&& std::is_signed_v<T>
&& sizeof(T) <= sizeof(int32_t)
, T>> : public detail::IntConvBase<T> {};
std::is_integral_v<T>
&& detail::is_leq_i32<T>
, T>> {
static T from(ContextRef ctx, ValueWeak val) {
int32_t res;
int ex = JS_ToInt32(ctx, &res, val.getVal());
if (ex < 0) {
throw Exception::create(Exception::Type::TypeError, "Failed to convert to int");
}
return res;
}

static Value to(ContextRef ctx, T val) {
return Value(ctx, JS_NewInt32(ctx, val));
}
};

template<typename T>
struct ConvTraits<T, std::enable_if_t<
std::is_integral_v<T>
&& std::is_unsigned_v<T>
&& sizeof(T) < sizeof(int32_t)
, T>> : public detail::IntConvBase<T> {};
std::is_floating_point_v<T>
&& sizeof(T) <= sizeof(double)
, T>> {
static T from(ContextRef ctx, ValueWeak val) {
double res;
int ex = JS_ToFloat64(ctx, &res, val.getVal());
if (ex < 0) {
throw Exception::create(Exception::Type::TypeError, "Failed to convert to double");
}
return res;
}

static Value to(ContextRef ctx, T val) {
return Value(ctx, JS_NewFloat64(ctx, val));
}
};

template<typename T>
struct ConvTraits<T, std::enable_if_t<
std::is_floating_point_v<T>
&& sizeof(T) <= sizeof(double)
, T>> : public detail::FloatConvBase<T> {};
std::is_integral_v<T>
&& sizeof(T) <= sizeof(int64_t)
&& !detail::is_leq_i32<T>
, T>> {
static T from(ContextRef ctx, ValueWeak val) {
int64_t res = 0;
int ex = JS_ToInt64(ctx, &res, val.getVal());
if (ex < 0) {
throw Exception::create(Exception::Type::TypeError, "Failed to convert to int");
}
return res;
}

static Value to(ContextRef ctx, T val) {
return Value(ctx, JS_NewInt64(ctx, val));
}
};

template<>
struct ConvTraits<const char*> {
Expand Down
16 changes: 7 additions & 9 deletions tests/values.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>

#include <cstdint>
#include <cstring>
#include <limits>
#include <memory>
#include <string>
#include <string_view>
Expand Down Expand Up @@ -32,7 +34,11 @@ TEST_CASE("To JS value", "[base]") {
val{"uint8_t", [](jac::ContextRef ctx) { return jac::Value::from(ctx, uint8_t(42)); }, "number", "42"},
val{"int16_t", [](jac::ContextRef ctx) { return jac::Value::from(ctx, int16_t(-42)); }, "number", "-42"},
val{"uint16_t", [](jac::ContextRef ctx) { return jac::Value::from(ctx, uint16_t(42)); }, "number", "42"},
val{"int32_t", [](jac::ContextRef ctx) { return jac::Value::from(ctx, int32_t(-42)); }, "number", "-42"},
val{"int32_t", [](jac::ContextRef ctx) { return jac::Value::from(ctx, int32_t(std::numeric_limits<int32_t>::max())); }, "number", std::to_string(std::numeric_limits<int32_t>::max())},
val{"int32_t", [](jac::ContextRef ctx) { return jac::Value::from(ctx, int32_t(std::numeric_limits<int32_t>::min())); }, "number", std::to_string(std::numeric_limits<int32_t>::min())},
val{"uint32_t", [](jac::ContextRef ctx) { return jac::Value::from(ctx, std::numeric_limits<uint32_t>::max()); }, "number", std::to_string(std::numeric_limits<uint32_t>::max())},
val{"int64_t", [](jac::ContextRef ctx) { return jac::Value::from(ctx, int64_t(-0xf00000000)); }, "number", std::to_string(-0xf00000000)},
val{"uint64_t", [](jac::ContextRef ctx) { return jac::Value::from(ctx, uint64_t(0xf00000000)); }, "number", std::to_string(0xf00000000)},
val{"const c string", [](jac::ContextRef ctx) { return jac::Value::from(ctx, "Hello World"); }, "string", "Hello World"},
val{"non const c string", [](jac::ContextRef ctx) {
std::string_view str = "Hello World";
Expand Down Expand Up @@ -82,14 +88,6 @@ TEST_CASE("To JS value", "[base]") {
REQUIRE(reports[0] == "number");
REQUIRE(reports[1].substr(0, 4) == "42.7");
}

SECTION("Invalid types") {
static_assert(std::is_void_v<decltype(jac::ConvTraits<uint32_t>::from(std::declval<jac::ContextRef>(), std::declval<jac::ValueWeak>()))>, "Invalid type");
static_assert(std::is_void_v<decltype(jac::ConvTraits<uint32_t>::to(std::declval<jac::ContextRef>(), std::declval<uint32_t>()))>, "Invalid type");

static_assert(std::is_void_v<decltype(jac::ConvTraits<int64_t>::from(std::declval<jac::ContextRef>(), std::declval<jac::ValueWeak>()))>, "Invalid type");
static_assert(std::is_void_v<decltype(jac::ConvTraits<int64_t>::to(std::declval<jac::ContextRef>(), std::declval<int64_t>()))>, "Invalid type");
}
}


Expand Down

0 comments on commit 141466b

Please sign in to comment.