text: #ifndef __LUA_RAPIDJSON_TOLUAHANDLER_HPP__
  #define __LUA_RAPIDJSON_TOLUAHANDLER_HPP__
  
  #include <vector>
  #include <lua.hpp>
  #include <rapidjson/rapidjson.h>
  #include <rapidjson/document.h>
  #include <rapidjson/reader.h>
  #include <rapidjson/error/en.h>
  
  #include "luax.hpp"
  #include "StringStream.hpp"
  
  namespace values {
  	typedef rapidjson::Document::AllocatorType Allocator;
  
  	int push_null(lua_State* L);
  
  	inline bool isnull(lua_State* L, int idx)
  	{
          idx = luax::absindex(L, idx);
  		push_null(L);
  		bool is = lua_rawequal(L, -1, idx) != 0;
  		lua_pop(L, 1); // []
  
  		return is;
  	}
  
  	inline bool hasJsonType(lua_State* L, int idx, bool& isarray)
  	{
  		bool has = false;
  		if (lua_getmetatable(L, idx)) {
  			// [metatable]
  			lua_getfield(L, -1, "__jsontype"); // [metatable, metatable.__jsontype]
  			if (lua_isstring(L, -1))
  			{
  				size_t len;
  				const char* s = lua_tolstring(L, -1, &len);
  				isarray = strncmp(s, "array", 6) == 0;
  				has = true;
  			}
  			lua_pop(L, 2); // []
  		}
  
  		return has;
  	}
  
  	inline bool isarray(lua_State* L, int idx, bool empty_table_as_array = false) {
  		bool arr = false;
  		if (hasJsonType(L, idx, arr)) // any table with a meta field __jsontype set to 'array' are arrays
  			return arr;
  
          idx = luax::absindex(L, idx);
  		lua_pushnil(L);
  		if (lua_next(L, idx) != 0) {
  			lua_pop(L, 2);
  
  			return luax::rawlen(L, idx) > 0; // any non empty table has length > 0 are treat as array.
  		}
  
  		// Now it comes empty table
  		return empty_table_as_array;
  	}
  
  
  
  	/**
  	 * Handle json SAX events and create Lua object.
  	 */
  	struct ToLuaHandler {
  		explicit ToLuaHandler(lua_State* aL) : L(aL) { stack_.reserve(32); }
  
  		bool Null() {
  			push_null(L);
  			context_.submit(L);
  			return true;
  		}
  		bool Bool(bool b) {
  			lua_pushboolean(L, b);
  			context_.submit(L);
  			return true;
  		}
  		bool Int(int i) {
  			lua_pushinteger(L, i);
  			context_.submit(L);
  			return true;
  		}
  		bool Uint(unsigned u) {
  			if (sizeof(lua_Integer) > sizeof(unsigned int) || u <= static_cast<unsigned>(std::numeric_limits<lua_Integer>::max()))
  				lua_pushinteger(L, static_cast<lua_Integer>(u));
  			else
  				lua_pushnumber(L, static_cast<lua_Number>(u));
  			context_.submit(L);
  			return true;
  		}
  		bool Int64(int64_t i) {
  			if (sizeof(lua_Integer) >= sizeof(int64_t) || (i <= std::numeric_limits<lua_Integer>::max() && i >= std::numeric_limits<lua_Integer>::min()))
  				lua_pushinteger(L, static_cast<lua_Integer>(i));
  			else
  				lua_pushnumber(L, static_cast<lua_Number>(i));
  			context_.submit(L);
  			return true;
  		}
  		bool Uint64(uint64_t u) {
  			if (sizeof(lua_Integer) > sizeof(uint64_t) || u <= static_cast<uint64_t>(std::numeric_limits<lua_Integer>::max()))
  				lua_pushinteger(L, static_cast<lua_Integer>(u));
  			else
  				lua_pushnumber(L, static_cast<lua_Number>(u));
  			context_.submit(L);
  			return true;
  		}
  		bool Double(double d) {
  			lua_pushnumber(L, static_cast<lua_Number>(d));
  			context_.submit(L);
  			return true;
  		}
  		bool RawNumber(const char* str, rapidjson::SizeType length, bool copy) {
  			lua_getglobal(L, "tonumber");
  			lua_pushlstring(L, str, length);
  			lua_call(L, 1, 1);
  			context_.submit(L);
  			return true;
  		}
  		bool String(const char* str, rapidjson::SizeType length, bool copy) {
  			lua_pushlstring(L, str, length);
  			context_.submit(L);
  			return true;
  		}
  		bool StartObject() {
  			if (!lua_checkstack(L, 2)) // make sure there's room on the stack
  				return false;
  
  			lua_createtable(L, 0, 0);							// [..., object]
  
  			// mark as object.
  			luaL_getmetatable(L, "json.object");	//[..., object, json.object]
  			lua_setmetatable(L, -2);							// [..., object]
  
  			stack_.push_back(context_);
  			context_ = Ctx::Object();
  			return true;
  		}
  		bool Key(const char* str, rapidjson::SizeType length, bool copy) const {
  			lua_pushlstring(L, str, length);
  			return true;
  		}
  		bool EndObject(rapidjson::SizeType memberCount) {
  			context_ = stack_.back();
  			stack_.pop_back();
  			context_.submit(L);
  			return true;
  		}
  		bool StartArray() {
  			if (!lua_checkstack(L, 2)) // make sure there's room on the stack
  				return false;
  
  			lua_createtable(L, 0, 0);
  
  			// mark as array.
  			luaL_getmetatable(L, "json.array");  //[..., array, json.array]
  			lua_setmetatable(L, -2); // [..., array]
  
  			stack_.push_back(context_);
  			context_ = Ctx::Array();
  			return true;
  		}
  		bool EndArray(rapidjson::SizeType elementCount) {
  			assert(elementCount == context_.index_);
  			context_ = stack_.back();
  			stack_.pop_back();
  			context_.submit(L);
  			return true;
  		}
  	private:
  
  
  		struct Ctx {
  			Ctx() : index_(0), fn_(&topFn) {}
  			Ctx(const Ctx& rhs) : index_(rhs.index_), fn_(rhs.fn_)
  			{
  			}
  			const Ctx& operator=(const Ctx& rhs) {
  				if (this != &rhs) {
  					index_ = rhs.index_;
  					fn_ = rhs.fn_;
  				}
  				return *this;
  			}
  			static Ctx Object() {
  				return Ctx(&objectFn);
  			}
  			static Ctx Array()
  			{
  				return Ctx(&arrayFn);
  			}
  			void submit(lua_State* L)
  			{
  				fn_(L, this);
  			}
  
  			int index_;
  			void(*fn_)(lua_State* L, Ctx* ctx);
  		private:
  			explicit Ctx(void(*f)(lua_State* L, Ctx* ctx)) : index_(0), fn_(f) {}
  
  
  			static void objectFn(lua_State* L, Ctx* ctx)
  			{
  				lua_rawset(L, -3);
  			}
  
  			static void arrayFn(lua_State* L, Ctx* ctx)
  			{
  				lua_rawseti(L, -2, ++ctx->index_);
  			}
  			static void topFn(lua_State* L, Ctx* ctx)
  			{
  			}
  		};
  
  		lua_State* L;
  		std::vector < Ctx > stack_;
  		Ctx context_;
  	};
  
  
  	// for xLua compile 
  	// namespace details {
  	// 	rapidjson::Value toValue(lua_State* L, int idx, int depth, Allocator& allocator);
  	// }
  
  	// inline rapidjson::Value toValue(lua_State* L, int idx, Allocator& allocator) {
  	// 	return details::toValue(L, idx, 0, allocator);
  	// }
  
  	// inline void toDocument(lua_State* L, int idx, rapidjson::Document* doc) {
  	// 	details::toValue(L, idx, 0, doc->GetAllocator()).Swap(*doc);
  	// }
  
  	inline void pushValue(lua_State *L, const rapidjson::Value& v) {
  		ToLuaHandler handler(L);
  		v.Accept(handler);
  	}
  
  
      template<typename Stream>
      inline int pushDecoded(lua_State* L, Stream& s) {
          int top = lua_gettop(L);
          values::ToLuaHandler handler(L);
          rapidjson::Reader reader;
          rapidjson::ParseResult r = reader.Parse(s, handler);
  
          if (!r) {
              lua_settop(L, top);
              lua_pushnil(L);
              lua_pushfstring(L, "%s (%d)", rapidjson::GetParseError_En(r.Code()), r.Offset());
              return 2;
          }
  
          return 1;
      }
  
      inline int pushDecoded(lua_State* L, const char* ptr, size_t len) {
          rapidjson::extend::StringStream s(ptr, len);
          return pushDecoded(L, s);
  	}
  }
  
  #endif // __LUA_RAPIDJSON_TOLUAHANDLER_HPP__
  