changeset 528:65db2dc8a046

Js: complete removal of TypeTraits
author David Demelier <markand@malikania.fr>
date Thu, 02 Jun 2016 16:55:45 +0200
parents 8f8c32f102f1
children 49f9dadad4cd
files modules/js/js.hpp modules/js/test/main.cpp
diffstat 2 files changed, 527 insertions(+), 1778 deletions(-) [+]
line wrap: on
line diff
--- a/modules/js/js.hpp	Wed Jun 01 17:36:52 2016 +0200
+++ b/modules/js/js.hpp	Thu Jun 02 16:55:45 2016 +0200
@@ -23,449 +23,14 @@
  * \file js.hpp
  * \brief Bring JavaScript using Duktape.
  * \author David Demelier <markand@malikania.fr>
- *
- * This file provides usual Duktape function renamed and placed into `duk` namespace. It also replaces error
- * code with exceptions when possible.
- *
- * For convenience, this file also provides templated functions, overloads and much more.
- */
-
-/**
- * \page js JavaScript binding
- * \brief JavaScript binding using Duktape
- *
- * This page will show you how to setup this module to host JavaScript environment into your C++ application.
- *
- * ## Duktape
- *
- * Duktape is a C library designed for performance, small footprint and conformance. This wrapper is built top of it and
- * requires it at build and runtime.
- *
- * It is highly recommended that you read the [Duktape guide](http://duktape.org/guide.html) before continuing because
- * a lot of concepts are kept as-is.
- *
- * ## Installation
- *
- * You need the Duktape source amalgamation, it is provided with this module.
- *
- * When compiling, be sure to enable `-DDUK_OPT_CPP_EXCEPTIONS` and that Duktape source file has **cpp** extension.
- *
- * Just copy the **js.hpp** file and include it into your project. The header depends on **duktape.h** so be sure to
- * provide it when compiling.
- *
- *   - \subpage js-init
- *   - \subpage js-types
- *   - \subpage js-basics
- *   - \subpage js-more
- */
-
-/**
- * \page js-init Initialization
- * \brief Context initialization.
- *
- * To host JavaScript, you need a context. Usually one is sufficient but you can create as many as you want but they
- * won't share any resource.
- *
- * \code
- * #include "js.hpp"
- *
- * int main()
- * {
- *   duk::UniqueContext ctx;
- *
- *   return 0;
- * }
- * \endcode
- *
- * The duk::UniqueContext class is a RAII based wrapper around the native duk_context structure. It is automatically created and closed
- * in the destructor.
- *
- * Be sure to not keep any pointer to it.
- */
-
-/**
- * \page js-types Predefined types
- * \brief Default duk::TypeTraits specializations
- *
- * The following specializations are provided with libjs.
- *
- * ## Primitive types
- *
- * | Type           | Support                          | Remarks                               |
- * |----------------|----------------------------------|---------------------------------------|
- * | `int`          | get, is, optional, push, require |                                       |
- * | `bool`         | get, is, optional, push, require |                                       |
- * | `double`       | get, is, optional, push, require |                                       |
- * | `std::string`  | get, is, optional, push, require | can contain '\0' and binary data      |
- * | `const char *` | get, is, optional, push, require |                                       |
- * | `unsigned`     | get, is, optional, push, require |                                       |
- * | T *            | get, is, optional, push, require | raw pointer, never deleted by Duktape |
- *
- * ## Special JavaScript types
- *
- * The following types are used to create or inspect JavaScript types.
- *
- * | Type             | Support  | Remarks                                |
- * |------------------|----------|----------------------------------------|
- * | duk::Array       | is, push |                                        |
- * | duk::Function    | is, push | is just check if the value is callable |
- * | duk::FunctionMap | put      |                                        |
- * | duk::Global      | push     |                                        |
- * | duk::Null        | is, push |                                        |
- * | duk::Object      | is, push |                                        |
- * | duk::This        | push     |                                        |
- * | duk::Undefined   | is, push |                                        |
- *
- * ## Partial specializations
- *
- * These partial specializations will use complete specialization for T.
- *
- * | Type                               | Support   | Remarks                |
- * |------------------------------------|-----------|------------------------|
- * | std::unordered_map<std::string, T> | push, put | push or put properties |
- * | std::vector<T>                     | push, put | push array of values   |
- */
-
-/**
- * \page js-basics Basics
- * \brief Basics use case.
- *
- * The following topics are sample use case of the C++ front end. It does not use extended features that this module
- * provides.
- *
- *   - \subpage js-basics-t1
- *   - \subpage js-basics-t2
- *   - \subpage js-basics-t3
- */
-
-/**
- * \page js-basics-t1 Example 1: call JavaScript code from C++
- * \brief Evaluate JavaScript code from C++.
- *
- * Let use JavaScript to compute a simple expression.
- *
- * \code
- * #include "js.hpp"
- *
- * int main()
- * {
- *   duk::UniqueContext ctx;
- *
- *   duk::pevalString(ctx, "1 + 1");
- *   std::cout << duk::get<int>(ctx -1) << std::endl;
- *
- *   return 0;
- * }
- * \endcode
- */
-
-/**
- * \page js-basics-t2 Example 2: call C++ code from JavaScript
- * \brief Evaluate a function from JavaScript.
- *
- * In that example, we will add a C++ function to JavaScript and call it from the script. The function just compute the
- * two arguments that are passed through the function and return the result.
- *
- * We take the benefits of C++11 to map the function. The lambda can not have a capture because Duktape use raw C
- * function pointers and this module keep them.
- *
- * \code
- * #include "js.hpp"
- *
- * int main()
- * {
- *   duk::UniqueContext ctx;
- *
- *   // Push a function as global "add"
- *   duk::putGlobal(ctx, "add", duk::Function{[] (duk::Context *ctx) -> duk::Ret {
- *     int x = duk::require<int>(ctx, 0);
- *     int y = duk::require<int>(ctx, 1);
- *
- *     duk::push(ctx, x + y);
- *
- *     return 1;
- *   }, 2});
- *
- *   // Evaluate from JavaScript
- *   duk::pevalString(ctx, "add(1, 2)");
- *
- *   return 0;
- * }
- * \endcode
- *
- * Please note the **2** at end of lambda which indicates that the function takes 2 arguments. If number of arguments
- * is variadic, pass DUK_VARARGS there.
  */
 
-/**
- * \page js-basics-t3 Example 3: pushing and getting values
- * \brief Manage values between JavaScript and C++.
- *
- * As you have seen in the previous examples, we were pushing some values to the Duktape context.
- *
- * With the C Duktape frontend, you usually use duk_push_int, duk_push_string and all other related functions. The libjs
- * module provides an uniform and convenient way for sharing values with the same functions.
- *
- * See the description of duk::TypeTraits to see the supported types.
- *
- * ## Push
- *
- * The duk::push function is a template that accept most of the primitives types. It uses the specializations of the
- * duk::TypeTraits class (described later).
- *
- * Example of code
- *
- * \code
- * duk::push(ctx, 123); // an integer
- * duk::push(ctx, true); // a boolean
- * \endcode
- *
- * The push function add a new value to the stack for any specialization of TypeTraits provided by libjs.
- *
- * ## Get
- *
- * The duk::get function is similar to duk_get_ functions. It usually does not check the value and return a sane default
- * value.
- *
- * This template function does not take the template argument so it can't be deduced and must be specified explicitly.
- *
- * \code
- * duk::get<int>(ctx, 0) // get an int at index 0
- * duk::get<std::string>(ctx, 1) // get a std::string at index 1
- * \endcode
- *
- * ## Require
- *
- * The duk::require function is similar to duk_require functions. It requires the exact type at the given index. If the
- * value is invalid a JavaScript error is propagated.
- *
- * \code
- * duk::require<int>(ctx, 0) // require an int at index 0 or raise an error
- * \endcode
- *
- * ## Put
- *
- * This special function is similar to push except that it applies to the existing object at the top of the stack. It
- * is usually implemented for map and vector.
- *
- * \code
- * // Fill the object at the top of the stack with this map
- * std:unordered_map<std::string, int> map{
- *   { "value1", 1 },
- *   { "value2", 2 }
- * };
- *
- * duk::put(ctx, map);
- * \endcode
- *
- * ## Is
- *
- * This function duk::is checks if the value at the given index is of the given type and return true.
- *
- * Just like duk::get, this function need the explicit template parameter.
- *
- * \code
- * duk::push(ctx, 1);
- * duk::is<int>(ctx, -1); // true
- * \endcode
- *
- * ## Optional
- *
- * The duk::optional function has no equivalent in Duktape C API. It is a convenient way to get values with a default
- * replacement is not available.
- *
- * The common implementation uses duk::is and then duk::get.
- *
- * \code
- * duk::optional<int>(ctx, -1, 123); // 123 is -1 has no value or is not an int
- * \endcode
- */
-
-/**
- * \page js-more Extensions and advanced features.
- * \brief Evolved extensions provided by libjs.
- *
- * The following topics are provided by libjs and have no equivalent in Duktape C API.
- *
- * \subpage js-more-t1
- */
-
-/**
- * \page js-more-t1 Advanced 1: adding your own types to TypeTraits
- * \brief How to specialize duk::TypeTraits structure.
- *
- * This topic shows how you can specialize the duk::TypeTraits structure to add more types.
- *
- * Specializing the duk::TypeTraits is usually only needed when you want to convert a C++ object into JavaScript.
- *
- * In this example we will convert a C++ small structure containing two integers to JavaScript.
- *
- * \note It is not required to implement all functions from duk::TypeTraits. Just provide which one you need.
- *
- * ## The C++ structure
- *
- * The point does not have any methods, it just a description of two integers.
- *
- * \code
- * struct Point {
- *   int x;
- *   int y;
- * };
- * \endcode
- *
- * ## The push function
- *
- * Let's add a push function that will create a JavaScript object with **x** and **y** properties.
- *
- * \code
- * namespace duk {
- *
- * template <>
- * class TypeTraits<Point> {
- * public:
- *   static void push(Context *ctx, const Point &point)
- *   {
- *     // Create an object
- *     push(ctx, Object());
- *
- *     // Set x
- *     putProperty(ctx, -1, "x", point.x);
- *
- *     // Set y
- *     putProperty(ctx, -1, "y", point.y);
- *   }
- * };
- *
- * }
- * \endcode
- *
- * You can safely use different type of reference as second argument.
- *
- * That's it, you can now safely invoke `duk::push(ctx, Point{100, 200});`.
- *
- * ## The get function
- *
- * The get function usually return a new object. The recommandation is to provide sane defaults except if you have any
- * reason to not do so.
- *
- * \code
- * namespace duk {
- *
- * template <>
- * class TypeTraits<Point> {
- * public:
- *   static Point get(Context *ctx, Index index)
- *   {
- *     Point point{0, 0};
- *
- *     if (is<Object>(ctx, index)) {
- *       point.x = getProperty<int>(ctx, index, "x");
- *       point.y = getProperty<int>(ctx, index, "y");
- *     }
- *
- *     return point;
- *   }
- * };
- *
- * }
- * \endcode
- *
- * Now you can invoke `duk::get<Point>(ctx, 0)` to convert a JavaScript object to the Point structure.
- *
- * ## The require function
- *
- * The require function has the same signature as get. It's up to you to decide which criterias makes the object not
- * suitable for conversion.
- *
- * In that example, we will require that object at the index is a JavaScript object and that **x**, **y** are present.
- *
- * \code
- * namespace duk {
- *
- * template <>
- * class TypeTraits<Point> {
- * public:
- *   static Point require(Context *ctx, Index index)
- *   {
- *     Point point;
- *
- *     // Raise an error if not object
- *     if (!is<Object>(ctx, index))
- *       duk::raise(ctx, TypeError("object required"));
- *
- *     // Get x, for simplicity we just check that x and y exist.
- *     if (!hasProperty(ctx, index, "x"))
- *       duk::raise(ctx, TypeError("property x missing"));
- *
- *     // Get y
- *     if (!hasProperty(ctx, index, "y"))
- *       duk::raise(ctx, TypeError("property y missing"));
- *
- *     // Note: if you need more security, check that types are integers too.
- *     point.x = duk::getProperty<int>(ctx, index, "x");
- *     point.y = duk::getProperty<int>(ctx, index, "y");
- *
- *     return point;
- *   }
- * };
- *
- * }
- * \endcode
- *
- * ## The is function
- *
- * The is function returns a boolean. Again, you decide when the value is appropriate.
- *
- * \code
- *
- * namespace duk {
- *
- * template <>
- * class TypeTraits<Point> {
- * public:
- *   static bool is(Context *ctx, Index index)
- *   {
- *     return is<Object>(ctx, index) && hasProperty(ctx, index, "x") && hasProperty(ctx, index, "y");
- *   }
- * };
- *
- * }
- *
- * \endcode
- *
- * ## The optional function
- *
- * The optional function is like get, you should return a value when it is appropriate for conversion. The
- * recommandation is to return the default value **only if** there is no value at the given index or it it not
- * the correct type.
- *
- * Usual implementation looks like this:
- *
- * \code
- * namespace duk {
- *
- * template <>
- * class TypeTraits<Point> {
- * public:
- *   static Point optional(Context *ctx, Index index, Point def)
- *   {
- *     return is(ctx, index) ? get(ctx, index) : def;
- *   }
- * };
- *
- * }
- * \endcode
- */
-
-#include <cassert>
 #include <cstdio>
-#include <functional>
+#include <cstdlib>
 #include <memory>
 #include <string>
-#include <type_traits>
 #include <unordered_map>
 #include <utility>
-#include <vector>
 
 #include <duktape.h>
 
@@ -572,115 +137,6 @@
 };
 
 /**
- * \class TypeTraits
- * \brief Type information to implement new types in JavaScript's context.
- *
- * %This class depending on your needs may have the following functions:
- *
- * ## Construct
- *
- * Used by duk::construct, the function must place the value as this binding when the Duktape C function is
- * new-constructed.
- *
- * \code
- * static void construct(Context *ctx, Type value);
- * \endcode
- *
- * ## Get
- *
- * Convert the value at the given index and return it. Should return default object if value is invalid.
- *
- * \code
- * static Type get(Context *ctx, int index);
- * \endcode
- *
- * ## Is
- *
- * Tells if the value at given index is of the requested type.
- *
- * \code
- * static bool is(Context *ctx, int index);
- * \endcode
- *
- * ## Optional
- *
- * Get the value at the given index or return the defaultValue.
- *
- * \code
- * static Type optional(Context *ctx, int index, Type defaultValue);
- * \endcode
- *
- * ## Push
- *
- * Push the value into the stack.
- *
- * \code
- * static void push(Context *ctx, Type value);
- * \endcode
- *
- * ## Put
- *
- * Apply the value to the object at the top of the stack.
- *
- * \code
- * static void put(Context *ctx, Type value);
- * \endcode
- *
- * ## Require
- *
- * Require a value at the given index.
- *
- * \code
- * static Type require(Context *ctx, int index);
- * \endcode
- *
- */
-template <typename Type>
-class TypeTraits;
-
-/**
- * \class Object
- * \brief Special type for duk::TypeTraits.
- */
-class Object {
-};
-
-/**
- * \class Array
- * \brief Special type for duk::TypeTraits.
- */
-class Array {
-};
-
-/**
- * \class Global
- * \brief Special type for duk::TypeTraits.
- */
-class Global {
-};
-
-/**
- * \class Undefined
- * \brief Special type for duk::TypeTraits.
- */
-class Undefined {
-};
-
-/**
- * \class Null
- * \brief Special type for duk::TypeTraits.
- */
-class Null {
-};
-
-/**
- * \class This
- * \brief Special type for duk::TypeTraits.
- */
-class This {
-};
-
-/**
  * \class Function
  * \brief Duktape/C function definition.
  *
@@ -717,12 +173,6 @@
 using FunctionMap = std::unordered_map<std::string, Function>;
 
 /**
- * \brief Map of any type.
- */
-template <typename T>
-using Map = std::unordered_map<std::string, T>;
-
-/**
  * \class Exception
  * \brief Error description.
  *
@@ -1111,6 +561,7 @@
 {
 	return result ? duk_eval_string(ctx, src.c_str()) : duk_eval_string_noresult(ctx, src.c_str());
 }
+
 /**
  * Wrapper for [duk_gc](http://duktape.org/api.html#duk_gc).
  *
@@ -1123,6 +574,39 @@
 }
 
 /**
+ * Wrapper for [duk_get_global_string](http://duktape.org/api.html#duk_get_global_string).
+ *
+ * \param ctx the context
+ * \param key the property
+ */
+inline bool getGlobal(Context *ctx, const std::string &key)
+{
+	return duk_get_global_string(ctx, key.c_str());
+}
+
+/**
+ * Wrapper for [duk_get_prop_string](http://duktape.org/api.html#duk_get_prop_string).
+ *
+ * \param ctx the context
+ * \param key the property
+ */
+inline bool getProperty(Context *ctx, Index index, const std::string &key)
+{
+	return duk_get_prop_string(ctx, index, key.c_str());
+}
+
+/**
+ * Wrapper for [duk_get_prop_index](http://duktape.org/api.html#duk_get_prop_index).
+ *
+ * \param ctx the context
+ * \param position the property
+ */
+inline bool getProperty(Context *ctx, Index index, unsigned position)
+{
+	return duk_get_prop_index(ctx, index, position);
+}
+
+/**
  * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop).
  *
  * \param ctx the context
@@ -1328,6 +812,17 @@
 }
 
 /**
+ * Wrapper for [duk_put_global_string](http://duktape.org/api.html#duk_put_global_string).
+ *
+ * \param ctx the context
+ * \param key the property
+ */
+inline bool putGlobal(Context *ctx, const std::string &key)
+{
+	return duk_put_global_string(ctx, key.c_str());
+}
+
+/**
  * Wrapper for [duk_put_prop](http://duktape.org/api.html#duk_put_prop).
  *
  * \param ctx the context
@@ -1524,284 +1019,6 @@
 }
 
 /**
- * Push a value into the stack. Calls TypeTraits<T>::push(ctx, value);
- *
- * \param ctx the context
- * \param value the value to forward
- */
-template <typename Type>
-inline void push(Context *ctx, Type &&value)
-{
-	TypeTraits<std::decay_t<Type>>::push(ctx, std::forward<Type>(value));
-}
-
-/**
- * Put the value to the object at the top of the stack. Calls TypeTraits<T>::put(ctx, value);
- *
- * \param ctx the context
- * \param value the value to apply
- */
-template <typename Type>
-inline void put(Context *ctx, Type &&value)
-{
-	TypeTraits<std::decay_t<Type>>::put(ctx, std::forward<Type>(value));
-}
-
-/**
- * Generic template function to get a value from the stack.
- *
- * \param ctx the context
- * \param index the index
- * \return the value
- */
-template <typename Type>
-inline auto get(Context *ctx, int index) -> decltype(TypeTraits<Type>::get(ctx, 0))
-{
-	return TypeTraits<Type>::get(ctx, index);
-}
-
-/**
- * Require a type at the specified index.
- *
- * \param ctx the context
- * \param index the index
- * \return the value
- */
-template <typename Type>
-inline auto require(Context *ctx, int index) -> decltype(TypeTraits<Type>::require(ctx, 0))
-{
-	return TypeTraits<Type>::require(ctx, index);
-}
-
-/**
- * Check if a value is a type of T.
- *
- * The TypeTraits<T> must have `static bool is(ContextPtr ptr, int index)`.
- *
- * \param ctx the context
- * \param index the value index
- * \return true if is the type
- */
-template <typename T>
-inline bool is(Context *ctx, int index)
-{
-	return TypeTraits<T>::is(ctx, index);
-}
-
-/**
- * Get an optional value from the stack, if the value is not available of not the correct type,
- * return defaultValue instead.
- *
- * The TypeTraits<T> must have `static T optional(Context &, int index, T &&defaultValue)`.
- *
- * \param ctx the context
- * \param index the value index
- * \param defaultValue the value replacement
- * \return the value or defaultValue
- */
-template <typename Type>
-inline auto optional(Context *ctx, int index, Type &&defaultValue)
-{
-	return TypeTraits<std::decay_t<Type>>::optional(ctx, index, std::forward<Type>(defaultValue));
-}
-
-/**
- * Get the property `name' as value from the object at the specified index.
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \return the value
- * \note The stack is unchanged
- */
-template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr>
-inline auto getProperty(Context *ctx, int index, const std::string &name) -> decltype(get<Type>(ctx, 0))
-{
-	duk_get_prop_string(ctx, index, name.c_str());
-	decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1);
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
- * Get a property by index, for arrays.
- *
- * \param ctx the context
- * \param index the object index
- * \param position the position int the object
- * \return the value
- * \note The stack is unchanged
- */
-template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr>
-inline auto getProperty(Context *ctx, int index, int position) -> decltype(get<Type>(ctx, 0))
-{
-	duk_get_prop_index(ctx, index, position);
-	decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1);
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
- * Get the property `name' and push it to the stack from the object at the specified index.
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \note The stack contains the property value
- */
-template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr>
-inline void getProperty(Context *ctx, int index, const std::string &name)
-{
-	duk_get_prop_string(ctx, index, name.c_str());
-}
-
-/**
- * Get the property by index and push it to the stack from the object at the specified index.
- *
- * \param ctx the context
- * \param index the object index
- * \param position the position in the object
- * \note The stack contains the property value
- */
-template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr>
-inline void getProperty(Context *ctx, int index, int position)
-{
-	duk_get_prop_index(ctx, index, position);
-}
-
-/**
- * Get an optional property `name` from the object at the specified index.
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \param def the default value
- * \return the value or def
- * \note The stack is unchanged
- */
-template <typename Type, typename DefaultValue>
-inline auto optionalProperty(Context *ctx, int index, const std::string &name, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def)))
-{
-	duk_get_prop_string(ctx, index, name.c_str());
-	decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) value = optional(ctx, -1, std::forward<DefaultValue>(def));
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
- * Get an optional property by index, for arrays
- *
- * \param ctx the context
- * \param index the object index
- * \param position the position int the object
- * \param def the default value
- * \return the value or def
- * \note The stack is unchanged
- */
-template <typename Type, typename DefaultValue>
-inline auto optionalProperty(Context *ctx, int index, int position, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def)))
-{
-	duk_get_prop_index(ctx, index, position);
-	decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) value = optional(ctx, -1, std::forward<DefaultValue>(def));
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
- * Set a property to the object at the specified index.
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \param value the value to forward
- * \note The stack is unchanged
- */
-template <typename Type>
-void putProperty(Context *ctx, int index, const std::string &name, Type &&value)
-{
-	index = duk_normalize_index(ctx, index);
-
-	push(ctx, std::forward<Type>(value));
-	duk_put_prop_string(ctx, index, name.c_str());
-}
-
-/**
- * Set a property by index, for arrays.
- *
- * \param ctx the context
- * \param index the object index
- * \param position the position in the object
- * \param value the value to forward
- * \note The stack is unchanged
- */
-template <typename Type>
-void putProperty(Context *ctx, int index, int position, Type &&value)
-{
-	index = duk_normalize_index(ctx, index);
-
-	push(ctx, std::forward<Type>(value));
-	duk_put_prop_index(ctx, index, position);
-}
-
-/**
- * Get a global value.
- *
- * \param ctx the context
- * \param name the name of the global variable
- * \return the value
- */
-template <typename Type>
-inline auto getGlobal(Context *ctx, const std::string &name, std::enable_if_t<!std::is_void<Type>::value> * = nullptr) -> decltype(get<Type>(ctx, 0))
-{
-	duk_get_global_string(ctx, name.c_str());
-	decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1);
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
- * Overload that push the value at the top of the stack instead of returning it.
- *
- * \param ctx the context
- * \param name the name of the global variable
- */
-template <typename Type>
-inline void getGlobal(Context *ctx, const std::string &name, std::enable_if_t<std::is_void<Type>::value> * = nullptr)
-{
-	duk_get_global_string(ctx, name.c_str());
-}
-
-/**
- * Set a global variable.
- *
- * \param ctx the context
- * \param name the name of the global variable
- * \param type the value to set
- */
-template <typename Type>
-inline void putGlobal(Context *ctx, const std::string &name, Type&& type)
-{
-	push(ctx, std::forward<Type>(type));
-	duk_put_global_string(ctx, name.c_str());
-}
-
-/**
- * Put the value at the top of the stack as global property.
- *
- * \param ctx the context
- * \param name the property name
- */
-inline void putGlobal(Context *ctx, const std::string &name)
-{
-	duk_put_global_string(ctx, name.c_str());
-}
-
-/**
  * Enumerate an object or an array at the specified index.
  *
  * \param ctx the context
@@ -1824,22 +1041,6 @@
 }
 
 /**
- * Return the this binding of the current function.
- *
- * \param ctx the context
- * \return the this binding as the template given
- */
-template <typename T>
-inline auto self(Context *ctx) -> decltype(TypeTraits<T>::require(ctx, 0))
-{
-	duk_push_this(ctx);
-	decltype(TypeTraits<T>::require(ctx, 0)) value = TypeTraits<T>::require(ctx, -1);
-	duk_pop(ctx);
-
-	return value;
-}
-
-/**
  * Throw an ECMAScript exception.
  *
  * \param ctx the context
@@ -1852,23 +1053,6 @@
 }
 
 /**
- * Construct the object in place, setting value as this binding.
- *
- * The TypeTraits<T> must have the following requirements:
- *
- * - static void construct(Context &, T): must update this with the value and keep the stack unchanged
- *
- * \param ctx the context
- * \param value the value to forward
- * \see self
- */
-template <typename T>
-inline void construct(Context *ctx, T &&value)
-{
-	TypeTraits<std::decay_t<T>>::construct(ctx, std::forward<T>(value));
-}
-
-/**
  * \}
  */
 
@@ -2021,842 +1205,488 @@
 };
 
 /**
- * \class TypeTraits<int>
- * \brief Default implementation for int.
+ * Get an integer, return 0 if not an integer.
  *
- * Provides: get, is, optional, push, require.
+ * \param ctx the context
+ * \param index the index
+ * \return the integer
  */
-template <>
-class TypeTraits<int> {
-public:
-	/**
-	 * Get an integer, return 0 if not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the integer
-	 */
-	static inline int get(Context *ctx, int index)
-	{
-		return duk_get_int(ctx, index);
-	}
+inline int getInt(Context *ctx, int index)
+{
+	return duk_get_int(ctx, index);
+}
 
-	/**
-	 * Check if value is an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if integer
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_number(ctx, index) != 0;
-	}
+/**
+ * Get a boolean, return 0 if not a boolean.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the boolean
+ */
+inline bool getBool(Context *ctx, int index)
+{
+	return duk_get_boolean(ctx, index) != 0;
+}
 
-	/**
-	 * Get an integer, return defaultValue if the value is not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the integer or defaultValue
-	 */
-	static inline int optional(Context *ctx, int index, int defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
+/**
+ * Get a double, return 0 if not a double.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the double
+ */
+inline double getDouble(Context *ctx, int index)
+{
+	return duk_get_number(ctx, index);
+}
 
-	/**
-	 * Push an integer.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, int value)
-	{
-		duk_push_int(ctx, value);
-	}
+/**
+ * Get a string, return 0 if not a string.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the string
+ */
+inline std::string getString(Context *ctx, int index)
+{
+	duk_size_t size;
+	const char *text = duk_get_lstring(ctx, index, &size);
 
-	/**
-	 * Require an integer, throws a JavaScript exception if not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the integer
-	 */
-	static inline int require(Context *ctx, int index)
-	{
-		return duk_require_int(ctx, index);
-	}
-};
+	return std::string(text, size);
+}
 
 /**
- * \class TypeTraits<bool>
- * \brief Default implementation for bool.
+ * Get an integer, return 0 if not an integer.
  *
- * Provides: get, is, optional, push, require.
+ * \param ctx the context
+ * \param index the index
+ * \return the integer
  */
-template <>
-class TypeTraits<bool> {
-public:
-	/**
-	 * Get a boolean, return 0 if not a boolean.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the boolean
-	 */
-	static inline bool get(Context *ctx, int index)
-	{
-		return duk_get_boolean(ctx, index) != 0;
-	}
+inline unsigned getUnsigned(Context *ctx, int index)
+{
+	return duk_get_uint(ctx, index);
+}
 
-	/**
-	 * Check if value is a boolean.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if boolean
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_boolean(ctx, index) != 0;
-	}
+/**
+ * Get a pointer, return nullptr if not a pointer.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the pointer
+ */
+inline void *getPointer(Context *ctx, int index)
+{
+	return duk_to_pointer(ctx, index);
+}
 
-	/**
-	 * Get a bool, return defaultValue if the value is not a boolean.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the boolean or defaultValue
-	 */
-	static inline bool optional(Context *ctx, int index, bool defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
+/**
+ * Check if value is a array.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return true if array
+ */
+inline bool isArray(Context *ctx, int index)
+{
+	return duk_is_array(ctx, index) != 0;
+}
 
-	/**
-	 * Push a boolean.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, bool value)
-	{
-		duk_push_boolean(ctx, value);
-	}
+/**
+ * Check if value is a boolean.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return true if boolean
+ */
+inline bool isBool(Context *ctx, int index)
+{
+	return duk_is_boolean(ctx, index) != 0;
+}
 
-	/**
-	 * Require a boolean, throws a JavaScript exception if not a boolean.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the boolean
-	 */
-	static inline bool require(Context *ctx, int index)
-	{
-		return duk_require_boolean(ctx, index) != 0;
-	}
-};
+/**
+ * Check if value is null.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return true if null
+ */
+inline bool isNull(Context *ctx, int index)
+{
+	return duk_is_null(ctx, index) != 0;
+}
 
 /**
- * \class TypeTraits<double>
- * \brief Default implementation for double.
+ * Check if value is an integer.
  *
- * Provides: get, is, optional, push, require.
+ * \param ctx the context
+ * \param index the index
+ * \return true if integer
  */
-template <>
-class TypeTraits<double> {
-public:
-	/**
-	 * Get a double, return 0 if not a double.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the double
-	 */
-	static inline double get(Context *ctx, int index)
-	{
-		return duk_get_number(ctx, index);
-	}
+inline bool isNumber(Context *ctx, int index)
+{
+	return duk_is_number(ctx, index) != 0;
+}
 
-	/**
-	 * Check if value is a double.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if double
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_number(ctx, index) != 0;
-	}
+/**
+ * Check if value is an object.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return true if object
+ */
+inline bool isObject(Context *ctx, int index)
+{
+	return duk_is_object(ctx, index) != 0;
+}
 
-	/**
-	 * Get a double, return defaultValue if the value is not a double.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the double or defaultValue
-	 */
-	static inline double optional(Context *ctx, int index, double defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
+/**
+ * Check if value is a pointer.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return true if pointer
+ */
+inline bool isPointer(Context *ctx, int index)
+{
+	return duk_is_pointer(ctx, index) != 0;
+}
 
-	/**
-	 * Push a double.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, double value)
-	{
-		duk_push_number(ctx, value);
-	}
+/**
+ * Check if value is a string.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return true if string
+ */
+inline bool isString(Context *ctx, int index)
+{
+	return duk_is_string(ctx, index) != 0;
+}
 
-	/**
-	 * Require a double, throws a JavaScript exception if not a double.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the double
-	 */
-	static inline double require(Context *ctx, int index)
-	{
-		return duk_require_number(ctx, index);
-	}
-};
+/**
+ * Check if value is undefined.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return true if undefined
+ */
+inline bool isUndefined(Context *ctx, int index)
+{
+	return duk_is_undefined(ctx, index) != 0;
+}
 
 /**
- * \class TypeTraits<std::string>
- * \brief Default implementation for std::string.
+ * Get a bool, return defaultValue if the value is not a boolean.
  *
- * Provides: get, is, optional, push, require.
- *
- * Note: the functions allows embedded '\0'.
+ * \param ctx the context
+ * \param index the index
+ * \param defaultValue the defaultValue
+ * \return the boolean or defaultValue
  */
-template <>
-class TypeTraits<std::string> {
-public:
-	/**
-	 * Get a string, return 0 if not a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the string
-	 */
-	static inline std::string get(Context *ctx, int index)
-	{
-		duk_size_t size;
-		const char *text = duk_get_lstring(ctx, index, &size);
-
-		return std::string{text, size};
-	}
-
-	/**
-	 * Check if value is a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if string
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_string(ctx, index) != 0;
-	}
+inline bool optionalBool(Context *ctx, int index, bool defaultValue)
+{
+	return isBool(ctx, index) ? getBool(ctx, index) : defaultValue;
+}
 
-	/**
-	 * Get a string, return defaultValue if the value is not an string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the string or defaultValue
-	 */
-	static inline std::string optional(Context *ctx, int index, std::string defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
-
-	/**
-	 * Push a string.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, const std::string &value)
-	{
-		duk_push_lstring(ctx, value.c_str(), value.length());
-	}
-
-	/**
-	 * Require a string, throws a JavaScript exception if not a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the string
-	 */
-	static inline std::string require(Context *ctx, int index)
-	{
-		duk_size_t size;
-		const char *text = duk_require_lstring(ctx, index, &size);
-
-		return std::string{text, size};
-	}
-};
+/**
+ * Get a double, return defaultValue if the value is not a double.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \param defaultValue the defaultValue
+ * \return the double or defaultValue
+ */
+inline double optionalDouble(Context *ctx, int index, double defaultValue)
+{
+	return isNumber(ctx, index) ? getDouble(ctx, index) : defaultValue;
+}
 
 /**
- * \class TypeTraits<const char *>
- * \brief Default implementation for const char literals.
+ * Get an integer, return defaultValue if the value is not an integer.
  *
- * Provides: get, is, optional, push, require.
+ * \param ctx the context
+ * \param index the index
+ * \param defaultValue the defaultValue
+ * \return the integer or defaultValue
  */
-template <>
-class TypeTraits<const char *> {
-public:
-	/**
-	 * Get a string, return 0 if not a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the string
-	 */
-	static inline const char *get(Context *ctx, int index)
-	{
-		return duk_get_string(ctx, index);
-	}
-
-	/**
-	 * Check if value is a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if string
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_string(ctx, index) != 0;
-	}
+inline int optionalInt(Context *ctx, int index, int defaultValue)
+{
+	return isNumber(ctx, index) ? getInt(ctx, index) : defaultValue;
+}
 
-	/**
-	 * Get an integer, return defaultValue if the value is not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the integer or defaultValue
-	 */
-	static inline const char *optional(Context *ctx, int index, const char *defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
+/**
+ * Get a string, return defaultValue if the value is not an string.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \param defaultValue the defaultValue
+ * \return the string or defaultValue
+ */
+inline std::string optionalString(Context *ctx, int index, std::string defaultValue)
+{
+	return isString(ctx, index) ? getString(ctx, index) : defaultValue;
+}
 
-	/**
-	 * Push a string.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, const char *value)
-	{
-		duk_push_string(ctx, value);
-	}
-
-	/**
-	 * Require a string, throws a JavaScript exception if not a string.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the string
-	 */
-	static inline const char *require(Context *ctx, int index)
-	{
-		return duk_require_string(ctx, index);
-	}
-};
+/**
+ * Get an integer, return defaultValue if the value is not an integer.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \param defaultValue the defaultValue
+ * \return the integer or defaultValue
+ */
+inline unsigned optionalUnsigned(Context *ctx, int index, unsigned defaultValue)
+{
+	return isNumber(ctx, index) ? getUnsigned(ctx, index) : defaultValue;
+}
 
 /**
- * \class TypeTraits<unsigned>
- * \brief Default implementation for unsigned.
+ * Get a pointer, return defaultValue if the value is not a pointer.
  *
- * Provides: get, is, optional, push, require.
+ * \param ctx the context
+ * \param index the index
+ * \param defaultValue the defaultValue
+ * \return the pointer or defaultValue
  */
-template <>
-class TypeTraits<unsigned> {
-public:
-	/**
-	 * Get an integer, return 0 if not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the integer
-	 */
-	static inline unsigned get(Context *ctx, int index)
-	{
-		return duk_get_uint(ctx, index);
-	}
+inline void *optionalPointer(Context *ctx, int index, void *defaultValue)
+{
+	return isPointer(ctx, index) ? getPointer(ctx, index) : defaultValue;
+}
 
-	/**
-	 * Check if value is an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if integer
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_number(ctx, index) != 0;
-	}
+/**
+ * Create an empty array on the stack.
+ *
+ * \param ctx the context
+ */
+inline void pushArray(Context *ctx)
+{
+	duk_push_array(ctx);
+}
 
-	/**
-	 * Get an integer, return defaultValue if the value is not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the integer or defaultValue
-	 */
-	static inline unsigned optional(Context *ctx, int index, unsigned defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
+/**
+ * Push a boolean.
+ *
+ * \param ctx the context
+ * \param value the value
+ */
+inline void pushBool(Context *ctx, bool value)
+{
+	duk_push_boolean(ctx, value);
+}
 
-	/**
-	 * Push an integer.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, unsigned value)
-	{
-		duk_push_uint(ctx, value);
-	}
+/**
+ * Push a double.
+ *
+ * \param ctx the context
+ * \param value the value
+ */
+inline void pushDouble(Context *ctx, double value)
+{
+	duk_push_number(ctx, value);
+}
 
-	/**
-	 * Require an integer, throws a JavaScript exception if not an integer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the integer
-	 */
-	static inline unsigned require(Context *ctx, int index)
-	{
-		return duk_require_uint(ctx, index);
-	}
-};
+/**
+ * Push the global object into the stack.
+ *
+ * \param ctx the context
+ */
+inline void pushGlobal(Context *ctx)
+{
+	duk_push_global_object(ctx);
+}
 
 /**
- * \brief Implementation for raw pointers.
+ * Push an integer.
  *
- * Provides: get, is, optional, push, require.
+ * \param ctx the context
+ * \param value the value
  */
-template <>
-class TypeTraits<void *> {
-public:
-	/**
-	 * Get a pointer, return nullptr if not a pointer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the pointer
-	 */
-	static inline void *get(Context *ctx, int index)
-	{
-		return duk_to_pointer(ctx, index);
-	}
-
-	/**
-	 * Check if value is a pointer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if pointer
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_pointer(ctx, index) != 0;
-	}
+inline void pushInt(Context *ctx, int value)
+{
+	duk_push_int(ctx, value);
+}
 
-	/**
-	 * Get a pointer, return defaultValue if the value is not a pointer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \param defaultValue the defaultValue
-	 * \return the pointer or defaultValue
-	 */
-	static inline void *optional(Context *ctx, int index, void *defaultValue)
-	{
-		return is(ctx, index) ? get(ctx, index) : defaultValue;
-	}
-
-	/**
-	 * Push a pointer.
-	 *
-	 * \param ctx the context
-	 * \param value the value
-	 */
-	static inline void push(Context *ctx, void *value)
-	{
-		duk_push_pointer(ctx, value);
-	}
-
-	/**
-	 * Require a pointer, throws a JavaScript exception if not a pointer.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return the pointer
-	 */
-	static inline void *require(Context *ctx, int index)
-	{
-		return duk_require_pointer(ctx, index);
-	}
-};
+/**
+ * Push null value on the stack.
+ *
+ * \param ctx the context
+ */
+inline void pushNull(Context *ctx)
+{
+	duk_push_null(ctx);
+}
 
 /**
- * \class TypeTraits<Function>
- * \brief Push C++ function to the stack.
+ * Create an empty object on the stack.
  *
- * Provides: push.
- *
- * This implementation push a Duktape/C function that is wrapped as C++ for convenience.
+ * \param ctx the context
  */
-template <>
-class TypeTraits<Function> {
-public:
-	/**
-	 * Check if the value at the given index is callable.
-	 *
-	 * \param ctx the context
-	 * \param index the value index
-	 * \return true if the value is callable
-	 */
-	static bool is(Context *ctx, Index index)
-	{
-		return duk_is_callable(ctx, index) != 0;
-	}
-
-	/**
-	 * Push the C++ function, it is wrapped as Duktape/C function and allocated on the heap by moving the
-	 * std::function.
-	 *
-	 * \param ctx the context
-	 * \param fn the function
-	 */
-	static void push(Context *ctx, Function fn)
-	{
-		duk_push_c_function(ctx, fn.function, fn.nargs);
-	}
-};
+inline void pushObject(Context *ctx)
+{
+	duk_push_object(ctx);
+}
 
 /**
- * \class TypeTraits<FunctionMap>
- * \brief Put the functions to the object at the top of the stack.
+ * Push a string.
  *
- * Provides: put.
+ * \param ctx the context
+ * \param value the value
  */
-template <>
-class TypeTraits<FunctionMap> {
-public:
-	/**
-	 * Push all functions to the object at the top of the stack.
-	 *
-	 * \param ctx the context
-	 * \param map the map of function
-	 */
-	static void put(Context *ctx, const FunctionMap &map)
-	{
-		StackAssert sa(ctx, 0);
-
-		for (const auto &entry : map) {
-			duk_push_c_function(ctx, entry.second.function, entry.second.nargs);
-			duk_put_prop_string(ctx, -2, entry.first.c_str());
-		}
-	}
-};
+inline void pushString(Context *ctx, const std::string &value)
+{
+	duk_push_lstring(ctx, value.c_str(), value.length());
+}
 
 /**
- * \class TypeTraits<Object>
- * \brief Push empty object to the stack.
+ * Push this function into the stack.
  *
- * Provides: is, push.
+ * \param ctx the context
  */
-template <>
-class TypeTraits<Object> {
-public:
-	/**
-	 * Check if value is an object.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if object
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_object(ctx, index) != 0;
-	}
+inline void pushThis(Context *ctx)
+{
+	duk_push_this(ctx);
+}
 
-	/**
-	 * Create an empty object on the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const Object &)
-	{
-		duk_push_object(ctx);
-	}
-};
+/**
+ * Push undefined value on the stack.
+ *
+ * \param ctx the context
+ */
+inline void pushUndefined(Context *ctx)
+{
+	duk_push_undefined(ctx);
+}
 
 /**
- * \class TypeTraits<Array>
- * \brief Push empty array to the stack.
+ * Push an integer.
  *
- * Provides: is, push.
+ * \param ctx the context
+ * \param value the value
  */
-template <>
-class TypeTraits<Array> {
-public:
-	/**
-	 * Check if value is a array.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if array
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_array(ctx, index) != 0;
-	}
+inline void pushUnsigned(Context *ctx, unsigned value)
+{
+	duk_push_uint(ctx, value);
+}
 
-	/**
-	 * Create an empty array on the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const Array &)
-	{
-		duk_push_array(ctx);
-	}
-};
+/**
+ * Push a pointer.
+ *
+ * \param ctx the context
+ * \param value the value
+ */
+inline void pushPointer(Context *ctx, void *value)
+{
+	duk_push_pointer(ctx, value);
+}
 
 /**
- * \class TypeTraits<Undefined>
- * \brief Push undefined value to the stack.
- *
- * Provides: is, push.
+ * \param ctx the context
+ * \param fn the function
  */
-template <>
-class TypeTraits<Undefined> {
-public:
-	/**
-	 * Check if value is undefined.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if undefined
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_undefined(ctx, index) != 0;
-	}
-
-	/**
-	 * Push undefined value on the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const Undefined &)
-	{
-		duk_push_undefined(ctx);
-	}
-};
+inline void pushFunction(Context *ctx, Function fn)
+{
+	duk_push_c_function(ctx, fn.function, fn.nargs);
+}
 
 /**
- * \class TypeTraits<Null>
- * \brief Push null value to the stack.
- *
- * Provides: is, push.
+ * \param ctx the context
+ * \param fn the function
  */
-template <>
-class TypeTraits<Null> {
-public:
-	/**
-	 * Check if value is null.
-	 *
-	 * \param ctx the context
-	 * \param index the index
-	 * \return true if null
-	 */
-	static inline bool is(Context *ctx, int index)
-	{
-		return duk_is_null(ctx, index) != 0;
-	}
-
-	/**
-	 * Push null value on the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const Null &)
-	{
-		duk_push_null(ctx);
-	}
-};
+inline void pushFunction(Context *ctx, duk_c_function function, duk_idx_t nargs = 0)
+{
+	duk_push_c_function(ctx, function, nargs);
+}
 
 /**
- * \brief Push this binding into the stack.
+ * Push all functions to the object at the top of the stack.
  *
- * Provides: push.
+ * \param ctx the context
+ * \param map the map of function
  */
-template <>
-class TypeTraits<This> {
-public:
-	/**
-	 * Push this function into the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const This &)
-	{
-		duk_push_this(ctx);
+inline void putFunctions(Context *ctx, const FunctionMap &map)
+{
+	StackAssert sa(ctx, 0);
+
+	for (const auto &entry : map) {
+		duk_push_c_function(ctx, entry.second.function, entry.second.nargs);
+		duk_put_prop_string(ctx, -2, entry.first.c_str());
 	}
-};
+}
 
 /**
- * \class TypeTraits<Global>
- * \brief Push the global object to the stack.
+ * Require a boolean, throws a JavaScript exception if not a boolean.
  *
- * Provides: push.
+ * \param ctx the context
+ * \param index the index
+ * \return the boolean
  */
-template <>
-class TypeTraits<Global> {
-public:
-	/**
-	 * Push the global object into the stack.
-	 *
-	 * \param ctx the context
-	 */
-	static inline void push(Context *ctx, const Global &)
-	{
-		duk_push_global_object(ctx);
-	}
-};
+inline bool requireBool(Context *ctx, int index)
+{
+	return duk_require_boolean(ctx, index) != 0;
+}
 
 /**
- * \brief Push a map of key-value pair as objects.
+ * Require a double, throws a JavaScript exception if not a double.
  *
- * Provides: push, put.
- *
- * This class is convenient for settings constants such as enums, string and such.
+ * \param ctx the context
+ * \param index the index
+ * \return the double
  */
-template <typename T>
-class TypeTraits<std::unordered_map<std::string, T>> {
-public:
-	/**
-	 * Put all values from the map as properties to the object at the top of the stack.
-	 *
-	 * \param ctx the context
-	 * \param map the values
-	 * \note You need an object at the top of the stack before calling this function
-	 */
-	static void push(Context *ctx, const std::unordered_map<std::string, T> &map)
-	{
-		StackAssert sa(ctx, 1);
+inline double requireDouble(Context *ctx, int index)
+{
+	return duk_require_number(ctx, index);
+}
 
-		duk_push_object(ctx);
-		put(ctx, map);
-	}
-
-	/**
-	 * Apply the map to the object at the top of the stack.
-	 *
-	 * \pre top value must be an object
-	 * \param ctx the context
-	 * \param map the map
-	 */
-	static void put(Context *ctx, const std::unordered_map<std::string, T> &map)
-	{
-		assert(type(ctx, -1) == DUK_TYPE_OBJECT);
-
-		StackAssert sa(ctx);
-
-		for (const auto &pair : map) {
-			TypeTraits<T>::push(ctx, pair.second);
-			duk_put_prop_string(ctx, -2, pair.first.c_str());
-		}
-	}
-};
+/**
+ * Require an integer, throws a JavaScript exception if not an integer.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the integer
+ */
+inline int requireInt(Context *ctx, int index)
+{
+	return duk_require_int(ctx, index);
+}
 
 /**
- * \brief Push or get vectors as JavaScript arrays.
+ * Require a string, throws a JavaScript exception if not a string.
  *
- * Provides: get, push, put.
+ * \param ctx the context
+ * \param index the index
+ * \return the string
  */
-template <typename T>
-class TypeTraits<std::vector<T>> {
-public:
-	/**
-	 * Get an array from the stack.
-	 *
-	 * \param ctx the context
-	 * \param index the array index
-	 * \return the array or empty array if the value is not an array
-	 */
-	static std::vector<T> get(Context *ctx, int index)
-	{
-		StackAssert sa(ctx, 0);
+inline std::string requireString(Context *ctx, int index)
+{
+	duk_size_t size;
+	const char *text = duk_require_lstring(ctx, index, &size);
 
-		std::vector<T> result;
-
-		if (!duk_is_array(ctx, -1))
-			return result;
-
-		size_t total = duk_get_length(ctx, index);
-
-		for (size_t i = 0; i < total; ++i)
-			result.push_back(getProperty<T>(ctx, index, static_cast<int>(i)));
-
-		return result;
-	}
+	return std::string(text, size);
+}
 
-	/**
-	 * Create an array with the specified values.
-	 *
-	 * \param ctx the context
-	 * \param array the values
-	 */
-	static void push(Context *ctx, const std::vector<T> &array)
-	{
-		StackAssert sa(ctx, 1);
-
-		duk_push_array(ctx);
-		put(ctx, array);
-	}
+/**
+ * Require an integer, throws a JavaScript exception if not an integer.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the integer
+ */
+inline unsigned requireUnsigned(Context *ctx, int index)
+{
+	return duk_require_uint(ctx, index);
+}
 
-	/**
-	 * Apply the array to the object at the top of the stack.
-	 *
-	 * \pre top value must be an object
-	 * \param ctx the context
-	 * \param array the array
-	 */
-	static void put(Context *ctx, const std::vector<T> &array)
-	{
-		assert(type(ctx, -1) == DUK_TYPE_OBJECT);
-
-		StackAssert sa(ctx);
-
-		unsigned i = 0;
-		for (const auto &v : array) {
-			TypeTraits<T>::push(ctx, v);
-			duk_put_prop_index(ctx, -2, i++);
-		}
-	}
-};
+/**
+ * Require a pointer, throws a JavaScript exception if not a pointer.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the pointer
+ */
+inline void *requirePointer(Context *ctx, int index)
+{
+	return duk_require_pointer(ctx, index);
+}
 
 } // !duk
 
--- a/modules/js/test/main.cpp	Wed Jun 01 17:36:52 2016 +0200
+++ b/modules/js/test/main.cpp	Thu Jun 02 16:55:45 2016 +0200
@@ -38,11 +38,11 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, true);
-	ASSERT_TRUE(duk::get<bool>(context, -1));
+	duk::pushBool(context, true);
+	ASSERT_TRUE(duk::getBool(context, -1));
 	ASSERT_EQ(1, duk::top(context));
-	duk::push(context, false);
-	ASSERT_FALSE(duk::get<bool>(context, -1));
+	duk::pushBool(context, false);
+	ASSERT_FALSE(duk::getBool(context, -1));
 	ASSERT_EQ(2, duk::top(context));
 }
 
@@ -51,11 +51,11 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, 123);
-	ASSERT_EQ(123, duk::get<int>(context, -1));
+	duk::pushInt(context, 123);
+	ASSERT_EQ(123, duk::getInt(context, -1));
 	ASSERT_EQ(1, duk::top(context));
-	duk::push(context, 456);
-	ASSERT_EQ(456, duk::get<int>(context, -1));
+	duk::pushInt(context, 456);
+	ASSERT_EQ(456, duk::getInt(context, -1));
 	ASSERT_EQ(2, duk::top(context));
 }
 
@@ -64,11 +64,11 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, 123U);
-	ASSERT_EQ(123U, duk::get<unsigned>(context, -1));
+	duk::pushUnsigned(context, 123U);
+	ASSERT_EQ(123U, duk::getUnsigned(context, -1));
 	ASSERT_EQ(1, duk::top(context));
-	duk::push(context, 456U);
-	ASSERT_EQ(456U, duk::get<unsigned>(context, -1));
+	duk::pushUnsigned(context, 456U);
+	ASSERT_EQ(456U, duk::getUnsigned(context, -1));
 	ASSERT_EQ(2, duk::top(context));
 }
 
@@ -77,11 +77,11 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, 10.5);
-	ASSERT_EQ(10.5, duk::get<double>(context, -1));
+	duk::pushDouble(context, 10.5);
+	ASSERT_EQ(10.5, duk::getDouble(context, -1));
 	ASSERT_EQ(1, duk::top(context));
-	duk::push(context, 50.1);
-	ASSERT_EQ(50.1, duk::get<double>(context, -1));
+	duk::pushDouble(context, 50.1);
+	ASSERT_EQ(50.1, duk::getDouble(context, -1));
 	ASSERT_EQ(2, duk::top(context));
 }
 
@@ -90,8 +90,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, "hello world!");
-	ASSERT_EQ("hello world!", duk::get<std::string>(context, -1));
+	duk::pushString(context, "hello world!");
+	ASSERT_EQ("hello world!", duk::getString(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -100,7 +100,7 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, duk::Undefined{});
+	duk::pushUndefined(context);
 	ASSERT_EQ(DUK_TYPE_UNDEFINED, duk::type(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
@@ -110,52 +110,19 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, duk::Null{});
+	duk::pushNull(context);
 	ASSERT_EQ(DUK_TYPE_NULL, duk::type(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
-TEST(PushAndGet, map)
-{
-	duk::UniqueContext context;
-	duk::Map<int> map{
-		{ "one",	1 },
-		{ "two",	2 }
-	};
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, map);
-
-	ASSERT_EQ(DUK_TYPE_OBJECT, duk::type(context, -1));
-	ASSERT_EQ(1, duk::getProperty<int>(context, -1, "one"));
-	ASSERT_EQ(2, duk::getProperty<int>(context, -1, "two"));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(PushAndGet, vector)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, std::vector<int>{1, 2, 3});
-	ASSERT_EQ(DUK_TYPE_OBJECT, duk::type(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-
-	auto array = duk::get<std::vector<int>>(context, -1);
-	ASSERT_EQ(3U, array.size());
-	ASSERT_EQ(1, array[0]);
-	ASSERT_EQ(2, array[1]);
-	ASSERT_EQ(3, array[2]);
-}
-
 TEST(PushAndGet, pointer)
 {
 	duk::UniqueContext context;
 	int value = 1;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push<void *>(context, &value);
-	ASSERT_EQ(1, *static_cast<int *>(duk::get<void *>(context, -1)));
+	duk::pushPointer(context, &value);
+	ASSERT_EQ(1, *static_cast<int *>(duk::getPointer(context, -1)));
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -171,11 +138,11 @@
 	ASSERT_EQ(0, duk::top(context));
 
 	try {
-		duk::push(context, duk::Function{[] (duk::Context *ctx) -> duk::Ret {
-			duk::require<bool>(ctx, 0);
+		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
+			duk::requireBool(ctx, 0);
 
 			return 0;
-		}});
+		});
 
 		ASSERT_NE(0, duk::peval(context));
 	} catch (const std::exception &ex) {
@@ -192,11 +159,11 @@
 	ASSERT_EQ(0, duk::top(context));
 
 	try {
-		duk::push(context, duk::Function{[] (duk::Context *ctx) -> duk::Ret {
-			duk::require<int>(ctx, 0);
+		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
+			duk::requireInt(ctx, 0);
 
 			return 0;
-		}});
+		});
 
 		ASSERT_NE(0, duk::peval(context));
 	} catch (const std::exception &ex) {
@@ -213,11 +180,11 @@
 	ASSERT_EQ(0, duk::top(context));
 
 	try {
-		duk::push(context, duk::Function{[] (duk::Context *ctx) -> duk::Ret {
-			duk::require<unsigned>(ctx, 0);
+		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
+			duk::requireUnsigned(ctx, 0);
 
 			return 0;
-		}});
+		});
 
 		ASSERT_NE(0, duk::peval(context));
 	} catch (const std::exception &ex) {
@@ -234,11 +201,11 @@
 	ASSERT_EQ(0, duk::top(context));
 
 	try {
-		duk::push(context, duk::Function{[] (duk::Context *ctx) -> duk::Ret {
-			duk::require<double>(ctx, 0);
+		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
+			duk::requireDouble(ctx, 0);
 
 			return 0;
-		}});
+		});
 
 		ASSERT_NE(0, duk::peval(context));
 	} catch (const std::exception &ex) {
@@ -255,32 +222,11 @@
 	ASSERT_EQ(0, duk::top(context));
 
 	try {
-		duk::push(context, duk::Function{[] (duk::Context *ctx) -> duk::Ret {
-			duk::require<std::string>(ctx, 0);
+		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
+			duk::requireString(ctx, 0);
 
 			return 0;
-		}});
-
-		ASSERT_NE(0, duk::peval(context));
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Require, cstring)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-
-	try {
-		duk::push(context, duk::Function{[] (duk::Context *ctx) -> duk::Ret {
-			duk::require<const char *>(ctx, 0);
-
-			return 0;
-		}});
+		});
 
 		ASSERT_NE(0, duk::peval(context));
 	} catch (const std::exception &ex) {
@@ -297,11 +243,11 @@
 	ASSERT_EQ(0, duk::top(context));
 
 	try {
-		duk::push(context, duk::Function{[] (duk::Context *ctx) -> duk::Ret {
-			duk::require<void *>(ctx, 0);
+		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
+			duk::requirePointer(ctx, 0);
 
 			return 0;
-		}});
+		});
 
 		ASSERT_NE(0, duk::peval(context));
 	} catch (const std::exception &ex) {
@@ -321,8 +267,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, true);
-	ASSERT_TRUE(duk::is<bool>(context, -1));
+	duk::pushBool(context, true);
+	ASSERT_TRUE(duk::isBool(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -331,8 +277,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, 123);
-	ASSERT_TRUE(duk::is<int>(context, -1));
+	duk::pushInt(context, 123);
+	ASSERT_TRUE(duk::isNumber(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -341,8 +287,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, 123U);
-	ASSERT_TRUE(duk::is<unsigned>(context, -1));
+	duk::pushUnsigned(context, 123U);
+	ASSERT_TRUE(duk::isNumber(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -351,8 +297,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, 50.5);
-	ASSERT_TRUE(duk::is<double>(context, -1));
+	duk::pushDouble(context, 50.5);
+	ASSERT_TRUE(duk::isNumber(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -361,18 +307,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, std::string("hello"));
-	ASSERT_TRUE(duk::is<std::string>(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Is, cstring)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, "hello");
-	ASSERT_TRUE(duk::is<const char *>(context, -1));
+	duk::pushString(context, "hello");
+	ASSERT_TRUE(duk::isString(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -381,8 +317,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, duk::Undefined{});
-	ASSERT_TRUE(duk::is<duk::Undefined>(context, -1));
+	duk::pushUndefined(context);
+	ASSERT_TRUE(duk::isUndefined(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -391,8 +327,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, duk::Null{});
-	ASSERT_TRUE(duk::is<duk::Null>(context, -1));
+	duk::pushNull(context);
+	ASSERT_TRUE(duk::isNull(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -401,8 +337,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, duk::Object{});
-	ASSERT_TRUE(duk::is<duk::Object>(context, -1));
+	duk::pushObject(context);
+	ASSERT_TRUE(duk::isObject(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -411,19 +347,18 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, duk::Array{});
-	ASSERT_TRUE(duk::is<duk::Array>(context, -1));
+	duk::pushArray(context);
+	ASSERT_TRUE(duk::isArray(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
 TEST(Is, pointer)
 {
 	duk::UniqueContext context;
-	int value = 1;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push<void *>(context, &value);
-	ASSERT_TRUE(duk::is<void *>(context, -1));
+	duk::pushPointer(context, nullptr);
+	ASSERT_TRUE(duk::isPointer(context, -1));
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -437,8 +372,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	ASSERT_TRUE(duk::optional<bool>(context, 0, true));
-	ASSERT_FALSE(duk::optional<bool>(context, 0, false));
+	ASSERT_TRUE(duk::optionalBool(context, 0, true));
+	ASSERT_FALSE(duk::optionalBool(context, 0, false));
 	ASSERT_EQ(0, duk::top(context));
 }
 
@@ -447,8 +382,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	ASSERT_EQ(123, duk::optional<int>(context, 0, 123));
-	ASSERT_EQ(456, duk::optional<int>(context, 0, 456));
+	ASSERT_EQ(123, duk::optionalInt(context, 0, 123));
+	ASSERT_EQ(456, duk::optionalInt(context, 0, 456));
 	ASSERT_EQ(0, duk::top(context));
 }
 
@@ -457,8 +392,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	ASSERT_EQ(123U, duk::optional<unsigned>(context, 0, 123U));
-	ASSERT_EQ(456U, duk::optional<unsigned>(context, 0, 456U));
+	ASSERT_EQ(123U, duk::optionalUnsigned(context, 0, 123U));
+	ASSERT_EQ(456U, duk::optionalUnsigned(context, 0, 456U));
 	ASSERT_EQ(0, duk::top(context));
 }
 
@@ -467,8 +402,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	ASSERT_EQ(10.0, duk::optional<double>(context, 0, 10.0));
-	ASSERT_EQ(20.0, duk::optional<double>(context, 0, 20.0));
+	ASSERT_EQ(10.0, duk::optionalDouble(context, 0, 10.0));
+	ASSERT_EQ(20.0, duk::optionalDouble(context, 0, 20.0));
 	ASSERT_EQ(0, duk::top(context));
 }
 
@@ -477,8 +412,8 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	ASSERT_EQ("no", duk::optional<std::string>(context, 0, "no"));
-	ASSERT_EQ("yes", duk::optional<std::string>(context, 0, "yes"));
+	ASSERT_EQ("no", duk::optionalString(context, 0, "no"));
+	ASSERT_EQ("yes", duk::optionalString(context, 0, "yes"));
 	ASSERT_EQ(0, duk::top(context));
 }
 
@@ -487,7 +422,7 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	ASSERT_EQ(nullptr, duk::optional<void *>(context, 0, nullptr));
+	ASSERT_EQ(nullptr, duk::optionalPointer(context, 0, nullptr));
 	ASSERT_EQ(0, duk::top(context));
 }
 
@@ -496,29 +431,12 @@
  * ------------------------------------------------------------------
  */
 
-TEST(Basics, global)
-{
-	duk::UniqueContext context;
-
-	// boolean.
-	ASSERT_EQ(0, duk::top(context));
-	duk::putGlobal(context, "valueBoolean", true);
-	ASSERT_TRUE(duk::getGlobal<bool>(context, "valueBoolean"));
-	ASSERT_EQ(0, duk::top(context));
-
-	// integer.
-	ASSERT_EQ(0, duk::top(context));
-	duk::putGlobal(context, "valueInteger", 123);
-	ASSERT_EQ(123, duk::getGlobal<int>(context, "valueInteger"));
-	ASSERT_EQ(0, duk::top(context));
-}
-
 TEST(Basics, top)
 {
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, true);
+	duk::pushBool(context, true);
 	ASSERT_EQ(1, duk::top(context));
 }
 
@@ -527,7 +445,7 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, true);
+	duk::pushBool(context, true);
 	duk::pop(context);
 	ASSERT_EQ(0, duk::top(context));
 }
@@ -537,22 +455,13 @@
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, true);
-	duk::push(context, true);
+	duk::pushBool(context, true);
+	duk::pushBool(context, true);
 	duk::pop(context, 2);
 	ASSERT_EQ(0, duk::top(context));
 }
 
-TEST(Basics, putProperty)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, duk::Object{});
-	duk::putProperty(context, -1, "x", 123);
-	ASSERT_EQ(123, duk::getProperty<int>(context, -1, "x"));
-	ASSERT_EQ(1, duk::top(context));
-}
+#if 0
 
 TEST(Basics, enumerate)
 {
@@ -575,21 +484,29 @@
 	ASSERT_EQ(1, duk::top(context));
 }
 
+#endif
+
 TEST(Basics, call)
 {
 	duk::UniqueContext context;
 
 	ASSERT_EQ(0, duk::top(context));
-	duk::push(context, duk::Function{[] (duk::Context *ctx) -> duk::Ret {
-		duk::putGlobal(ctx, "x", 123);
+	duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
+		duk::pushInt(ctx, 123);
+		duk::putGlobal(ctx, "x");
 
 		return 0;
-	}});
+	});
 	duk::call(context);
+
 	ASSERT_EQ(1, duk::top(context));
-	ASSERT_EQ(123, duk::getGlobal<int>(context, "x"));
+
+	duk::getGlobal(context, "x");
+	ASSERT_EQ(123, duk::getInt(context, -1));
 }
 
+#if 0
+
 /*
  * Eval.
  * ------------------------------------------------------------------
@@ -881,6 +798,8 @@
 	ASSERT_TRUE(duk::getGlobal<bool>(context, "correct"));
 }
 
+#endif
+
 int main(int argc, char **argv)
 {
 	testing::InitGoogleTest(&argc, argv);