Initial commit.

This commit is contained in:
Cheng Zhao
2014-04-15 11:04:36 +08:00
commit ff65b7dae1
20 changed files with 1887 additions and 0 deletions

48
native_mate/arguments.cc Normal file
View File

@@ -0,0 +1,48 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#include "native_mate/arguments.h"
#include "base/strings/stringprintf.h"
#include "native_mate/converter.h"
namespace mate {
Arguments::Arguments()
: isolate_(NULL),
info_(NULL),
next_(0),
insufficient_arguments_(false) {
}
Arguments::Arguments(const MATE_METHOD_ARGS_TYPE& info)
: isolate_(info.GetIsolate()),
info_(&info),
next_(0),
insufficient_arguments_(false) {
}
Arguments::~Arguments() {
}
v8::Handle<v8::Value> Arguments::PeekNext() const {
if (next_ >= info_->Length())
return v8::Handle<v8::Value>();
return (*info_)[next_];
}
void Arguments::ThrowError() const {
if (insufficient_arguments_)
return ThrowTypeError("Insufficient number of arguments.");
ThrowTypeError(base::StringPrintf(
"Error processing argument %d.", next_ - 1));
}
void Arguments::ThrowTypeError(const std::string& message) const {
MATE_THROW_EXCEPTION(isolate_, v8::Exception::TypeError(
StringToV8(isolate_, message)));
}
} // namespace mate

82
native_mate/arguments.h Normal file
View File

@@ -0,0 +1,82 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#ifndef NATIVE_MATE_ARGUMENTS_H_
#define NATIVE_MATE_ARGUMENTS_H_
#include "base/basictypes.h"
#include "native_mate/compat.h"
#include "native_mate/converter.h"
namespace mate {
// Arguments is a wrapper around v8::FunctionCallbackInfo that integrates
// with Converter to make it easier to marshall arguments and return values
// between V8 and C++.
class Arguments {
public:
Arguments();
explicit Arguments(const MATE_METHOD_ARGS_TYPE& info);
~Arguments();
template<typename T>
bool GetHolder(T* out) {
return ConvertFromV8(isolate_, info_->Holder(), out);
}
template<typename T>
bool GetData(T* out) {
return ConvertFromV8(isolate_, info_->Data(), out);
}
template<typename T>
bool GetNext(T* out) {
if (next_ >= info_->Length()) {
insufficient_arguments_ = true;
return false;
}
v8::Handle<v8::Value> val = (*info_)[next_++];
return ConvertFromV8(isolate_, val, out);
}
template<typename T>
bool GetRemaining(std::vector<T>* out) {
if (next_ >= info_->Length()) {
insufficient_arguments_ = true;
return false;
}
int remaining = info_->Length() - next_;
out->resize(remaining);
for (int i = 0; i < remaining; ++i) {
v8::Handle<v8::Value> val = (*info_)[next_++];
if (!ConvertFromV8(isolate_, val, &out->at(i)))
return false;
}
return true;
}
#if NODE_VERSION_AT_LEAST(0, 11, 0)
template<typename T>
void Return(T val) {
info_->GetReturnValue().Set(ConvertToV8(isolate_, val));
}
#endif
v8::Handle<v8::Value> PeekNext() const;
void ThrowError() const;
void ThrowTypeError(const std::string& message) const;
v8::Isolate* isolate() const { return isolate_; }
private:
v8::Isolate* isolate_;
const MATE_METHOD_ARGS_TYPE* info_;
int next_;
bool insufficient_arguments_;
};
} // namespace mate
#endif // NATIVE_MATE_ARGUMENTS_H_

100
native_mate/compat.h Normal file
View File

@@ -0,0 +1,100 @@
// Copyright 2014 Cheng Zhao. All rights reserved.
// Use of this source code is governed by MIT license that can be found in the
// LICENSE file.
#ifndef NATIVE_MATE_COMPAT_H_
#define NATIVE_MATE_COMPAT_H_
#include "node_version.h"
#if (NODE_MODULE_VERSION > 0x000B) // Node 0.11+
#define MATE_HANDLE_SCOPE(isolate) v8::HandleScope handle_scope(isolate)
#define MATE_METHOD_ARGS_TYPE v8::FunctionCallbackInfo<v8::Value>
#define MATE_METHOD_RETURN_TYPE void
#define MATE_METHOD_RETURN_VALUE(value) return info.GetReturnValue().Set(value)
#define MATE_METHOD_RETURN_UNDEFINED() return
#define MATE_METHOD_RETURN_NULL() return info.GetReturnValue().SetNull()
#define MATE_METHOD_RETURN(value) args.Return(value)
#define MATE_STRING_NEW_FROM_UTF8(isolate, data, length) \
v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString, length)
#define MATE_STRING_NEW_SYMBOL(isolate, data, length) \
v8::String::NewFromUtf8(isolate, data, v8::String::kInternalizedString, length)
#define MATE_SET_INTERNAL_FIELD_POINTER(object, index, value) \
object->SetAlignedPointerInInternalField(index, value)
#define MATE_GET_INTERNAL_FIELD_POINTER(object, index) \
object->GetAlignedPointerFromInternalField(index)
#define MATE_PERSISTENT_INIT(isolate, handle, value) \
handle(isolate, value)
#define MATE_PERSISTENT_ASSIGN(type, isolate, handle, value) \
handle.Reset(isolate, value)
#define MATE_PERSISTENT_RESET(handle) \
handle.Reset()
#define MATE_PERSISTENT_TO_LOCAL(type, isolate, handle) \
v8::Local<type>::New(isolate, handle)
#define MATE_PERSISTENT_SET_WEAK(handle, parameter, callback) \
handle.SetWeak(parameter, callback)
#define MATE_WEAK_CALLBACK(name, v8_type, c_type) \
void name(const v8::WeakCallbackData<v8_type, c_type>& data)
#define MATE_WEAK_CALLBACK_INIT(c_type) \
c_type* self = data.GetParameter()
#else // Node 0.8 and 0.10
#define MATE_HANDLE_SCOPE(isolate) v8::HandleScope handle_scope
#define MATE_METHOD_ARGS_TYPE v8::Arguments
#define MATE_METHOD_RETURN_TYPE v8::Handle<v8::Value>
#define MATE_METHOD_RETURN_VALUE(value) return value
#define MATE_METHOD_RETURN_UNDEFINED() return v8::Undefined()
#define MATE_METHOD_RETURN_NULL() return v8::Null()
#define MATE_METHOD_RETURN(value) \
MATE_METHOD_RETURN_VALUE(ConvertToV8(args.isolate(), value))
#define MATE_STRING_NEW_FROM_UTF8(isolate, data, length) \
v8::String::New(data, length)
#define MATE_STRING_NEW_SYMBOL(isolate, data, length) \
v8::String::NewSymbol(data, length)
#define MATE_SET_INTERNAL_FIELD_POINTER(object, index, value) \
object->SetPointerInInternalField(index, value)
#define MATE_GET_INTERNAL_FIELD_POINTER(object, index) \
object->GetPointerFromInternalField(index)
#define MATE_PERSISTENT_INIT(isolate, handle, value) \
handle(value)
#define MATE_PERSISTENT_ASSIGN(type, isolate, handle, value) \
handle = v8::Persistent<type>::New(value)
#define MATE_PERSISTENT_RESET(handle) \
handle.Dispose(); \
handle.Clear()
#define MATE_PERSISTENT_TO_LOCAL(type, isolate, handle) \
v8::Local<type>::New(handle)
#define MATE_PERSISTENT_SET_WEAK(handle, parameter, callback) \
handle.MakeWeak(parameter, callback)
#define MATE_WEAK_CALLBACK(name, v8_type, c_type) \
void name(v8::Persistent<v8::Value> object, void* parameter)
#define MATE_WEAK_CALLBACK_INIT(c_type) \
c_type* self = static_cast<c_type*>(parameter)
#endif // (NODE_MODULE_VERSION > 0x000B)
// Generally we should not provide utility macros, but this just makes things
// much more comfortable so we keep it.
#define MATE_METHOD(name) \
MATE_METHOD_RETURN_TYPE name(const MATE_METHOD_ARGS_TYPE& info)
// In lastest V8 ThrowException would need to pass isolate, be prepared for it.
#define MATE_THROW_EXCEPTION(isolate, value) \
v8::ThrowException(value)
#endif // NATIVE_MATE_COMPAT_H_

190
native_mate/converter.cc Normal file
View File

@@ -0,0 +1,190 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#include "native_mate/converter.h"
#include "native_mate/compat.h"
#include "v8/include/v8.h"
using v8::Boolean;
using v8::External;
using v8::Function;
using v8::Handle;
using v8::Integer;
using v8::Isolate;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
namespace mate {
Handle<Value> Converter<bool>::ToV8(Isolate* isolate, bool val) {
return Boolean::New(val);
}
bool Converter<bool>::FromV8(Isolate* isolate, Handle<Value> val, bool* out) {
*out = val->BooleanValue();
return true;
}
Handle<Value> Converter<int32_t>::ToV8(Isolate* isolate, int32_t val) {
return Integer::New(val);
}
bool Converter<int32_t>::FromV8(Isolate* isolate, Handle<Value> val,
int32_t* out) {
if (!val->IsInt32())
return false;
*out = val->Int32Value();
return true;
}
Handle<Value> Converter<uint32_t>::ToV8(Isolate* isolate, uint32_t val) {
return Integer::NewFromUnsigned(val);
}
bool Converter<uint32_t>::FromV8(Isolate* isolate, Handle<Value> val,
uint32_t* out) {
if (!val->IsUint32())
return false;
*out = val->Uint32Value();
return true;
}
Handle<Value> Converter<int64_t>::ToV8(Isolate* isolate, int64_t val) {
return Number::New(static_cast<double>(val));
}
bool Converter<int64_t>::FromV8(Isolate* isolate, Handle<Value> val,
int64_t* out) {
if (!val->IsNumber())
return false;
// Even though IntegerValue returns int64_t, JavaScript cannot represent
// the full precision of int64_t, which means some rounding might occur.
*out = val->IntegerValue();
return true;
}
Handle<Value> Converter<uint64_t>::ToV8(Isolate* isolate, uint64_t val) {
return Number::New(static_cast<double>(val));
}
bool Converter<uint64_t>::FromV8(Isolate* isolate, Handle<Value> val,
uint64_t* out) {
if (!val->IsNumber())
return false;
*out = static_cast<uint64_t>(val->IntegerValue());
return true;
}
Handle<Value> Converter<float>::ToV8(Isolate* isolate, float val) {
return Number::New(val);
}
bool Converter<float>::FromV8(Isolate* isolate, Handle<Value> val,
float* out) {
if (!val->IsNumber())
return false;
*out = static_cast<float>(val->NumberValue());
return true;
}
Handle<Value> Converter<double>::ToV8(Isolate* isolate, double val) {
return Number::New(val);
}
bool Converter<double>::FromV8(Isolate* isolate, Handle<Value> val,
double* out) {
if (!val->IsNumber())
return false;
*out = val->NumberValue();
return true;
}
Handle<Value> Converter<base::StringPiece>::ToV8(
Isolate* isolate, const base::StringPiece& val) {
return MATE_STRING_NEW_FROM_UTF8(isolate, val.data(),
static_cast<uint32_t>(val.length()));
}
Handle<Value> Converter<std::string>::ToV8(Isolate* isolate,
const std::string& val) {
return Converter<base::StringPiece>::ToV8(isolate, val);
}
bool Converter<std::string>::FromV8(Isolate* isolate, Handle<Value> val,
std::string* out) {
if (!val->IsString())
return false;
Handle<String> str = Handle<String>::Cast(val);
int length = str->Utf8Length();
out->resize(length);
str->WriteUtf8(&(*out)[0], length, NULL, String::NO_NULL_TERMINATION);
return true;
}
bool Converter<Handle<Function> >::FromV8(Isolate* isolate, Handle<Value> val,
Handle<Function>* out) {
if (!val->IsFunction())
return false;
*out = Handle<Function>::Cast(val);
return true;
}
Handle<Value> Converter<Handle<Object> >::ToV8(Isolate* isolate,
Handle<Object> val) {
return val;
}
bool Converter<Handle<Object> >::FromV8(Isolate* isolate, Handle<Value> val,
Handle<Object>* out) {
if (!val->IsObject())
return false;
*out = Handle<Object>::Cast(val);
return true;
}
Handle<Value> Converter<Handle<External> >::ToV8(Isolate* isolate,
Handle<External> val) {
return val;
}
bool Converter<Handle<External> >::FromV8(Isolate* isolate,
v8::Handle<Value> val,
Handle<External>* out) {
if (!val->IsExternal())
return false;
*out = Handle<External>::Cast(val);
return true;
}
Handle<Value> Converter<Handle<Value> >::ToV8(Isolate* isolate,
Handle<Value> val) {
return val;
}
bool Converter<Handle<Value> >::FromV8(Isolate* isolate, Handle<Value> val,
Handle<Value>* out) {
*out = val;
return true;
}
v8::Handle<v8::String> StringToSymbol(v8::Isolate* isolate,
const base::StringPiece& val) {
return MATE_STRING_NEW_SYMBOL(isolate,
val.data(),
static_cast<uint32_t>(val.length()));
}
std::string V8ToString(v8::Handle<v8::Value> value) {
if (value.IsEmpty())
return std::string();
std::string result;
if (!ConvertFromV8(NULL, value, &result))
return std::string();
return result;
}
} // namespace mate

193
native_mate/converter.h Normal file
View File

@@ -0,0 +1,193 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#ifndef NATIVE_MATE_CONVERTER_H_
#define NATIVE_MATE_CONVERTER_H_
#include <string>
#include <vector>
#include "base/strings/string_piece.h"
#include "v8/include/v8.h"
namespace mate {
template<typename T, typename Enable = void>
struct Converter {};
template<>
struct Converter<bool> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
bool val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
bool* out);
};
template<>
struct Converter<int32_t> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
int32_t val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
int32_t* out);
};
template<>
struct Converter<uint32_t> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
uint32_t val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
uint32_t* out);
};
template<>
struct Converter<int64_t> {
// Warning: JavaScript cannot represent 64 integers precisely.
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
int64_t val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
int64_t* out);
};
template<>
struct Converter<uint64_t> {
// Warning: JavaScript cannot represent 64 integers precisely.
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
uint64_t val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
uint64_t* out);
};
template<>
struct Converter<float> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
float val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
float* out);
};
template<>
struct Converter<double> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
double val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
double* out);
};
template<>
struct Converter<base::StringPiece> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
const base::StringPiece& val);
// No conversion out is possible because StringPiece does not contain storage.
};
template<>
struct Converter<std::string> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
const std::string& val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
std::string* out);
};
template<>
struct Converter<v8::Handle<v8::Function> > {
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
v8::Handle<v8::Function>* out);
};
template<>
struct Converter<v8::Handle<v8::Object> > {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
v8::Handle<v8::Object> val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
v8::Handle<v8::Object>* out);
};
template<>
struct Converter<v8::Handle<v8::External> > {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
v8::Handle<v8::External> val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
v8::Handle<v8::External>* out);
};
template<>
struct Converter<v8::Handle<v8::Value> > {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
v8::Handle<v8::Value>* out);
};
template<typename T>
struct Converter<std::vector<T> > {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
const std::vector<T>& val) {
v8::Handle<v8::Array> result(
v8::Array::New(static_cast<int>(val.size())));
for (size_t i = 0; i < val.size(); ++i) {
result->Set(static_cast<int>(i), Converter<T>::ToV8(isolate, val[i]));
}
return result;
}
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
std::vector<T>* out) {
if (!val->IsArray())
return false;
std::vector<T> result;
v8::Handle<v8::Array> array(v8::Handle<v8::Array>::Cast(val));
uint32_t length = array->Length();
for (uint32_t i = 0; i < length; ++i) {
T item;
if (!Converter<T>::FromV8(isolate, array->Get(i), &item))
return false;
result.push_back(item);
}
out->swap(result);
return true;
}
};
// Convenience functions that deduce T.
template<typename T>
v8::Handle<v8::Value> ConvertToV8(v8::Isolate* isolate,
T input) {
return Converter<T>::ToV8(isolate, input);
}
inline v8::Handle<v8::String> StringToV8(
v8::Isolate* isolate,
const base::StringPiece& input) {
return ConvertToV8(isolate, input).As<v8::String>();
}
v8::Handle<v8::String> StringToSymbol(v8::Isolate* isolate,
const base::StringPiece& val);
template<typename T>
bool ConvertFromV8(v8::Isolate* isolate, v8::Handle<v8::Value> input,
T* result) {
return Converter<T>::FromV8(isolate, input, result);
}
std::string V8ToString(v8::Handle<v8::Value> value);
} // namespace mate
#endif // NATIVE_MATE_CONVERTER_H_

42
native_mate/dictionary.cc Normal file
View File

@@ -0,0 +1,42 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#include "native_mate/dictionary.h"
namespace mate {
Dictionary::Dictionary(v8::Isolate* isolate)
: isolate_(isolate) {
}
Dictionary::Dictionary(v8::Isolate* isolate,
v8::Handle<v8::Object> object)
: isolate_(isolate),
object_(object) {
}
Dictionary::~Dictionary() {
}
Dictionary Dictionary::CreateEmpty(v8::Isolate* isolate) {
Dictionary dictionary(isolate);
dictionary.object_ = v8::Object::New();
return dictionary;
}
v8::Handle<v8::Value> Converter<Dictionary>::ToV8(v8::Isolate* isolate,
Dictionary val) {
return val.object_;
}
bool Converter<Dictionary>::FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
Dictionary* out) {
if (!val->IsObject())
return false;
*out = Dictionary(isolate, v8::Handle<v8::Object>::Cast(val));
return true;
}
} // namespace mate

64
native_mate/dictionary.h Normal file
View File

@@ -0,0 +1,64 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#ifndef NATIVE_MATE_DICTIONARY_H_
#define NATIVE_MATE_DICTIONARY_H_
#include "native_mate/converter.h"
namespace mate {
// Dictionary is useful when writing bindings for a function that either
// receives an arbitrary JavaScript object as an argument or returns an
// arbitrary JavaScript object as a result. For example, Dictionary is useful
// when you might use the |dictionary| type in WebIDL:
//
// http://heycam.github.io/webidl/#idl-dictionaries
//
// WARNING: You cannot retain a Dictionary object in the heap. The underlying
// storage for Dictionary is tied to the closest enclosing
// v8::HandleScope. Generally speaking, you should store a Dictionary
// on the stack.
//
class Dictionary {
public:
explicit Dictionary(v8::Isolate* isolate);
Dictionary(v8::Isolate* isolate, v8::Handle<v8::Object> object);
~Dictionary();
static Dictionary CreateEmpty(v8::Isolate* isolate);
template<typename T>
bool Get(const std::string& key, T* out) {
v8::Handle<v8::Value> val = object_->Get(StringToV8(isolate_, key));
return ConvertFromV8(isolate_, val, out);
}
template<typename T>
bool Set(const std::string& key, T val) {
return object_->Set(StringToV8(isolate_, key), ConvertToV8(isolate_, val));
}
v8::Isolate* isolate() const { return isolate_; }
private:
friend struct Converter<Dictionary>;
// TODO(aa): Remove this. Instead, get via FromV8(), Set(), and Get().
v8::Isolate* isolate_;
v8::Handle<v8::Object> object_;
};
template<>
struct Converter<Dictionary> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
Dictionary val);
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
Dictionary* out);
};
} // namespace mate
#endif // NATIVE_MATE_DICTIONARY_H_

View File

@@ -0,0 +1,35 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#include "native_mate/function_template.h"
namespace mate {
namespace internal {
CallbackHolderBase::CallbackHolderBase(v8::Isolate* isolate)
: MATE_PERSISTENT_INIT(isolate, v8_ref_, v8::External::New(isolate)) {
MATE_PERSISTENT_SET_WEAK(v8_ref_, this, &CallbackHolderBase::WeakCallback);
}
CallbackHolderBase::~CallbackHolderBase() {
DCHECK(v8_ref_.IsEmpty());
}
v8::Handle<v8::External> CallbackHolderBase::GetHandle(v8::Isolate* isolate) {
return MATE_PERSISTENT_TO_LOCAL(v8::External, isolate, v8_ref_);
}
// static
MATE_WEAK_CALLBACK(CallbackHolderBase::WeakCallback,
v8::External,
CallbackHolderBase) {
MATE_WEAK_CALLBACK_INIT(CallbackHolderBase);
MATE_PERSISTENT_RESET(self->v8_ref_);
delete self;
}
} // namespace internal
} // namespace mate

View File

@@ -0,0 +1,498 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#ifndef NATIVE_MATE_FUNCTION_TEMPLATE_H_
#define NATIVE_MATE_FUNCTION_TEMPLATE_H_
#include "base/callback.h"
#include "base/logging.h"
#include "native_mate/arguments.h"
#include "native_mate/converter.h"
#include "v8/include/v8.h"
namespace mate {
class PerIsolateData;
enum CreateFunctionTemplateFlags {
HolderIsFirstArgument = 1 << 0,
};
namespace internal {
template<typename T>
struct CallbackParamTraits {
typedef T LocalType;
};
template<typename T>
struct CallbackParamTraits<const T&> {
typedef T LocalType;
};
template<typename T>
struct CallbackParamTraits<const T*> {
typedef T* LocalType;
};
// CallbackHolder and CallbackHolderBase are used to pass a base::Callback from
// CreateFunctionTemplate through v8 (via v8::FunctionTemplate) to
// DispatchToCallback, where it is invoked.
// This simple base class is used so that we can share a single object template
// among every CallbackHolder instance.
class CallbackHolderBase {
public:
v8::Handle<v8::External> GetHandle(v8::Isolate* isolate);
protected:
explicit CallbackHolderBase(v8::Isolate* isolate);
virtual ~CallbackHolderBase();
private:
static MATE_WEAK_CALLBACK(WeakCallback, v8::External, CallbackHolderBase);
v8::Persistent<v8::External> v8_ref_;
DISALLOW_COPY_AND_ASSIGN(CallbackHolderBase);
};
template<typename Sig>
class CallbackHolder : public CallbackHolderBase {
public:
CallbackHolder(v8::Isolate* isolate,
const base::Callback<Sig>& callback,
int flags)
: CallbackHolderBase(isolate), callback(callback), flags(flags) {}
base::Callback<Sig> callback;
int flags;
private:
virtual ~CallbackHolder() {}
DISALLOW_COPY_AND_ASSIGN(CallbackHolder);
};
// This set of templates invokes a base::Callback, converts the return type to a
// JavaScript value, and returns that value to script via the provided
// mate::Arguments object.
//
// In C++, you can declare the function foo(void), but you can't pass a void
// expression to foo. As a result, we must specialize the case of Callbacks that
// have the void return type.
template<typename R, typename P1 = void, typename P2 = void,
typename P3 = void, typename P4 = void, typename P5 = void,
typename P6 = void>
struct Invoker {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<R(P1, P2, P3, P4, P5, P6)>& callback,
const P1& a1,
const P2& a2,
const P3& a3,
const P4& a4,
const P5& a5,
const P6& a6) {
MATE_METHOD_RETURN(callback.Run(a1, a2, a3, a4, a5, a6));
}
};
template<typename P1, typename P2, typename P3, typename P4, typename P5,
typename P6>
struct Invoker<void, P1, P2, P3, P4, P5, P6> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<void(P1, P2, P3, P4, P5, P6)>& callback,
const P1& a1,
const P2& a2,
const P3& a3,
const P4& a4,
const P5& a5,
const P6& a6) {
callback.Run(a1, a2, a3, a4, a5, a6);
MATE_METHOD_RETURN_UNDEFINED();
}
};
template<typename R, typename P1, typename P2, typename P3, typename P4,
typename P5>
struct Invoker<R, P1, P2, P3, P4, P5, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<R(P1, P2, P3, P4, P5)>& callback,
const P1& a1,
const P2& a2,
const P3& a3,
const P4& a4,
const P5& a5) {
MATE_METHOD_RETURN(callback.Run(a1, a2, a3, a4, a5));
}
};
template<typename P1, typename P2, typename P3, typename P4, typename P5>
struct Invoker<void, P1, P2, P3, P4, P5, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<void(P1, P2, P3, P4, P5)>& callback,
const P1& a1,
const P2& a2,
const P3& a3,
const P4& a4,
const P5& a5) {
callback.Run(a1, a2, a3, a4, a5);
MATE_METHOD_RETURN_UNDEFINED();
}
};
template<typename R, typename P1, typename P2, typename P3, typename P4>
struct Invoker<R, P1, P2, P3, P4, void, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<R(P1, P2, P3, P4)>& callback,
const P1& a1,
const P2& a2,
const P3& a3,
const P4& a4) {
MATE_METHOD_RETURN(callback.Run(a1, a2, a3, a4));
}
};
template<typename P1, typename P2, typename P3, typename P4>
struct Invoker<void, P1, P2, P3, P4, void, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<void(P1, P2, P3, P4)>& callback,
const P1& a1,
const P2& a2,
const P3& a3,
const P4& a4) {
callback.Run(a1, a2, a3, a4);
MATE_METHOD_RETURN_UNDEFINED();
}
};
template<typename R, typename P1, typename P2, typename P3>
struct Invoker<R, P1, P2, P3, void, void, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<R(P1, P2, P3)>& callback,
const P1& a1,
const P2& a2,
const P3& a3) {
MATE_METHOD_RETURN(callback.Run(a1, a2, a3));
}
};
template<typename P1, typename P2, typename P3>
struct Invoker<void, P1, P2, P3, void, void, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<void(P1, P2, P3)>& callback,
const P1& a1,
const P2& a2,
const P3& a3) {
callback.Run(a1, a2, a3);
MATE_METHOD_RETURN_UNDEFINED();
}
};
template<typename R, typename P1, typename P2>
struct Invoker<R, P1, P2, void, void, void, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<R(P1, P2)>& callback,
const P1& a1,
const P2& a2) {
MATE_METHOD_RETURN(callback.Run(a1, a2));
}
};
template<typename P1, typename P2>
struct Invoker<void, P1, P2, void, void, void, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<void(P1, P2)>& callback,
const P1& a1,
const P2& a2) {
callback.Run(a1, a2);
MATE_METHOD_RETURN_UNDEFINED();
}
};
template<typename R, typename P1>
struct Invoker<R, P1, void, void, void, void, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<R(P1)>& callback,
const P1& a1) {
MATE_METHOD_RETURN(callback.Run(a1));
}
};
template<typename P1>
struct Invoker<void, P1, void, void, void, void, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<void(P1)>& callback,
const P1& a1) {
MATE_METHOD_RETURN(callback.Run(a1));
}
};
template<typename R>
struct Invoker<R, void, void, void, void, void, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<R()>& callback) {
MATE_METHOD_RETURN(callback.Run());
}
};
template<>
struct Invoker<void, void, void, void, void, void, void> {
inline static MATE_METHOD_RETURN_TYPE Go(
Arguments& args,
const base::Callback<void()>& callback) {
callback.Run();
MATE_METHOD_RETURN_UNDEFINED();
}
};
template<typename T>
bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
T* result) {
if (is_first && (create_flags & HolderIsFirstArgument) != 0) {
return args->GetHolder(result);
} else {
return args->GetNext(result);
}
}
// For advanced use cases, we allow callers to request the unparsed Arguments
// object and poke around in it directly.
inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
Arguments* result) {
*result = *args;
return true;
}
inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
Arguments** result) {
*result = args;
return true;
}
// It's common for clients to just need the isolate, so we make that easy.
inline bool GetNextArgument(Arguments* args, int create_flags,
bool is_first, v8::Isolate** result) {
*result = args->isolate();
return true;
}
// DispatchToCallback converts all the JavaScript arguments to C++ types and
// invokes the base::Callback.
template<typename Sig>
struct Dispatcher {
};
template<typename R>
struct Dispatcher<R()> {
static MATE_METHOD(DispatchToCallback) {
Arguments args(info);
v8::Handle<v8::External> v8_holder;
CHECK(args.GetData(&v8_holder));
CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
v8_holder->Value());
typedef CallbackHolder<R()> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
return Invoker<R>::Go(args, holder->callback);
}
};
template<typename R, typename P1>
struct Dispatcher<R(P1)> {
static MATE_METHOD(DispatchToCallback) {
Arguments args(info);
v8::Handle<v8::External> v8_holder;
CHECK(args.GetData(&v8_holder));
CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
v8_holder->Value());
typedef CallbackHolder<R(P1)> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
typename CallbackParamTraits<P1>::LocalType a1;
if (!GetNextArgument(args, holder->flags, true, &a1)) {
args.ThrowError();
MATE_METHOD_RETURN_UNDEFINED();
}
return Invoker<R, P1>::Go(args, holder->callback, a1);
}
};
template<typename R, typename P1, typename P2>
struct Dispatcher<R(P1, P2)> {
static MATE_METHOD(DispatchToCallback) {
Arguments args(info);
v8::Handle<v8::External> v8_holder;
CHECK(args.GetData(&v8_holder));
CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
v8_holder->Value());
typedef CallbackHolder<R(P1, P2)> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
if (!GetNextArgument(args, holder->flags, true, &a1) ||
!GetNextArgument(args, holder->flags, false, &a2)) {
args.ThrowError();
MATE_METHOD_RETURN_UNDEFINED();
}
return Invoker<R, P1, P2>::Go(args, holder->callback, a1, a2);
}
};
template<typename R, typename P1, typename P2, typename P3>
struct Dispatcher<R(P1, P2, P3)> {
static MATE_METHOD(DispatchToCallback) {
Arguments args(info);
v8::Handle<v8::External> v8_holder;
CHECK(args.GetData(&v8_holder));
CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
v8_holder->Value());
typedef CallbackHolder<R(P1, P2, P3)> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
typename CallbackParamTraits<P3>::LocalType a3;
if (!GetNextArgument(args, holder->flags, true, &a1) ||
!GetNextArgument(args, holder->flags, false, &a2) ||
!GetNextArgument(args, holder->flags, false, &a3)) {
args.ThrowError();
MATE_METHOD_RETURN_UNDEFINED();
}
return Invoker<R, P1, P2, P3>::Go(args, holder->callback, a1, a2, a3);
}
};
template<typename R, typename P1, typename P2, typename P3, typename P4>
struct Dispatcher<R(P1, P2, P3, P4)> {
static MATE_METHOD(DispatchToCallback) {
Arguments args(info);
v8::Handle<v8::External> v8_holder;
CHECK(args.GetData(&v8_holder));
CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
v8_holder->Value());
typedef CallbackHolder<R(P1, P2, P3, P4)> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
typename CallbackParamTraits<P3>::LocalType a3;
typename CallbackParamTraits<P4>::LocalType a4;
if (!GetNextArgument(args, holder->flags, true, &a1) ||
!GetNextArgument(args, holder->flags, false, &a2) ||
!GetNextArgument(args, holder->flags, false, &a3) ||
!GetNextArgument(args, holder->flags, false, &a4)) {
args.ThrowError();
MATE_METHOD_RETURN_UNDEFINED();
}
return Invoker<R, P1, P2, P3, P4>::Go(args, holder->callback, a1, a2, a3,
a4);
}
};
template<typename R, typename P1, typename P2, typename P3, typename P4,
typename P5>
struct Dispatcher<R(P1, P2, P3, P4, P5)> {
static MATE_METHOD(DispatchToCallback) {
Arguments args(info);
v8::Handle<v8::External> v8_holder;
CHECK(args.GetData(&v8_holder));
CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
v8_holder->Value());
typedef CallbackHolder<R(P1, P2, P3, P4, P5)> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
typename CallbackParamTraits<P3>::LocalType a3;
typename CallbackParamTraits<P4>::LocalType a4;
typename CallbackParamTraits<P5>::LocalType a5;
if (!GetNextArgument(args, holder->flags, true, &a1) ||
!GetNextArgument(args, holder->flags, false, &a2) ||
!GetNextArgument(args, holder->flags, false, &a3) ||
!GetNextArgument(args, holder->flags, false, &a4) ||
!GetNextArgument(args, holder->flags, false, &a5)) {
args.ThrowError();
MATE_METHOD_RETURN_UNDEFINED();
}
return Invoker<R, P1, P2, P3, P4, P5>::Go(args, holder->callback, a1, a2,
a3, a4, a5);
}
};
template<typename R, typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6>
struct Dispatcher<R(P1, P2, P3, P4, P5, P6)> {
static MATE_METHOD(DispatchToCallback) {
Arguments args(info);
v8::Handle<v8::External> v8_holder;
CHECK(args.GetData(&v8_holder));
CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
v8_holder->Value());
typedef CallbackHolder<R(P1, P2, P3, P4, P5, P6)> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
typename CallbackParamTraits<P3>::LocalType a3;
typename CallbackParamTraits<P4>::LocalType a4;
typename CallbackParamTraits<P5>::LocalType a5;
typename CallbackParamTraits<P6>::LocalType a6;
if (!GetNextArgument(args, holder->flags, true, &a1) ||
!GetNextArgument(args, holder->flags, false, &a2) ||
!GetNextArgument(args, holder->flags, false, &a3) ||
!GetNextArgument(args, holder->flags, false, &a4) ||
!GetNextArgument(args, holder->flags, false, &a5) ||
!GetNextArgument(args, holder->flags, false, &a6)) {
args.ThrowError();
MATE_METHOD_RETURN_UNDEFINED();
}
return Invoker<R, P1, P2, P3, P4, P5, P6>::Go(args, holder->callback, a1,
a2, a3, a4, a5, a6);
}
};
} // namespace internal
// CreateFunctionTemplate creates a v8::FunctionTemplate that will create
// JavaScript functions that execute a provided C++ function or base::Callback.
// JavaScript arguments are automatically converted via mate::Converter, as is
// the return value of the C++ function, if any.
template<typename Sig>
v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
v8::Isolate* isolate, const base::Callback<Sig> callback,
int callback_flags = 0) {
typedef internal::CallbackHolder<Sig> HolderT;
HolderT* holder = new HolderT(isolate, callback, callback_flags);
return v8::FunctionTemplate::New(
isolate,
&internal::Dispatcher<Sig>::DispatchToCallback,
ConvertToV8<v8::Handle<v8::External> >(isolate,
holder->GetHandle(isolate)));
}
} // namespace mate
#endif // NATIVE_MATE_FUNCTION_TEMPLATE_H_

68
native_mate/handle.h Normal file
View File

@@ -0,0 +1,68 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#ifndef NATIVE_MATE_HANDLE_H_
#define NATIVE_MATE_HANDLE_H_
#include "native_mate/converter.h"
namespace mate {
// You can use mate::Handle on the stack to retain a mate::Wrappable object.
// Currently we don't have a mechanism for retaining a mate::Wrappable object
// in the C++ heap because strong references from C++ to V8 can cause memory
// leaks.
template<typename T>
class Handle {
public:
Handle() : object_(NULL) {}
Handle(v8::Handle<v8::Value> wrapper, T* object)
: wrapper_(wrapper),
object_(object) {
}
bool IsEmpty() const { return !object_; }
void Clear() {
wrapper_.Clear();
object_ = NULL;
}
T* operator->() const { return object_; }
v8::Handle<v8::Value> ToV8() const { return wrapper_; }
T* get() const { return object_; }
private:
v8::Handle<v8::Value> wrapper_;
T* object_;
};
template<typename T>
struct Converter<mate::Handle<T> > {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
const mate::Handle<T>& val) {
return val.ToV8();
}
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
mate::Handle<T>* out) {
T* object = NULL;
if (!Converter<T*>::FromV8(isolate, val, &object)) {
return false;
}
*out = mate::Handle<T>(val, object);
return true;
}
};
// This function is a convenient way to create a handle from a raw pointer
// without having to write out the type of the object explicitly.
template<typename T>
mate::Handle<T> CreateHandle(v8::Isolate* isolate, T* object) {
return mate::Handle<T>(object->GetWrapper(isolate), object);
}
} // namespace mate
#endif // NATIVE_MATE_HANDLE_H_

View File

@@ -0,0 +1,39 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#include "native_mate/object_template_builder.h"
namespace mate {
ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate)
: isolate_(isolate), template_(v8::ObjectTemplate::New()) {
template_->SetInternalFieldCount(1);
}
ObjectTemplateBuilder::~ObjectTemplateBuilder() {
}
ObjectTemplateBuilder& ObjectTemplateBuilder::SetImpl(
const base::StringPiece& name, v8::Handle<v8::Data> val) {
template_->Set(StringToSymbol(isolate_, name), val);
return *this;
}
ObjectTemplateBuilder& ObjectTemplateBuilder::SetPropertyImpl(
const base::StringPiece& name, v8::Handle<v8::FunctionTemplate> getter,
v8::Handle<v8::FunctionTemplate> setter) {
#if NODE_VERSION_AT_LEAST(0, 11, 0)
template_->SetAccessorProperty(StringToSymbol(isolate_, name), getter,
setter);
#endif
return *this;
}
v8::Local<v8::ObjectTemplate> ObjectTemplateBuilder::Build() {
v8::Local<v8::ObjectTemplate> result = template_;
template_.Clear();
return result;
}
} // namespace mate

View File

@@ -0,0 +1,123 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#ifndef NATIVE_MATE_OBJECT_TEMPLATE_BUILDER_H_
#define NATIVE_MATE_OBJECT_TEMPLATE_BUILDER_H_
#include "base/bind.h"
#include "base/callback.h"
#include "base/strings/string_piece.h"
#include "base/template_util.h"
#include "native_mate/converter.h"
#include "native_mate/function_template.h"
#include "v8/include/v8.h"
namespace mate {
namespace {
// Base template - used only for non-member function pointers. Other types
// either go to one of the below specializations, or go here and fail to compile
// because of base::Bind().
template<typename T, typename Enable = void>
struct CallbackTraits {
static v8::Handle<v8::FunctionTemplate> CreateTemplate(v8::Isolate* isolate,
T callback) {
return CreateFunctionTemplate(isolate, base::Bind(callback));
}
};
// Specialization for base::Callback.
template<typename T>
struct CallbackTraits<base::Callback<T> > {
static v8::Handle<v8::FunctionTemplate> CreateTemplate(
v8::Isolate* isolate, const base::Callback<T>& callback) {
return CreateFunctionTemplate(isolate, callback);
}
};
// Specialization for member function pointers. We need to handle this case
// specially because the first parameter for callbacks to MFP should typically
// come from the the JavaScript "this" object the function was called on, not
// from the first normal parameter.
template<typename T>
struct CallbackTraits<T, typename base::enable_if<
base::is_member_function_pointer<T>::value>::type> {
static v8::Handle<v8::FunctionTemplate> CreateTemplate(v8::Isolate* isolate,
T callback) {
return CreateFunctionTemplate(isolate, base::Bind(callback),
HolderIsFirstArgument);
}
};
// This specialization allows people to construct function templates directly if
// they need to do fancier stuff.
template<>
struct CallbackTraits<v8::Handle<v8::FunctionTemplate> > {
static v8::Handle<v8::FunctionTemplate> CreateTemplate(
v8::Handle<v8::FunctionTemplate> templ) {
return templ;
}
};
} // namespace
// ObjectTemplateBuilder provides a handy interface to creating
// v8::ObjectTemplate instances with various sorts of properties.
class ObjectTemplateBuilder {
public:
explicit ObjectTemplateBuilder(v8::Isolate* isolate);
~ObjectTemplateBuilder();
// It's against Google C++ style to return a non-const ref, but we take some
// poetic license here in order that all calls to Set() can be via the '.'
// operator and line up nicely.
template<typename T>
ObjectTemplateBuilder& SetValue(const base::StringPiece& name, T val) {
return SetImpl(name, ConvertToV8(isolate_, val));
}
// In the following methods, T and U can be function pointer, member function
// pointer, base::Callback, or v8::FunctionTemplate. Most clients will want to
// use one of the first two options. Also see mate::CreateFunctionTemplate()
// for creating raw function templates.
template<typename T>
ObjectTemplateBuilder& SetMethod(const base::StringPiece& name,
const T& callback) {
return SetImpl(name, CallbackTraits<T>::CreateTemplate(isolate_, callback));
}
template<typename T>
ObjectTemplateBuilder& SetProperty(const base::StringPiece& name,
const T& getter) {
return SetPropertyImpl(name,
CallbackTraits<T>::CreateTemplate(isolate_, getter),
v8::Local<v8::FunctionTemplate>());
}
template<typename T, typename U>
ObjectTemplateBuilder& SetProperty(const base::StringPiece& name,
const T& getter, const U& setter) {
return SetPropertyImpl(name,
CallbackTraits<T>::CreateTemplate(isolate_, getter),
CallbackTraits<U>::CreateTemplate(isolate_, setter));
}
v8::Local<v8::ObjectTemplate> Build();
private:
ObjectTemplateBuilder& SetImpl(const base::StringPiece& name,
v8::Handle<v8::Data> val);
ObjectTemplateBuilder& SetPropertyImpl(
const base::StringPiece& name, v8::Handle<v8::FunctionTemplate> getter,
v8::Handle<v8::FunctionTemplate> setter);
v8::Isolate* isolate_;
// ObjectTemplateBuilder should only be used on the stack.
v8::Local<v8::ObjectTemplate> template_;
};
} // namespace mate
#endif // NATIVE_MATE_OBJECT_TEMPLATE_BUILDER_H_

View File

@@ -0,0 +1,111 @@
// Copyright 2014 Cheng Zhao. All rights reserved.
// Use of this source code is governed by MIT license that can be found in the
// LICENSE file.
#ifndef NATIVE_MATE_SCOPED_PERSISTENT_H_
#define NATIVE_MATE_SCOPED_PERSISTENT_H_
#include "base/memory/ref_counted.h"
#include "v8/include/v8.h"
namespace mate {
// A v8::Persistent handle to a V8 value which destroys and clears the
// underlying handle on destruction.
template <typename T>
class ScopedPersistent {
public:
ScopedPersistent() {
}
explicit ScopedPersistent(v8::Handle<T> handle) {
reset(handle);
}
~ScopedPersistent() {
reset();
}
void reset(v8::Handle<T> handle) {
if (!handle.IsEmpty())
handle_.Reset(GetIsolate(handle), handle);
else
reset();
}
void reset() {
handle_.Reset();
}
bool IsEmpty() const {
return handle_.IsEmpty();
}
v8::Handle<T> NewHandle() const {
if (handle_.IsEmpty())
return v8::Local<T>();
return v8::Local<T>::New(GetIsolate(handle_), handle_);
}
v8::Handle<T> NewHandle(v8::Isolate* isolate) const {
if (handle_.IsEmpty())
return v8::Local<T>();
return v8::Local<T>::New(isolate, handle_);
}
template <typename P>
void MakeWeak(P* parameters,
typename v8::WeakReferenceCallbacks<T, P>::Revivable callback) {
handle_.MakeWeak(parameters, callback);
}
private:
template <typename U>
static v8::Isolate* GetIsolate(v8::Handle<U> object_handle) {
// Only works for v8::Object and its subclasses. Add specialisations for
// anything else.
if (!object_handle.IsEmpty())
return GetIsolate(object_handle->CreationContext());
return v8::Isolate::GetCurrent();
}
static v8::Isolate* GetIsolate(v8::Handle<v8::Context> context_handle) {
if (!context_handle.IsEmpty())
return context_handle->GetIsolate();
return v8::Isolate::GetCurrent();
}
static v8::Isolate* GetIsolate(
v8::Handle<v8::ObjectTemplate> template_handle) {
return v8::Isolate::GetCurrent();
}
template <typename U>
static v8::Isolate* GetIsolate(const U& any_handle) {
return v8::Isolate::GetCurrent();
}
v8::Persistent<T> handle_;
DISALLOW_COPY_AND_ASSIGN(ScopedPersistent);
};
template <typename T>
class RefCountedPersistent : public ScopedPersistent<T>,
public base::RefCounted<RefCountedPersistent<T>> {
public:
RefCountedPersistent() {}
explicit RefCountedPersistent(v8::Handle<T> handle)
: ScopedPersistent<T>(handle) {
}
protected:
friend class base::RefCounted<RefCountedPersistent<T>>;
~RefCountedPersistent() {}
private:
DISALLOW_COPY_AND_ASSIGN(RefCountedPersistent);
};
} // namespace mate
#endif // NATIVE_MATE_SCOPED_PERSISTENT_H_

49
native_mate/try_catch.cc Normal file
View File

@@ -0,0 +1,49 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#include "native_mate/try_catch.h"
#include <sstream>
#include "native_mate/converter.h"
namespace mate {
TryCatch::TryCatch() {
}
TryCatch::~TryCatch() {
}
bool TryCatch::HasCaught() {
return try_catch_.HasCaught();
}
std::string TryCatch::GetStackTrace() {
if (!HasCaught()) {
return "";
}
std::stringstream ss;
v8::Handle<v8::Message> message = try_catch_.Message();
ss << V8ToString(message->Get()) << std::endl
<< V8ToString(message->GetSourceLine()) << std::endl;
v8::Handle<v8::StackTrace> trace = message->GetStackTrace();
if (trace.IsEmpty())
return ss.str();
int len = trace->GetFrameCount();
for (int i = 0; i < len; ++i) {
v8::Handle<v8::StackFrame> frame = trace->GetFrame(i);
ss << V8ToString(frame->GetScriptName()) << ":"
<< frame->GetLineNumber() << ":"
<< frame->GetColumn() << ": "
<< V8ToString(frame->GetFunctionName())
<< std::endl;
}
return ss.str();
}
} // namespace mate

32
native_mate/try_catch.h Normal file
View File

@@ -0,0 +1,32 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#ifndef NATIVE_MATE_TRY_CATCH_H_
#define NATIVE_MATE_TRY_CATCH_H_
#include <string>
#include "base/basictypes.h"
#include "v8/include/v8.h"
namespace mate {
// TryCatch is a convenient wrapper around v8::TryCatch.
class TryCatch {
public:
TryCatch();
~TryCatch();
bool HasCaught();
std::string GetStackTrace();
private:
v8::TryCatch try_catch_;
DISALLOW_COPY_AND_ASSIGN(TryCatch);
};
} // namespace mate
#endif // NATIVE_MATE_TRY_CATCH_H_

58
native_mate/wrappable.cc Normal file
View File

@@ -0,0 +1,58 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#include "native_mate/wrappable.h"
#include "base/logging.h"
#include "native_mate/object_template_builder.h"
namespace mate {
Wrappable::Wrappable() {
}
Wrappable::~Wrappable() {
MATE_PERSISTENT_RESET(wrapper_);
}
ObjectTemplateBuilder Wrappable::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return ObjectTemplateBuilder(isolate);
}
// static
MATE_WEAK_CALLBACK(Wrappable::WeakCallback, v8::Object, Wrappable) {
MATE_WEAK_CALLBACK_INIT(Wrappable);
MATE_PERSISTENT_RESET(self->wrapper_);
delete self;
}
v8::Handle<v8::Object> Wrappable::GetWrapper(v8::Isolate* isolate) {
if (!wrapper_.IsEmpty()) {
return MATE_PERSISTENT_TO_LOCAL(v8::Object, isolate, wrapper_);
}
v8::Local<v8::ObjectTemplate> templ =
GetObjectTemplateBuilder(isolate).Build();
CHECK(!templ.IsEmpty());
CHECK_EQ(1, templ->InternalFieldCount());
v8::Handle<v8::Object> wrapper = templ->NewInstance();
MATE_SET_INTERNAL_FIELD_POINTER(wrapper, 0, this);
MATE_PERSISTENT_ASSIGN(v8::Object, isolate, wrapper_, wrapper);
MATE_PERSISTENT_SET_WEAK(wrapper_, this, WeakCallback);
return wrapper;
}
namespace internal {
void* FromV8Impl(v8::Isolate* isolate, v8::Handle<v8::Value> val) {
if (!val->IsObject())
return NULL;
v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
return MATE_GET_INTERNAL_FIELD_POINTER(obj, 0);
}
} // namespace internal
} // namespace mate

85
native_mate/wrappable.h Normal file
View File

@@ -0,0 +1,85 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
#ifndef NATIVE_MATE_WRAPPABLE_H_
#define NATIVE_MATE_WRAPPABLE_H_
#include "base/template_util.h"
#include "native_mate/compat.h"
#include "native_mate/converter.h"
namespace mate {
namespace internal {
void* FromV8Impl(v8::Isolate* isolate, v8::Handle<v8::Value> val);
} // namespace internal
// Wrappable is a base class for C++ objects that have corresponding v8 wrapper
// objects. To retain a Wrappable object on the stack, use a mate::Handle.
//
// USAGE:
// // my_class.h
// class MyClass : Wrappable {
// public:
// // Optional, only required if non-empty template should be used.
// virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
// v8::Isolate* isolate);
// ...
// };
//
// mate::ObjectTemplateBuilder MyClass::GetObjectTemplateBuilder(
// v8::Isolate* isolate) {
// return Wrappable::GetObjectTemplateBuilder(isolate).SetValue("foobar", 42);
// }
//
// Subclasses should also typically have private constructors and expose a
// static Create function that returns a mate::Handle. Forcing creators through
// this static Create function will enforce that clients actually create a
// wrapper for the object. If clients fail to create a wrapper for a wrappable
// object, the object will leak because we use the weak callback from the
// wrapper as the signal to delete the wrapped object.
class ObjectTemplateBuilder;
// Non-template base class to share code between templates instances.
class Wrappable {
public:
// Retrieve (or create) the v8 wrapper object cooresponding to this object.
v8::Handle<v8::Object> GetWrapper(v8::Isolate* isolate);
protected:
Wrappable();
virtual ~Wrappable();
virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate);
private:
static MATE_WEAK_CALLBACK(WeakCallback, v8::Object, Wrappable);
v8::Persistent<v8::Object> wrapper_; // Weak
DISALLOW_COPY_AND_ASSIGN(Wrappable);
};
// This converter handles any subclass of Wrappable.
template<typename T>
struct Converter<T*, typename base::enable_if<
base::is_convertible<T*, Wrappable*>::value>::type> {
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, T* val) {
return val->GetWrapper(isolate);
}
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, T** out) {
*out = static_cast<T*>(static_cast<Wrappable*>(
internal::FromV8Impl(isolate, val)));
return *out != NULL;
}
};
} // namespace mate
#endif // NATIVE_MATE_WRAPPABLE_H_