#define NODE_ARGUMENTS const v8::FunctionCallbackInfo<v8::Value>&
#define NODE_ARGUMENTS_POINTER const v8::FunctionCallbackInfo<v8::Value>*
#define NODE_METHOD(name) static void name(NODE_ARGUMENTS info)
#define NODE_GETTER(name) static void name(v8::Local<v8::String> _, const v8::PropertyCallbackInfo<v8::Value>& info)
#define INIT(name) static v8::Local<v8::Function> name(v8::Isolate* isolate, v8::Local<v8::External> data)

#define EasyIsolate v8::Isolate* isolate = v8::Isolate::GetCurrent()
#define OnlyIsolate info.GetIsolate()
#define OnlyContext isolate->GetCurrentContext()
#define OnlyAddon static_cast<Addon*>(v8::Local<v8::External>::Cast(info.Data())->Value())
#define UseIsolate v8::Isolate* isolate = OnlyIsolate
#define UseContext v8::Local<v8::Context> ctx = OnlyContext
#define UseAddon Addon* addon = OnlyAddon
#define Unwrap node::ObjectWrap::Unwrap

inline v8::Local<v8::String> StringFromUtf8(v8::Isolate* isolate, const char* data, int length) {
	return v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal, length).ToLocalChecked();
}
inline v8::Local<v8::String> InternalizedFromUtf8(v8::Isolate* isolate, const char* data, int length) {
	return v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kInternalized, length).ToLocalChecked();
}
inline v8::Local<v8::Value> InternalizedFromUtf8OrNull(v8::Isolate* isolate, const char* data, int length) {
	if (data == NULL) return v8::Null(isolate);
	return InternalizedFromUtf8(isolate, data, length);
}
inline v8::Local<v8::String> InternalizedFromLatin1(v8::Isolate* isolate, const char* str) {
	return v8::String::NewFromOneByte(isolate, reinterpret_cast<const uint8_t*>(str), v8::NewStringType::kInternalized).ToLocalChecked();
}

#hdr
template <class T> using CopyablePersistent = v8::Persistent<T, v8::CopyablePersistentTraits<T>>;
#end
inline void SetFrozen(v8::Isolate* isolate, v8::Local<v8::Context> ctx, v8::Local<v8::Object> obj, CopyablePersistent<v8::String>& key, v8::Local<v8::Value> value) {
	obj->DefineOwnProperty(ctx, CS::Get(isolate, key), value, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly)).FromJust();
}

void ThrowError(const char* message) { EasyIsolate; isolate->ThrowException(v8::Exception::Error(StringFromUtf8(isolate, message, -1))); }
void ThrowTypeError(const char* message) { EasyIsolate; isolate->ThrowException(v8::Exception::TypeError(StringFromUtf8(isolate, message, -1))); }
void ThrowRangeError(const char* message) { EasyIsolate; isolate->ThrowException(v8::Exception::RangeError(StringFromUtf8(isolate, message, -1))); }

#define REQUIRE_ARGUMENT_ANY(at, var)                                          \
	if (info.Length() <= (at()))                                               \
		return ThrowTypeError("Expected a "#at" argument");                    \
	var = info[at()]

#define _REQUIRE_ARGUMENT(at, var, Type, message, ...)                         \
	if (info.Length() <= (at()) || !info[at()]->Is##Type())                    \
		return ThrowTypeError("Expected "#at" argument to be "#message);       \
	var = v8::Local<v8::Type>::Cast(info[at()])__VA_ARGS__

#define REQUIRE_ARGUMENT_INT32(at, var)                                        \
	_REQUIRE_ARGUMENT(at, var, Int32, a 32-bit signed integer, ->Value())
#define REQUIRE_ARGUMENT_BOOLEAN(at, var)                                      \
	_REQUIRE_ARGUMENT(at, var, Boolean, a boolean, ->Value())
#define REQUIRE_ARGUMENT_STRING(at, var)                                       \
	_REQUIRE_ARGUMENT(at, var, String, a string)
#define REQUIRE_ARGUMENT_OBJECT(at, var)                                       \
	_REQUIRE_ARGUMENT(at, var, Object, an object)
#define REQUIRE_ARGUMENT_FUNCTION(at, var)                                     \
	_REQUIRE_ARGUMENT(at, var, Function, a function)

#define REQUIRE_DATABASE_OPEN(db)                                              \
	if (!db->open)                                                             \
		return ThrowTypeError("The database connection is not open")
#define REQUIRE_DATABASE_NOT_BUSY(db)                                          \
	if (db->busy)                                                              \
		return ThrowTypeError("This database connection is busy executing a query")
#define REQUIRE_DATABASE_NO_ITERATORS(db)                                      \
	if (db->iterators)                                                         \
		return ThrowTypeError("This database connection is busy executing a query")
#define REQUIRE_DATABASE_NO_ITERATORS_UNLESS_UNSAFE(db)                        \
	if (!db->unsafe_mode) {                                                    \
		REQUIRE_DATABASE_NO_ITERATORS(db);                                     \
	} ((void)0)
#define REQUIRE_STATEMENT_NOT_LOCKED(stmt)                                     \
	if (stmt->locked)                                                          \
		return ThrowTypeError("This statement is busy executing a query")

#define first() 0
#define second() 1
#define third() 2
#define fourth() 3
#define fifth() 4
#define sixth() 5
#define seventh() 6
#define eighth() 7
#define ninth() 8
#define tenth() 9

// Returns a std:string of the concatenation of 3 well-formed C-strings.
std::string CONCAT(const char* a, const char* b, const char* c) {
	std::string result(a);
	result += b;
	result += c;
	return result;
}

// Returns a copy of a well-formed C-string.
const char* COPY(const char* source) {
	size_t bytes = strlen(source) + 1;
	char* dest = new char[bytes];
	memcpy(dest, source, bytes);
	return dest;
}

// Determines whether to skip the given character at the start of an SQL string.
inline bool IS_SKIPPED(char c) {
	return c == ' ' || c == ';' || (c >= '\t' && c <= '\r');
}

// Allocates an empty array, without calling constructors/initializers.
template<class T> inline T* ALLOC_ARRAY(size_t count) {
	return static_cast<T*>(::operator new[](count * sizeof(T)));
}

// Deallocates an array, without calling destructors.
template<class T> inline void FREE_ARRAY(T* array_pointer) {
	::operator delete[](array_pointer);
}

v8::Local<v8::FunctionTemplate> NewConstructorTemplate(
	v8::Isolate* isolate,
	v8::Local<v8::External> data,
	v8::FunctionCallback func,
	const char* name
) {
	v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate, func, data);
	t->InstanceTemplate()->SetInternalFieldCount(1);
	t->SetClassName(InternalizedFromLatin1(isolate, name));
	return t;
}
void SetPrototypeMethod(
	v8::Isolate* isolate,
	v8::Local<v8::External> data,
	v8::Local<v8::FunctionTemplate> recv,
	const char* name,
	v8::FunctionCallback func
) {
	v8::HandleScope scope(isolate);
	recv->PrototypeTemplate()->Set(
		InternalizedFromLatin1(isolate, name),
		v8::FunctionTemplate::New(isolate, func, data, v8::Signature::New(isolate, recv))
	);
}
void SetPrototypeSymbolMethod(
	v8::Isolate* isolate,
	v8::Local<v8::External> data,
	v8::Local<v8::FunctionTemplate> recv,
	v8::Local<v8::Symbol> symbol,
	v8::FunctionCallback func
) {
	v8::HandleScope scope(isolate);
	recv->PrototypeTemplate()->Set(
		symbol,
		v8::FunctionTemplate::New(isolate, func, data, v8::Signature::New(isolate, recv))
	);
}
void SetPrototypeGetter(
	v8::Isolate* isolate,
	v8::Local<v8::External> data,
	v8::Local<v8::FunctionTemplate> recv,
	const char* name,
	v8::AccessorGetterCallback func
) {
	v8::HandleScope scope(isolate);
	recv->InstanceTemplate()->SetAccessor(
		InternalizedFromLatin1(isolate, name),
		func,
		0,
		data,
		v8::AccessControl::DEFAULT,
		v8::PropertyAttribute::None,
		v8::AccessorSignature::New(isolate, recv)
	);
}
