/* * Tencent is pleased to support the open source community by making ScriptX available. * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include "foundation.h" #include SCRIPTX_BACKEND(Engine.h) namespace script { // values enum class ValueKind { kNull = 0, kObject, kString, kNumber, kBoolean, kFunction, kArray, kByteBuffer, // types that are not supported by ScriptX // like BigInt in js kUnsupported }; // value related APIs: // 1. Value.h value type class // 2. Reference.h Local specialized // 2.1 Local isXXX asXXX // 2.2 Local getKind // 4. backend_trait/Reference.h inline const char* valueKindName(ValueKind kind) noexcept { switch (kind) { case ValueKind::kNull: return "Null"; case ValueKind::kObject: return "Object"; case ValueKind::kString: return "String"; case ValueKind::kNumber: return "Number"; case ValueKind::kBoolean: return "Boolean"; case ValueKind::kFunction: return "Function"; case ValueKind::kArray: return "Array"; case ValueKind::kByteBuffer: return "ByteBuffer"; case ValueKind::kUnsupported: default: return "Unsupported"; } } inline std::ostream& operator<<(std::ostream& o, ValueKind k) { o << valueKindName(k); return o; } class Value {}; class Object : public Value { public: /** * @return new plain object, throw on failure. */ static Local newObject(); /** * @param type * @param args * @return new plain object instance of type, throw on failure * note: for JavaScript, type must be a function, for other Script language, refer to the backend. */ static Local newObject(const Local& type, const std::vector>& args); /** * @param type * @param args * @return new plain object instance of type, throw on failure * note: for JavaScript, type must be a function, for other Script language, refer to the backend. */ static Local newObject(const Local& type, const std::initializer_list>& args); /** * typesafe variadic template helper method * @tparam T MUST BE local reference, ie: Local. or supported raw C++ type to convert. * @return new plain object instance of type, throw on failure * note: for JavaScript, type must be a function, for other Script language, refer to the backend. */ template static Local newObject(const Local& type, T&&... args); private: static Local newObjectImpl(const Local& type, size_t size, const Local* args); friend class ScriptEngine; friend typename internal::ImplType::type; }; class String : public Value { public: /** * create string from utf8 encoding string. * * @param utf8 null-terminated c-style string * @return * * when utf8 is nullptr, a null local reference is returned; */ static Local newString(const char* utf8); /** * create string from utf8 encoding string. * * \code{.cc} * String::newString(u8"hello world! 😁"); * \endcode * * @param utf8 * @return */ static Local newString(std::string_view utf8); /** * create string from utf8 encoding string. * * \code{.cc} * String::newString(u8"hello world! 😁"); * \endcode * * @param utf8 * @return */ static Local newString(const std::string& utf8); // https://en.ccreference.com/w/cpp/preprocessor/replace#Predefined_macros #if defined(__cpp_char8_t) /** * create string from utf8 encoding string. * * This is the C++20 standard, and is preferred! * * @param utf8 null-terminated c-style string * @return * when utf8 is nullptr, a null local reference is returned; */ static Local newString(const char8_t* utf8); /** * Create string from utf8 encoding string. * * \code{.cc} * String::newString(u8"hello world! 😁"); * \endcode * * This is the C++20 standard, and is preferred! * */ static Local newString(std::u8string_view utf8); /** * Create string from utf8 encoding string. * * \code{.cc} * String::newString(u8"hello world! 😁"); * \endcode * * This is the C++20 standard, and is preferred! * */ static Local newString(const std::u8string& utf8); #endif }; class Number : public Value { public: static Local newNumber(int32_t value); static Local newNumber(int64_t value); static Local newNumber(float value); static Local newNumber(double value); }; class Boolean : public Value { public: static Local newBoolean(bool value); }; class Function : public Value { public: /** * create a new function, binding to native callback. * If you want any contextual info about the callback, * using lambda with capture and so on with std::function, * **be sure you understand std::function before really writing code**. * * @param callback function pointer of type FunctionCallback. * (a non-capture lambda can be implicitly cast to function pointer), * since callee owns the callback, you should always pass a rvalue-reference. * @return the created function, an exception maybe thrown. */ static Local newFunction(FunctionCallback callback); /** * helper method to create a function from binding. * @param nothrow when arguments type mismatch, throw the cast Exception or just return null. * note: the exception thrown by the callback still got propagated. */ // implementation is in Native.hpp template static Local newFunction(Func&& callback, bool nothrow = kDefaultNoThrow); private: #ifdef SCRIPTX_NO_EXCEPTION_ON_BIND_FUNCTION constexpr static bool kDefaultNoThrow = true; #else constexpr static bool kDefaultNoThrow = false; #endif }; class Array : public Value { public: static Local newArray(size_t size = 0); static Local newArray(const std::vector>& elements); static Local newArray(const std::initializer_list>& elements); /** * typesafe variadic template helper method * @tparam T MUST BE local reference, ie: Local. or supported raw C++ type to convert. * @return new plain object instance of type, throw on failure * note: for JavaScript, type must be a function, for other Script language, refer to the impl */ template static Local of(T&&... args); private: static Local newArrayImpl(size_t size, const Local* args); }; namespace internal { constexpr uint16_t makeType(uint8_t order, uint8_t size) { return static_cast(order << 8u) | size; // NOLINT } } // namespace internal class ByteBuffer : public Value { public: enum class Type : uint16_t { kUnspecified = internal::makeType(0, 1), kInt8 = internal::makeType(1, 1), kUint8 = internal::makeType(2, 1), kInt16 = internal::makeType(3, 2), kUint16 = internal::makeType(4, 2), kInt32 = internal::makeType(5, 4), kUint32 = internal::makeType(6, 4), kInt64 = internal::makeType(7, 8), kUint64 = internal::makeType(8, 8), KFloat32 = internal::makeType(9, 4), kFloat64 = internal::makeType(10, 8) }; /** * @return unit in byte */ static constexpr uint8_t getTypeSize(Type type) { return static_cast(static_cast(type) & 0xFFu); // NOLINT } /** * create a new ByteBuffer with given size. * on failure, an Exception is thrown. */ static Local newByteBuffer(size_t size); /** * create a new ByteBuffer and COPY content of nativeBuffer into it. * on failure(may due to engine not support), an Exception is thrown. * * ByteBuffer copy nativeBuffer to it's own storage. * note: caller still own the nativeBuffer pointer. * note: the returned Local has it own backing store, * thus ret.getRawBytes() != nativeBuffer * */ static Local newByteBuffer(void* nativeBuffer, size_t size); /** * create a new ByteBuffer SHARING the same buffer with native code. * on failure(may due to engine not support), an Exception is thrown. * * ByteBuffer using the same native memory as backing storage. * note: the returned Local use nativeBuffer as backing store, * thus ret.getRawBytes() == nativeBuffer.get() * */ static Local newByteBuffer(std::shared_ptr nativeBuffer, size_t size); }; class Unsupported : public Value {}; } // namespace script