/* * Copyright (C) 2016 Charybdis Development Team * Copyright (C) 2016 Jason Volk * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice is present in all copies. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #pragma once #define HAVE_IRCD_JS_VALUE_H namespace ircd { namespace js { // Use Value to carry a non-gc host pointer value template T *pointer_value(const JS::Value &); JS::Value pointer_value(const void *const &); JS::Value pointer_value(void *const &); namespace basic { template struct value :root { IRCD_OVERLOAD(pointer) explicit operator std::string() const; explicit operator double() const; explicit operator uint64_t() const; explicit operator int64_t() const; explicit operator uint32_t() const; explicit operator int32_t() const; explicit operator uint16_t() const; explicit operator bool() const; template value(const root &r); template value(const JS::MutableHandle &h); template value(const JS::Handle &h); value(pointer_t, void *const &); value(const std::string &); value(const char *const &); value(const nullptr_t &); value(const double &); value(const float &); value(const uint64_t &); value(const int32_t &); value(const bool &); value(const jsid &); value(JSObject &); value(JSObject *const &); value(JSString *const &); value(JSFunction *const &); value(JS::Symbol *const &); value(const JS::Value &); value(); value(const value &); }; } // namespace basic using value = basic::value; using heap_value = basic::value; template JSType type(const value &); template bool undefined(const value &val); template bool is_array(const value &val); // // Implementation // namespace basic { template value::value() :value::root::type{JS::UndefinedValue()} { } template value::value(const value &other) :value::root::type{other.get()} { } template value::value(const JS::Value &val) :value::root::type{val} { } template value::value(JS::Symbol *const &val) :value::root::type{JS::SymbolValue(val)} { } template value::value(JSObject *const &val) :value::root::type { val? JS::ObjectValue(*val) : throw internal_error("NULL JSObject") } { } template value::value(JSObject &val) :value::root::type{JS::ObjectValue(val)} { } template value::value(JSString *const &val) :value::root::type{JS::StringValue(val)} { } template value::value(JSFunction *const &val) :value::root::type{} { auto *const obj(JS_GetFunctionObject(val)); if(unlikely(!obj)) throw type_error("Function cannot convert to Object"); this->set(JS::ObjectValue(*obj)); } template value::value(const jsid &val) :value::root::type{} { if(!JS_IdToValue(*cx, val, &(*this))) throw type_error("Failed to construct value from Id"); } template value::value(const bool &b) :value::root::type{JS::BooleanValue(b)} { } template value::value(const int32_t &val) :value::root::type{JS::Int32Value(val)} { } template value::value(const uint64_t &val) :value::root::type{JS::DoubleValue(val)} { } template value::value(const float &val) :value::root::type{JS::Float32Value(val)} { } template value::value(const double &val) :value::root::type{JS::DoubleValue(val)} { } template value::value(const nullptr_t &) :value::root::type{JS::NullValue()} { } template value::value(const std::string &s) :value::root::type{[&s] { auto buf(native_external_copy(s)); const auto ret(JS_NewExternalString(*cx, buf.get(), s.size(), &native_external_delete)); buf.release(); return JS::StringValue(ret); }()} { } template value::value(const char *const &s) :value::root::type{!s? JS::NullValue() : [&s] { const auto len(strlen(s)); auto buf(native_external_copy(s, len)); const auto ret(JS_NewExternalString(*cx, buf.get(), len, &native_external_delete)); buf.release(); return JS::StringValue(ret); }()} { } template value::value(pointer_t, void *const &ptr) :value::root::type{pointer_value(ptr)} { } template template value::value(const JS::Handle &h) :value(h.get()) { } template template value::value(const JS::MutableHandle &h) :value(h.get()) { } template template value::value(const root &r): value(r.get()) { } template value::operator bool() const { return JS::ToBoolean(*this); } template value::operator uint16_t() const { uint16_t ret; if(!JS::ToUint16(*cx, *this, &ret)) throw type_error("Failed cast to uint16_t"); return ret; } template value::operator int32_t() const { int32_t ret; if(!JS::ToInt32(*cx, *this, &ret)) throw type_error("Failed cast to int32_t"); return ret; } template value::operator uint32_t() const { uint32_t ret; if(!JS::ToUint32(*cx, *this, &ret)) throw type_error("Failed cast to uint32_t"); return ret; } template value::operator int64_t() const { int64_t ret; if(!JS::ToInt64(*cx, *this, &ret)) throw type_error("Failed cast to int64_t"); return ret; } template value::operator uint64_t() const { uint64_t ret; if(!JS::ToUint64(*cx, *this, &ret)) throw type_error("Failed cast to uint64_t"); return ret; } template value::operator double() const { double ret; if(!JS::ToNumber(*cx, *this, &ret)) throw type_error("Failed cast to double"); return ret; } template value::operator std::string() const { const auto s(JS::ToString(*cx, *this)); return s? native(s) : throw type_error("Failed to cast to string"); } } // namespace basic template bool is_array(const value &val) { bool ret; if(!JS_IsArrayObject(*cx, val, &ret)) throw internal_error("Failed to query if value is array"); return ret; } template bool undefined(const value &val) { return type(val) == JSTYPE_VOID; } template JSType type(const value &val) { return JS_TypeOfValue(*cx, val); } inline JS::Value pointer_value(const void *const &ptr) { return pointer_value(const_cast(ptr)); } inline JS::Value pointer_value(void *const &ptr) { JS::Value ret; ret.setPrivate(ptr); return ret; } template T * pointer_value(const JS::Value &val) { const auto ret(val.toPrivate()); return reinterpret_cast(ret); } } // namespace js } // namespace ircd