Merge pull request #13379 from electron/native-mate-in-electron

Merge native_mate into electron/electron
This commit is contained in:
Samuel Attard 2018-06-23 02:00:58 +10:00 коммит произвёл GitHub
Родитель 1c4d20eb94 d068ff3afb
Коммит a96fc9170c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
29 изменённых файлов: 3178 добавлений и 8 удалений

3
.gitmodules поставляемый
Просмотреть файл

@ -7,9 +7,6 @@
[submodule "vendor/breakpad"]
path = vendor/breakpad
url = https://github.com/electron/chromium-breakpad.git
[submodule "vendor/native_mate"]
path = vendor/native_mate
url = https://github.com/electron/native-mate.git
[submodule "vendor/crashpad"]
path = vendor/crashpad
url = https://github.com/electron/crashpad.git

Просмотреть файл

@ -129,7 +129,7 @@ These individual tutorials expand on topics discussed in the guide above.
* [Menu](api/menu.md)
* [MenuItem](api/menu-item.md)
* [net](api/net.md)
* [netLog](api/netLog.md)
* [netLog](api/net-log.md)
* [powerMonitor](api/power-monitor.md)
* [powerSaveBlocker](api/power-save-blocker.md)
* [protocol](api/protocol.md)

Просмотреть файл

@ -1,6 +1,6 @@
# API Contract
Breaking changes will be documented here, and deprecation warnings added to JS code where possible, at least [one major version](electron-versioning.md#semver) before the change is made.
Breaking changes will be documented here, and deprecation warnings added to JS code where possible, at least [one major version](../tutorial/electron-versioning.md#semver) before the change is made.
# `FIXME` comments

Просмотреть файл

@ -10,7 +10,7 @@
'includes': [
'features.gypi',
'filenames.gypi',
'vendor/native_mate/native_mate_files.gypi',
'native_mate/native_mate_files.gypi',
],
'target_defaults': {
'defines': [
@ -300,7 +300,7 @@
'include_dirs': [
'.',
'chromium_src',
'vendor/native_mate',
'native_mate',
# Include atom_natives.h.
'<(SHARED_INTERMEDIATE_DIR)',
# Include directories for uv and node.

Просмотреть файл

@ -0,0 +1,27 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

56
native_mate/README.md Normal file
Просмотреть файл

@ -0,0 +1,56 @@
> A fork of Chromium's [gin library][chromium-gin-lib] that makes it easier to
> marshal types between C++ and JavaScript.
# Overview
`native-mate` was forked from `gin` so that it could be used in
[Electron][electron] without conflicting with Node's Environment. It has also
been extended to allow Electron to create classes in JavaScript.
With the help of Chromium's `base` library, `native-mate` makes writing JS
bindings very easy, and most of the intricate details of converting V8 types
to C++ types and back are taken care of auto-magically. In most cases there's
no need to use the raw V8 API to implement an API binding.
For example, here's an API binding that doesn't use `native-mate`:
```c++
// static
void Shell::OpenItem(const v8::FunctionCallbackInfo<v8::Value>& args) {
base::FilePath file_path;
if (!FromV8Arguments(args, &file_path))
return node::ThrowTypeError("Bad argument");
platform_util::OpenItem(file_path);
}
// static
void Shell::Initialize(v8::Handle<v8::Object> target) {
NODE_SET_METHOD(target, "openItem", OpenItem);
}
```
And here's the same API binding using `native-mate`:
```c++
void Initialize(v8::Handle<v8::Object> exports) {
mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
dict.SetMethod("openItem", &platform_util::OpenItem);
}
```
# Code Structure
* `converter.h` - Templatized JS<->C++ conversion routines for many common C++
types. You can define your own by specializing `Converter`.
* `function_template.h` - Create JavaScript functions that dispatch to any C++
function, member function pointer, or `base::Callback`.
* `object_template_builder.h` - A handy utility for creation of `v8::ObjectTemplate`.
* `wrappable.h` - Base class for C++ classes that want to be owned by the V8 GC.
Wrappable objects are automatically deleted when GC discovers that nothing in
the V8 heap refers to them. This is also an easy way to expose C++ objects to
JavaScript.
[chromium-gin-lib]: https://code.google.com/p/chromium/codesearch#chromium/src/gin/README.md&sq=package:chromium
[electron]: http://electron.atom.io/

Просмотреть файл

@ -0,0 +1,72 @@
// 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 {
namespace {
std::string V8TypeAsString(v8::Isolate* isolate, v8::Local<v8::Value> value) {
if (value.IsEmpty())
return "<empty handle>";
v8::MaybeLocal<v8::String> details =
value->ToDetailString(isolate->GetCurrentContext());
std::string result;
if (!details.IsEmpty())
ConvertFromV8(isolate, details.ToLocalChecked(), &result);
return result;
}
} // namespace
Arguments::Arguments()
: isolate_(NULL),
info_(NULL),
next_(0),
insufficient_arguments_(false) {
}
Arguments::Arguments(const v8::FunctionCallbackInfo<v8::Value>& info)
: isolate_(info.GetIsolate()),
info_(&info),
next_(0),
insufficient_arguments_(false) {
}
Arguments::~Arguments() {
}
v8::Local<v8::Value> Arguments::PeekNext() const {
if (next_ >= info_->Length())
return v8::Local<v8::Value>();
return (*info_)[next_];
}
v8::Local<v8::Value> Arguments::ThrowError() const {
if (insufficient_arguments_)
return ThrowTypeError("Insufficient number of arguments.");
return ThrowTypeError(base::StringPrintf(
"Error processing argument at index %d, conversion failure from %s",
next_, V8TypeAsString(isolate_, (*info_)[next_]).c_str()));
}
v8::Local<v8::Value> Arguments::ThrowError(const std::string& message) const {
isolate_->ThrowException(v8::Exception::Error(
StringToV8(isolate_, message)));
return v8::Undefined(isolate_);
}
v8::Local<v8::Value> Arguments::ThrowTypeError(
const std::string& message) const {
isolate_->ThrowException(v8::Exception::TypeError(
StringToV8(isolate_, message)));
return v8::Undefined(isolate_);
}
} // namespace mate

Просмотреть файл

@ -0,0 +1,99 @@
// 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/macros.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 v8::FunctionCallbackInfo<v8::Value>& info);
~Arguments();
v8::Local<v8::Object> GetHolder() const {
return info_->Holder();
}
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::Local<v8::Value> val = (*info_)[next_];
bool success = ConvertFromV8(isolate_, val, out);
if (success)
next_++;
return success;
}
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::Local<v8::Value> val = (*info_)[next_++];
if (!ConvertFromV8(isolate_, val, &out->at(i)))
return false;
}
return true;
}
v8::Local<v8::Object> GetThis() {
return info_->This();
}
bool IsConstructCall() const {
return info_->IsConstructCall();
}
int Length() const {
return info_->Length();
}
template<typename T>
void Return(T val) {
info_->GetReturnValue().Set(ConvertToV8(isolate_, val));
}
v8::Local<v8::Value> PeekNext() const;
v8::Local<v8::Value> ThrowError() const;
v8::Local<v8::Value> ThrowError(const std::string& message) const;
v8::Local<v8::Value> ThrowTypeError(const std::string& message) const;
v8::Isolate* isolate() const { return isolate_; }
private:
v8::Isolate* isolate_;
const v8::FunctionCallbackInfo<v8::Value>* info_;
int next_;
bool insufficient_arguments_;
};
} // namespace mate
#endif // NATIVE_MATE_ARGUMENTS_H_

Просмотреть файл

@ -0,0 +1,148 @@
// This file was GENERATED by command:
// pump.py constructor.h.pump
// DO NOT EDIT BY HAND!!!
// Copyright 2014 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_CLASS_H_
#define NATIVE_MATE_WRAPPABLE_CLASS_H_
#include "base/bind.h"
#include "native_mate/function_template.h"
namespace mate {
namespace internal {
// This set of templates invokes a base::Callback by converting the Arguments
// into native types. It relies on the function_template.h to provide helper
// templates.
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*()>& callback) {
return callback.Run();
};
template<typename P1>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1)>& callback) {
typename CallbackParamTraits<P1>::LocalType a1;
if (!GetNextArgument(args, 0, true, &a1))
return nullptr;
return callback.Run(a1);
};
template<typename P1, typename P2>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1, P2)>& callback) {
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
if (!GetNextArgument(args, 0, true, &a1) ||
!GetNextArgument(args, 0, false, &a2))
return nullptr;
return callback.Run(a1, a2);
};
template<typename P1, typename P2, typename P3>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1, P2, P3)>& callback) {
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
typename CallbackParamTraits<P3>::LocalType a3;
if (!GetNextArgument(args, 0, true, &a1) ||
!GetNextArgument(args, 0, false, &a2) ||
!GetNextArgument(args, 0, false, &a3))
return nullptr;
return callback.Run(a1, a2, a3);
};
template<typename P1, typename P2, typename P3, typename P4>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1, P2, P3, P4)>& callback) {
typename CallbackParamTraits<P1>::LocalType a1;
typename CallbackParamTraits<P2>::LocalType a2;
typename CallbackParamTraits<P3>::LocalType a3;
typename CallbackParamTraits<P4>::LocalType a4;
if (!GetNextArgument(args, 0, true, &a1) ||
!GetNextArgument(args, 0, false, &a2) ||
!GetNextArgument(args, 0, false, &a3) ||
!GetNextArgument(args, 0, false, &a4))
return nullptr;
return callback.Run(a1, a2, a3, a4);
};
template<typename P1, typename P2, typename P3, typename P4, typename P5>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1, P2, P3, P4, P5)>& callback) {
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, 0, true, &a1) ||
!GetNextArgument(args, 0, false, &a2) ||
!GetNextArgument(args, 0, false, &a3) ||
!GetNextArgument(args, 0, false, &a4) ||
!GetNextArgument(args, 0, false, &a5))
return nullptr;
return callback.Run(a1, a2, a3, a4, a5);
};
template<typename P1, typename P2, typename P3, typename P4, typename P5,
typename P6>
inline WrappableBase* InvokeFactory(
Arguments* args,
const base::Callback<WrappableBase*(P1, P2, P3, P4, P5, P6)>& callback) {
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, 0, true, &a1) ||
!GetNextArgument(args, 0, false, &a2) ||
!GetNextArgument(args, 0, false, &a3) ||
!GetNextArgument(args, 0, false, &a4) ||
!GetNextArgument(args, 0, false, &a5) ||
!GetNextArgument(args, 0, false, &a6))
return nullptr;
return callback.Run(a1, a2, a3, a4, a5, a6);
};
template<typename Sig>
void InvokeNew(const base::Callback<Sig>& factory,
v8::Isolate* isolate, Arguments* args) {
if (!args->IsConstructCall()) {
args->ThrowError("Requires constructor call");
return;
}
WrappableBase* object;
{
// Don't continue if the constructor throws an exception.
v8::TryCatch try_catch(isolate);
object = internal::InvokeFactory(args, factory);
if (try_catch.HasCaught()) {
try_catch.ReThrow();
return;
}
}
if (!object)
args->ThrowError();
return;
}
} // namespace internal
} // namespace mate
#endif // NATIVE_MATE_WRAPPABLE_CLASS_H_

Просмотреть файл

@ -0,0 +1,247 @@
// 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 "v8/include/v8.h"
using v8::Array;
using v8::Boolean;
using v8::External;
using v8::Function;
using v8::Integer;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
namespace mate {
Local<Value> Converter<bool>::ToV8(Isolate* isolate, bool val) {
return v8::Boolean::New(isolate, val);
}
bool Converter<bool>::FromV8(Isolate* isolate, Local<Value> val, bool* out) {
if (!val->IsBoolean())
return false;
*out = val->BooleanValue();
return true;
}
#if !defined(OS_LINUX) && !defined(OS_FREEBSD)
Local<Value> Converter<unsigned long>::ToV8(Isolate* isolate,
unsigned long val) {
return v8::Integer::New(isolate, val);
}
bool Converter<unsigned long>::FromV8(Isolate* isolate, Local<Value> val,
unsigned long* out) {
if (!val->IsNumber())
return false;
*out = val->IntegerValue();
return true;
}
#endif
Local<Value> Converter<int32_t>::ToV8(Isolate* isolate, int32_t val) {
return v8::Integer::New(isolate, val);
}
bool Converter<int32_t>::FromV8(Isolate* isolate, Local<Value> val,
int32_t* out) {
if (!val->IsInt32())
return false;
*out = val->Int32Value();
return true;
}
Local<Value> Converter<uint32_t>::ToV8(Isolate* isolate, uint32_t val) {
return v8::Integer::NewFromUnsigned(isolate, val);
}
bool Converter<uint32_t>::FromV8(Isolate* isolate, Local<Value> val,
uint32_t* out) {
if (!val->IsUint32())
return false;
*out = val->Uint32Value();
return true;
}
Local<Value> Converter<int64_t>::ToV8(Isolate* isolate, int64_t val) {
return v8::Number::New(isolate, static_cast<double>(val));
}
bool Converter<int64_t>::FromV8(Isolate* isolate, Local<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;
}
Local<Value> Converter<uint64_t>::ToV8(Isolate* isolate, uint64_t val) {
return v8::Number::New(isolate, static_cast<double>(val));
}
bool Converter<uint64_t>::FromV8(Isolate* isolate, Local<Value> val,
uint64_t* out) {
if (!val->IsNumber())
return false;
*out = static_cast<uint64_t>(val->IntegerValue());
return true;
}
Local<Value> Converter<float>::ToV8(Isolate* isolate, float val) {
return v8::Number::New(isolate, val);
}
bool Converter<float>::FromV8(Isolate* isolate, Local<Value> val,
float* out) {
if (!val->IsNumber())
return false;
*out = static_cast<float>(val->NumberValue());
return true;
}
Local<Value> Converter<double>::ToV8(Isolate* isolate, double val) {
return v8::Number::New(isolate, val);
}
bool Converter<double>::FromV8(Isolate* isolate, Local<Value> val,
double* out) {
if (!val->IsNumber())
return false;
*out = val->NumberValue();
return true;
}
Local<Value> Converter<const char*>::ToV8(
Isolate* isolate, const char* val) {
return v8::String::NewFromUtf8(isolate, val);
}
Local<Value> Converter<base::StringPiece>::ToV8(
Isolate* isolate, const base::StringPiece& val) {
return v8::String::NewFromUtf8(isolate,
val.data(),
v8::String::kNormalString,
static_cast<uint32_t>(val.length()));
}
Local<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, Local<Value> val,
std::string* out) {
if (!val->IsString())
return false;
Local<String> str = Local<String>::Cast(val);
int length = str->Utf8Length();
out->resize(length);
str->WriteUtf8(&(*out)[0], length, NULL, String::NO_NULL_TERMINATION);
return true;
}
Local<Value> Converter<Local<Function>>::ToV8(Isolate* isolate,
Local<Function> val) {
return val;
}
bool Converter<Local<Function> >::FromV8(Isolate* isolate, Local<Value> val,
Local<Function>* out) {
if (!val->IsFunction())
return false;
*out = Local<Function>::Cast(val);
return true;
}
Local<Value> Converter<Local<Object> >::ToV8(Isolate* isolate,
Local<Object> val) {
return val;
}
bool Converter<Local<Object> >::FromV8(Isolate* isolate, Local<Value> val,
Local<Object>* out) {
if (!val->IsObject())
return false;
*out = Local<Object>::Cast(val);
return true;
}
Local<Value> Converter<Local<String> >::ToV8(Isolate* isolate,
Local<String> val) {
return val;
}
bool Converter<Local<String> >::FromV8(Isolate* isolate, Local<Value> val,
Local<String>* out) {
if (!val->IsString())
return false;
*out = Local<String>::Cast(val);
return true;
}
Local<Value> Converter<Local<External> >::ToV8(Isolate* isolate,
Local<External> val) {
return val;
}
bool Converter<Local<External> >::FromV8(Isolate* isolate,
v8::Local<Value> val,
Local<External>* out) {
if (!val->IsExternal())
return false;
*out = Local<External>::Cast(val);
return true;
}
Local<Value> Converter<Local<Array> >::ToV8(Isolate* isolate,
Local<Array> val) {
return val;
}
bool Converter<Local<Array> >::FromV8(Isolate* isolate,
v8::Local<Value> val,
Local<Array>* out) {
if (!val->IsArray())
return false;
*out = Local<Array>::Cast(val);
return true;
}
Local<Value> Converter<Local<Value> >::ToV8(Isolate* isolate,
Local<Value> val) {
return val;
}
bool Converter<Local<Value> >::FromV8(Isolate* isolate, Local<Value> val,
Local<Value>* out) {
*out = val;
return true;
}
v8::Local<v8::String> StringToSymbol(v8::Isolate* isolate,
const base::StringPiece& val) {
return v8::String::NewFromUtf8(isolate,
val.data(),
v8::String::kInternalizedString,
static_cast<uint32_t>(val.length()));
}
std::string V8ToString(v8::Local<v8::Value> value) {
if (value.IsEmpty())
return std::string();
std::string result;
if (!ConvertFromV8(NULL, value, &result))
return std::string();
return result;
}
} // namespace mate

Просмотреть файл

@ -0,0 +1,364 @@
// 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 <map>
#include <string>
#include <vector>
#include <set>
#include "base/strings/string_piece.h"
#include "v8/include/v8.h"
namespace mate {
template<typename KeyType>
bool SetProperty(v8::Isolate* isolate,
v8::Local<v8::Object> object,
KeyType key,
v8::Local<v8::Value> value) {
auto maybe = object->Set(isolate->GetCurrentContext(), key, value);
return !maybe.IsNothing() && maybe.FromJust();
}
template<typename T>
struct ToV8ReturnsMaybe {
static const bool value = false;
};
template<typename T, typename Enable = void>
struct Converter {};
template<>
struct Converter<void*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, void* val) {
return v8::Undefined(isolate);
}
};
template<>
struct Converter<std::nullptr_t> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, std::nullptr_t val) {
return v8::Null(isolate);
}
};
template<>
struct Converter<bool> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
bool val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
bool* out);
};
#if !defined(OS_LINUX) && !defined(OS_FREEBSD)
template<>
struct Converter<unsigned long> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
unsigned long val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
unsigned long* out);
};
#endif
template<>
struct Converter<int32_t> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
int32_t val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
int32_t* out);
};
template<>
struct Converter<uint32_t> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
uint32_t val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
uint32_t* out);
};
template<>
struct Converter<int64_t> {
// Warning: JavaScript cannot represent 64 integers precisely.
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
int64_t val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
int64_t* out);
};
template<>
struct Converter<uint64_t> {
// Warning: JavaScript cannot represent 64 integers precisely.
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
uint64_t val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
uint64_t* out);
};
template<>
struct Converter<float> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
float val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
float* out);
};
template<>
struct Converter<double> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
double val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
double* out);
};
template<>
struct Converter<const char*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, const char* val);
};
template<>
struct Converter<base::StringPiece> {
static v8::Local<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::Local<v8::Value> ToV8(v8::Isolate* isolate,
const std::string& val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
std::string* out);
};
v8::Local<v8::String> StringToSymbol(v8::Isolate* isolate,
const base::StringPiece& input);
std::string V8ToString(v8::Local<v8::Value> value);
template<>
struct Converter<v8::Local<v8::Function> > {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
v8::Local<v8::Function> val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
v8::Local<v8::Function>* out);
};
template<>
struct Converter<v8::Local<v8::Object> > {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
v8::Local<v8::Object> val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
v8::Local<v8::Object>* out);
};
template<>
struct Converter<v8::Local<v8::String> > {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
v8::Local<v8::String> val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
v8::Local<v8::String>* out);
};
template<>
struct Converter<v8::Local<v8::External> > {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
v8::Local<v8::External> val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
v8::Local<v8::External>* out);
};
template<>
struct Converter<v8::Local<v8::Array> > {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
v8::Local<v8::Array> val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
v8::Local<v8::Array>* out);
};
template<>
struct Converter<v8::Local<v8::Value> > {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
v8::Local<v8::Value> val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
v8::Local<v8::Value>* out);
};
template<typename T>
struct Converter<std::vector<T> > {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const std::vector<T>& val) {
v8::Local<v8::Array> result(
v8::Array::New(isolate, 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::Local<v8::Value> val,
std::vector<T>* out) {
if (!val->IsArray())
return false;
std::vector<T> result;
v8::Local<v8::Array> array(v8::Local<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;
}
};
template<typename T>
struct Converter<std::set<T> > {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const std::set<T>& val) {
v8::Local<v8::Array> result(
v8::Array::New(isolate, static_cast<int>(val.size())));
typename std::set<T>::const_iterator it;
int i;
for (i = 0, it = val.begin(); it != val.end(); ++it, ++i)
result->Set(i, Converter<T>::ToV8(isolate, *it));
return result;
}
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
std::set<T>* out) {
if (!val->IsArray())
return false;
std::set<T> result;
v8::Local<v8::Array> array(v8::Local<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.insert(item);
}
out->swap(result);
return true;
}
};
template<typename T>
struct Converter<std::map<std::string, T> > {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
std::map<std::string, T> * out) {
if (!val->IsObject())
return false;
v8::Local<v8::Object> dict = val->ToObject();
v8::Local<v8::Array> keys = dict->GetOwnPropertyNames();
for (uint32_t i = 0; i < keys->Length(); ++i) {
v8::Local<v8::Value> key = keys->Get(i);
T value;
if (Converter<T>::FromV8(isolate, dict->Get(key), &value))
(*out)[V8ToString(key)] = std::move(value);
}
return true;
}
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const std::map<std::string, T>& val) {
v8::Local<v8::Object> result = v8::Object::New(isolate);
for (auto i = val.begin(); i != val.end(); i++) {
result->Set(Converter<T>::ToV8(isolate, i->first),
Converter<T>::ToV8(isolate, i->second));
}
return result;
}
};
// Convenience functions that deduce T.
template<typename T>
v8::Local<v8::Value> ConvertToV8(v8::Isolate* isolate, const T& input) {
return Converter<T>::ToV8(isolate, input);
}
inline v8::Local<v8::Value> ConvertToV8(v8::Isolate* isolate,
const char* input) {
return Converter<const char*>::ToV8(isolate, input);
}
template<typename T>
v8::MaybeLocal<v8::Value> ConvertToV8(v8::Local<v8::Context> context,
const T& input) {
return Converter<T>::ToV8(context, input);
}
template<typename T, bool = ToV8ReturnsMaybe<T>::value> struct ToV8Traits;
template <typename T>
struct ToV8Traits<T, true> {
static bool TryConvertToV8(v8::Isolate* isolate,
const T& input,
v8::Local<v8::Value>* output) {
auto maybe = ConvertToV8(isolate->GetCurrentContext(), input);
if (maybe.IsEmpty())
return false;
*output = maybe.ToLocalChecked();
return true;
}
};
template <typename T>
struct ToV8Traits<T, false> {
static bool TryConvertToV8(v8::Isolate* isolate,
const T& input,
v8::Local<v8::Value>* output) {
*output = ConvertToV8(isolate, input);
return true;
}
};
template <typename T>
bool TryConvertToV8(v8::Isolate* isolate,
const T& input,
v8::Local<v8::Value>* output) {
return ToV8Traits<T>::TryConvertToV8(isolate, input, output);
}
template<typename T>
bool ConvertFromV8(v8::Isolate* isolate, v8::Local<v8::Value> input,
T* result) {
return Converter<T>::FromV8(isolate, input, result);
}
inline v8::Local<v8::String> StringToV8(
v8::Isolate* isolate,
const base::StringPiece& input) {
return ConvertToV8(isolate, input).As<v8::String>();
}
} // namespace mate
#endif // NATIVE_MATE_CONVERTER_H_

Просмотреть файл

@ -0,0 +1,44 @@
// 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()
: isolate_(NULL) {
}
Dictionary::Dictionary(v8::Isolate* isolate,
v8::Local<v8::Object> object)
: isolate_(isolate),
object_(object) {
}
Dictionary::~Dictionary() {
}
Dictionary Dictionary::CreateEmpty(v8::Isolate* isolate) {
return Dictionary(isolate, v8::Object::New(isolate));
}
v8::Local<v8::Object> Dictionary::GetHandle() const {
return object_;
}
v8::Local<v8::Value> Converter<Dictionary>::ToV8(v8::Isolate* isolate,
Dictionary val) {
return val.GetHandle();
}
bool Converter<Dictionary>::FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
Dictionary* out) {
if (!val->IsObject() || val->IsFunction())
return false;
*out = Dictionary(isolate, v8::Local<v8::Object>::Cast(val));
return true;
}
} // namespace mate

Просмотреть файл

@ -0,0 +1,146 @@
// 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"
#include "native_mate/object_template_builder.h"
namespace mate {
namespace internal {
// Returns true if |maybe| is both a value, and that value is true.
inline bool IsTrue(v8::Maybe<bool> maybe) {
return maybe.IsJust() && maybe.FromJust();
}
} // namespace internal
// 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:
Dictionary();
Dictionary(v8::Isolate* isolate, v8::Local<v8::Object> object);
virtual ~Dictionary();
static Dictionary CreateEmpty(v8::Isolate* isolate);
template<typename T>
bool Get(const base::StringPiece& key, T* out) const {
// Check for existence before getting, otherwise this method will always
// returns true when T == v8::Local<v8::Value>.
v8::Local<v8::Context> context = isolate_->GetCurrentContext();
v8::Local<v8::String> v8_key = StringToV8(isolate_, key);
if (!internal::IsTrue(GetHandle()->Has(context, v8_key)))
return false;
v8::Local<v8::Value> val;
if (!GetHandle()->Get(context, v8_key).ToLocal(&val))
return false;
return ConvertFromV8(isolate_, val, out);
}
template<typename T>
bool GetHidden(const base::StringPiece& key, T* out) const {
v8::Local<v8::Context> context = isolate_->GetCurrentContext();
v8::Local<v8::Private> privateKey =
v8::Private::ForApi(isolate_, StringToV8(isolate_, key));
v8::Local<v8::Value> value;
v8::Maybe<bool> result =
GetHandle()->HasPrivate(context, privateKey);
if (internal::IsTrue(result) &&
GetHandle()->GetPrivate(context, privateKey).ToLocal(&value))
return ConvertFromV8(isolate_, value, out);
return false;
}
template<typename T>
bool Set(const base::StringPiece& key, const T& val) {
v8::Local<v8::Value> v8_value;
if (!TryConvertToV8(isolate_, val, &v8_value))
return false;
v8::Maybe<bool> result =
GetHandle()->Set(isolate_->GetCurrentContext(),
StringToV8(isolate_, key),
v8_value);
return !result.IsNothing() && result.FromJust();
}
template<typename T>
bool SetHidden(const base::StringPiece& key, T val) {
v8::Local<v8::Value> v8_value;
if (!TryConvertToV8(isolate_, val, &v8_value))
return false;
v8::Local<v8::Context> context = isolate_->GetCurrentContext();
v8::Local<v8::Private> privateKey =
v8::Private::ForApi(isolate_, StringToV8(isolate_, key));
v8::Maybe<bool> result =
GetHandle()->SetPrivate(context, privateKey, v8_value);
return !result.IsNothing() && result.FromJust();
}
template<typename T>
bool SetReadOnly(const base::StringPiece& key, T val) {
v8::Local<v8::Value> v8_value;
if (!TryConvertToV8(isolate_, val, &v8_value))
return false;
v8::Maybe<bool> result =
GetHandle()->DefineOwnProperty(isolate_->GetCurrentContext(),
StringToV8(isolate_, key),
v8_value,
v8::ReadOnly);
return !result.IsNothing() && result.FromJust();
}
template<typename T>
bool SetMethod(const base::StringPiece& key, const T& callback) {
return GetHandle()->Set(
StringToV8(isolate_, key),
CallbackTraits<T>::CreateTemplate(isolate_, callback)->GetFunction());
}
bool Delete(const base::StringPiece& key) {
v8::Maybe<bool> result = GetHandle()->Delete(isolate_->GetCurrentContext(),
StringToV8(isolate_, key));
return !result.IsNothing() && result.FromJust();
}
bool IsEmpty() const { return isolate() == NULL; }
virtual v8::Local<v8::Object> GetHandle() const;
v8::Isolate* isolate() const { return isolate_; }
protected:
v8::Isolate* isolate_;
private:
v8::Local<v8::Object> object_;
};
template<>
struct Converter<Dictionary> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
Dictionary val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
Dictionary* out);
};
} // namespace mate
#endif // NATIVE_MATE_DICTIONARY_H_

Просмотреть файл

@ -0,0 +1,40 @@
// 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)
: v8_ref_(isolate, v8::External::New(isolate, this)) {
v8_ref_.SetWeak(this, &CallbackHolderBase::FirstWeakCallback,
v8::WeakCallbackType::kParameter);
}
CallbackHolderBase::~CallbackHolderBase() {
DCHECK(v8_ref_.IsEmpty());
}
v8::Local<v8::External> CallbackHolderBase::GetHandle(v8::Isolate* isolate) {
return v8::Local<v8::External>::New(isolate, v8_ref_);
}
// static
void CallbackHolderBase::FirstWeakCallback(
const v8::WeakCallbackInfo<CallbackHolderBase>& data) {
data.GetParameter()->v8_ref_.Reset();
data.SetSecondPassCallback(SecondWeakCallback);
}
// static
void CallbackHolderBase::SecondWeakCallback(
const v8::WeakCallbackInfo<CallbackHolderBase>& data) {
delete data.GetParameter();
}
} // namespace internal
} // namespace mate

Просмотреть файл

@ -0,0 +1,285 @@
// 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/wrappable_base.h"
#include "v8/include/v8.h"
namespace mate {
enum CreateFunctionTemplateFlags {
HolderIsFirstArgument = 1 << 0,
};
namespace internal {
struct Destroyable {
static void Destroy(Arguments* args) {
if (IsDestroyed(args))
return;
v8::Local<v8::Object> holder = args->GetHolder();
delete static_cast<WrappableBase*>(
holder->GetAlignedPointerFromInternalField(0));
holder->SetAlignedPointerInInternalField(0, nullptr);
}
static bool IsDestroyed(Arguments* args) {
v8::Local<v8::Object> holder = args->GetHolder();
return holder->InternalFieldCount() == 0 ||
holder->GetAlignedPointerFromInternalField(0) == nullptr;
}
};
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::Local<v8::External> GetHandle(v8::Isolate* isolate);
protected:
explicit CallbackHolderBase(v8::Isolate* isolate);
virtual ~CallbackHolderBase();
private:
static void FirstWeakCallback(
const v8::WeakCallbackInfo<CallbackHolderBase>& data);
static void SecondWeakCallback(
const v8::WeakCallbackInfo<CallbackHolderBase>& data);
v8::Global<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);
};
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;
}
// Classes for generating and storing an argument pack of integer indices
// (based on well-known "indices trick", see: http://goo.gl/bKKojn):
template <size_t... indices>
struct IndicesHolder {};
template <size_t requested_index, size_t... indices>
struct IndicesGenerator {
using type = typename IndicesGenerator<requested_index - 1,
requested_index - 1,
indices...>::type;
};
template <size_t... indices>
struct IndicesGenerator<0, indices...> {
using type = IndicesHolder<indices...>;
};
// Class template for extracting and storing single argument for callback
// at position |index|.
template <size_t index, typename ArgType>
struct ArgumentHolder {
using ArgLocalType = typename CallbackParamTraits<ArgType>::LocalType;
ArgLocalType value;
bool ok;
ArgumentHolder(Arguments* args, int create_flags)
: ok(false) {
if (index == 0 &&
(create_flags & HolderIsFirstArgument) &&
Destroyable::IsDestroyed(args)) {
args->ThrowError("Object has been destroyed");
return;
}
ok = GetNextArgument(args, create_flags, index == 0, &value);
if (!ok) {
// Ideally we would include the expected c++ type in the error
// message which we can access via typeid(ArgType).name()
// however we compile with no-rtti, which disables typeid.
args->ThrowError();
}
}
};
// Class template for converting arguments from JavaScript to C++ and running
// the callback with them.
template <typename IndicesType, typename... ArgTypes>
class Invoker {};
template <size_t... indices, typename... ArgTypes>
class Invoker<IndicesHolder<indices...>, ArgTypes...>
: public ArgumentHolder<indices, ArgTypes>... {
public:
// Invoker<> inherits from ArgumentHolder<> for each argument.
// C++ has always been strict about the class initialization order,
// so it is guaranteed ArgumentHolders will be initialized (and thus, will
// extract arguments from Arguments) in the right order.
Invoker(Arguments* args, int create_flags)
: ArgumentHolder<indices, ArgTypes>(args, create_flags)..., args_(args) {
// GCC thinks that create_flags is going unused, even though the
// expansion above clearly makes use of it. Per jyasskin@, casting
// to void is the commonly accepted way to convince the compiler
// that you're actually using a parameter/varible.
(void)create_flags;
}
bool IsOK() {
return And(ArgumentHolder<indices, ArgTypes>::ok...);
}
template <typename ReturnType>
void DispatchToCallback(base::Callback<ReturnType(ArgTypes...)> callback) {
v8::MicrotasksScope script_scope(
args_->isolate(), v8::MicrotasksScope::kRunMicrotasks);
args_->Return(callback.Run(ArgumentHolder<indices, ArgTypes>::value...));
}
// 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.
void DispatchToCallback(base::Callback<void(ArgTypes...)> callback) {
v8::MicrotasksScope script_scope(
args_->isolate(), v8::MicrotasksScope::kRunMicrotasks);
callback.Run(ArgumentHolder<indices, ArgTypes>::value...);
}
private:
static bool And() { return true; }
template <typename... T>
static bool And(bool arg1, T... args) {
return arg1 && And(args...);
}
Arguments* args_;
};
// DispatchToCallback converts all the JavaScript arguments to C++ types and
// invokes the base::Callback.
template <typename Sig>
struct Dispatcher {};
template <typename ReturnType, typename... ArgTypes>
struct Dispatcher<ReturnType(ArgTypes...)> {
static void DispatchToCallback(
const v8::FunctionCallbackInfo<v8::Value>& info) {
Arguments args(info);
v8::Local<v8::External> v8_holder;
args.GetData(&v8_holder);
CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
v8_holder->Value());
typedef CallbackHolder<ReturnType(ArgTypes...)> HolderT;
HolderT* holder = static_cast<HolderT*>(holder_base);
using Indices = typename IndicesGenerator<sizeof...(ArgTypes)>::type;
Invoker<Indices, ArgTypes...> invoker(&args, holder->flags);
if (invoker.IsOK())
invoker.DispatchToCallback(holder->callback);
}
};
} // 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 gin::Converter, as is
// the return value of the C++ function, if any.
//
// NOTE: V8 caches FunctionTemplates for a lifetime of a web page for its own
// internal reasons, thus it is generally a good idea to cache the template
// returned by this function. Otherwise, repeated method invocations from JS
// will create substantial memory leaks. See http://crbug.com/463487.
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::Local<v8::External> >(isolate,
holder->GetHandle(isolate)));
}
// CreateFunctionHandler installs a CallAsFunction handler on the given
// object template that forwards to a provided C++ function or base::Callback.
template<typename Sig>
void CreateFunctionHandler(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> tmpl,
const base::Callback<Sig> callback,
int callback_flags = 0) {
typedef internal::CallbackHolder<Sig> HolderT;
HolderT* holder = new HolderT(isolate, callback, callback_flags);
tmpl->SetCallAsFunctionHandler(&internal::Dispatcher<Sig>::DispatchToCallback,
ConvertToV8<v8::Local<v8::External> >(
isolate, holder->GetHandle(isolate)));
}
} // namespace mate
#endif // NATIVE_MATE_FUNCTION_TEMPLATE_H_

Просмотреть файл

@ -0,0 +1,72 @@
// 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::Local<v8::Object> wrapper, T* object)
: wrapper_(wrapper),
object_(object) {
}
bool IsEmpty() const { return !object_; }
void Clear() {
wrapper_.Clear();
object_ = NULL;
}
T* operator->() const { return object_; }
v8::Local<v8::Object> ToV8() const { return wrapper_; }
T* get() const { return object_; }
private:
v8::Local<v8::Object> wrapper_;
T* object_;
};
template<typename T>
struct Converter<mate::Handle<T> > {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const mate::Handle<T>& val) {
return val.ToV8();
}
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
mate::Handle<T>* out) {
T* object = NULL;
if (val->IsNull() || val->IsUndefined()) {
*out = mate::Handle<T>();
return true;
}
if (!Converter<T*>::FromV8(isolate, val, &object)) {
return false;
}
*out = mate::Handle<T>(val->ToObject(), 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(), object);
}
} // namespace mate
#endif // NATIVE_MATE_HANDLE_H_

Просмотреть файл

@ -0,0 +1,44 @@
// 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,
v8::Local<v8::ObjectTemplate> templ)
: isolate_(isolate), template_(templ) {
}
ObjectTemplateBuilder::~ObjectTemplateBuilder() {
}
ObjectTemplateBuilder& ObjectTemplateBuilder::SetImpl(
const base::StringPiece& name, v8::Local<v8::Data> val) {
template_->Set(StringToSymbol(isolate_, name), val);
return *this;
}
ObjectTemplateBuilder& ObjectTemplateBuilder::SetPropertyImpl(
const base::StringPiece& name, v8::Local<v8::FunctionTemplate> getter,
v8::Local<v8::FunctionTemplate> setter) {
template_->SetAccessorProperty(StringToSymbol(isolate_, name), getter,
setter);
return *this;
}
ObjectTemplateBuilder& ObjectTemplateBuilder::MakeDestroyable() {
SetMethod("destroy", base::Bind(internal::Destroyable::Destroy));
SetMethod("isDestroyed", base::Bind(internal::Destroyable::IsDestroyed));
return *this;
}
v8::Local<v8::ObjectTemplate> ObjectTemplateBuilder::Build() {
v8::Local<v8::ObjectTemplate> result = template_;
template_.Clear();
return result;
}
} // namespace mate

Просмотреть файл

@ -0,0 +1,131 @@
// 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 "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::Local<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::Local<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 std::enable_if<
std::is_member_function_pointer<T>::value>::type> {
static v8::Local<v8::FunctionTemplate> CreateTemplate(
v8::Isolate* isolate, T callback) {
int flags = HolderIsFirstArgument;
return CreateFunctionTemplate(isolate, base::Bind(callback), flags);
}
};
// This specialization allows people to construct function templates directly if
// they need to do fancier stuff.
template<>
struct CallbackTraits<v8::Local<v8::FunctionTemplate> > {
static v8::Local<v8::FunctionTemplate> CreateTemplate(
v8::Local<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,
v8::Local<v8::ObjectTemplate> templ);
~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,
T callback) {
return SetImpl(name,
CallbackTraits<T>::CreateTemplate(isolate_, callback));
}
template<typename T>
ObjectTemplateBuilder& SetProperty(const base::StringPiece& name,
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,
T getter,
U setter) {
return SetPropertyImpl(
name,
CallbackTraits<T>::CreateTemplate(isolate_, getter),
CallbackTraits<U>::CreateTemplate(isolate_, setter));
}
// Add "destroy" and "isDestroyed" methods.
ObjectTemplateBuilder& MakeDestroyable();
v8::Local<v8::ObjectTemplate> Build();
private:
ObjectTemplateBuilder& SetImpl(const base::StringPiece& name,
v8::Local<v8::Data> val);
ObjectTemplateBuilder& SetPropertyImpl(
const base::StringPiece& name, v8::Local<v8::FunctionTemplate> getter,
v8::Local<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_

Просмотреть файл

@ -0,0 +1,34 @@
// 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.
#include "native_mate/persistent_dictionary.h"
namespace mate {
PersistentDictionary::PersistentDictionary() {
}
PersistentDictionary::PersistentDictionary(v8::Isolate* isolate,
v8::Local<v8::Object> object)
: handle_(new RefCountedPersistent<v8::Object>(isolate, object)) {
isolate_ = isolate;
}
PersistentDictionary::~PersistentDictionary() {
}
v8::Local<v8::Object> PersistentDictionary::GetHandle() const {
return handle_->NewHandle();
}
bool Converter<PersistentDictionary>::FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
PersistentDictionary* out) {
if (!val->IsObject())
return false;
*out = PersistentDictionary(isolate, v8::Local<v8::Object>::Cast(val));
return true;
}
} // namespace mate

Просмотреть файл

@ -0,0 +1,36 @@
// 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_PERSISTENT_DICTIONARY_H_
#define NATIVE_MATE_PERSISTENT_DICTIONARY_H_
#include "native_mate/dictionary.h"
#include "native_mate/scoped_persistent.h"
namespace mate {
// Like Dictionary, but stores object in persistent handle so you can keep it
// safely on heap.
class PersistentDictionary : public Dictionary {
public:
PersistentDictionary();
PersistentDictionary(v8::Isolate* isolate, v8::Local<v8::Object> object);
virtual ~PersistentDictionary();
v8::Local<v8::Object> GetHandle() const override;
private:
scoped_refptr<RefCountedPersistent<v8::Object> > handle_;
};
template<>
struct Converter<PersistentDictionary> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
PersistentDictionary* out);
};
} // namespace mate
#endif // NATIVE_MATE_PERSISTENT_DICTIONARY_H_

Просмотреть файл

@ -0,0 +1,45 @@
// Copyright (c) 2018 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "native_mate/promise.h"
namespace mate {
Promise::Promise()
: isolate_(NULL) {
}
Promise::Promise(v8::Isolate* isolate)
: isolate_(isolate) {
resolver_ = v8::Promise::Resolver::New(isolate);
}
Promise::~Promise() {
}
Promise Promise::Create(v8::Isolate* isolate) {
return Promise(isolate);
}
Promise Promise::Create() {
return Promise::Create(v8::Isolate::GetCurrent());
}
void Promise::RejectWithErrorMessage(const std::string& string) {
v8::Local<v8::String> error_message =
v8::String::NewFromUtf8(isolate(), string.c_str());
v8::Local<v8::Value> error = v8::Exception::Error(error_message);
resolver_->Reject(mate::ConvertToV8(isolate(), error));
}
v8::Local<v8::Object> Promise::GetHandle() const {
return resolver_->GetPromise();
}
v8::Local<v8::Value> Converter<Promise>::ToV8(v8::Isolate* isolate,
Promise val) {
return val.GetHandle();
}
} // namespace mate

Просмотреть файл

@ -0,0 +1,57 @@
// Copyright (c) 2018 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef NATIVE_MATE_PROMISE_H_
#define NATIVE_MATE_PROMISE_H_
#include "native_mate/converter.h"
namespace mate {
class Promise {
public:
Promise();
Promise(v8::Isolate* isolate);
virtual ~Promise();
static Promise Create(v8::Isolate* isolate);
static Promise Create();
v8::Isolate* isolate() const { return isolate_; }
virtual v8::Local<v8::Object> GetHandle() const;
template<typename T>
void Resolve(T* value) {
resolver_->Resolve(mate::ConvertToV8(isolate(), value));
}
template<typename T>
void Reject(T* value) {
resolver_->Reject(mate::ConvertToV8(isolate(), value));
}
void RejectWithErrorMessage(const std::string& error);
protected:
v8::Isolate* isolate_;
private:
v8::Local<v8::Promise::Resolver> resolver_;
};
template<>
struct Converter<Promise> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
Promise val);
// TODO(MarshallOfSound): Implement FromV8 to allow promise chaining
// in native land
// static bool FromV8(v8::Isolate* isolate,
// v8::Local<v8::Value> val,
// Promise* out);
};
} // namespace mate
#endif // NATIVE_MATE_PROMISE_H_

Просмотреть файл

@ -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 "native_mate/converter.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() : isolate_(v8::Isolate::GetCurrent()) {}
ScopedPersistent(v8::Isolate* isolate, v8::Local<v8::Value> handle)
: isolate_(isolate) {
reset(isolate, v8::Local<T>::Cast(handle));
}
~ScopedPersistent() {
reset();
}
void reset(v8::Isolate* isolate, v8::Local<T> handle) {
if (!handle.IsEmpty()) {
isolate_ = isolate;
handle_.Reset(isolate, handle);
} else {
reset();
}
}
void reset() {
handle_.Reset();
}
bool IsEmpty() const {
return handle_.IsEmpty();
}
v8::Local<T> NewHandle() const {
return NewHandle(isolate_);
}
v8::Local<T> NewHandle(v8::Isolate* isolate) const {
if (handle_.IsEmpty())
return v8::Local<T>();
return v8::Local<T>::New(isolate, handle_);
}
template<typename P, typename C>
void SetWeak(P* parameter, C callback) {
handle_.SetWeak(parameter, callback);
}
v8::Isolate* isolate() const { return isolate_; }
private:
v8::Isolate* isolate_;
v8::Persistent<T> handle_;
DISALLOW_COPY_AND_ASSIGN(ScopedPersistent);
};
template <typename T>
class RefCountedPersistent : public ScopedPersistent<T>,
public base::RefCounted<RefCountedPersistent<T>> {
public:
RefCountedPersistent() {}
RefCountedPersistent(v8::Isolate* isolate, v8::Local<v8::Value> handle)
: ScopedPersistent<T>(isolate, handle) {
}
protected:
friend class base::RefCounted<RefCountedPersistent<T>>;
~RefCountedPersistent() {}
private:
DISALLOW_COPY_AND_ASSIGN(RefCountedPersistent);
};
template<typename T>
struct Converter<ScopedPersistent<T> > {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const ScopedPersistent<T>& val) {
return val.NewHandle(isolate);
}
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
ScopedPersistent<T>* out) {
v8::Local<T> converted;
if (!Converter<v8::Local<T> >::FromV8(isolate, val, &converted))
return false;
out->reset(isolate, converted);
return true;
}
};
} // namespace mate
#endif // NATIVE_MATE_SCOPED_PERSISTENT_H_

Просмотреть файл

@ -0,0 +1,75 @@
// 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/dictionary.h"
#include "native_mate/object_template_builder.h"
namespace mate {
WrappableBase::WrappableBase() : isolate_(nullptr) {}
WrappableBase::~WrappableBase() {
if (wrapper_.IsEmpty())
return;
GetWrapper()->SetAlignedPointerInInternalField(0, nullptr);
wrapper_.ClearWeak();
wrapper_.Reset();
}
v8::Local<v8::Object> WrappableBase::GetWrapper() const {
if (!wrapper_.IsEmpty())
return v8::Local<v8::Object>::New(isolate_, wrapper_);
else
return v8::Local<v8::Object>();
}
void WrappableBase::InitWith(v8::Isolate* isolate,
v8::Local<v8::Object> wrapper) {
CHECK(wrapper_.IsEmpty());
isolate_ = isolate;
wrapper->SetAlignedPointerInInternalField(0, this);
wrapper_.Reset(isolate, wrapper);
wrapper_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
// Call object._init if we have one.
v8::Local<v8::Function> init;
if (Dictionary(isolate, wrapper).Get("_init", &init))
init->Call(wrapper, 0, nullptr);
AfterInit(isolate);
}
// static
void WrappableBase::FirstWeakCallback(
const v8::WeakCallbackInfo<WrappableBase>& data) {
WrappableBase* wrappable = data.GetParameter();
wrappable->wrapper_.Reset();
data.SetSecondPassCallback(SecondWeakCallback);
}
// static
void WrappableBase::SecondWeakCallback(
const v8::WeakCallbackInfo<WrappableBase>& data) {
WrappableBase* wrappable = data.GetParameter();
delete wrappable;
}
namespace internal {
void* FromV8Impl(v8::Isolate* isolate, v8::Local<v8::Value> val) {
if (!val->IsObject())
return nullptr;
v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(val);
if (obj->InternalFieldCount() != 1)
return nullptr;
return obj->GetAlignedPointerFromInternalField(0);
}
} // namespace internal
} // namespace mate

Просмотреть файл

@ -0,0 +1,99 @@
// 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/bind.h"
#include "native_mate/converter.h"
#include "native_mate/constructor.h"
#include "gin/per_isolate_data.h"
namespace mate {
namespace internal {
void* FromV8Impl(v8::Isolate* isolate, v8::Local<v8::Value> val);
} // namespace internal
template<typename T>
class Wrappable : public WrappableBase {
public:
Wrappable() {}
template<typename Sig>
static void SetConstructor(v8::Isolate* isolate,
const base::Callback<Sig>& constructor) {
v8::Local<v8::FunctionTemplate> templ = CreateFunctionTemplate(
isolate, base::Bind(&internal::InvokeNew<Sig>, constructor));
templ->InstanceTemplate()->SetInternalFieldCount(1);
T::BuildPrototype(isolate, templ);
gin::PerIsolateData::From(isolate)->SetFunctionTemplate(
&kWrapperInfo, templ);
}
static v8::Local<v8::FunctionTemplate> GetConstructor(v8::Isolate* isolate) {
// Fill the object template.
auto data = gin::PerIsolateData::From(isolate);
auto templ = data->GetFunctionTemplate(&kWrapperInfo);
if (templ.IsEmpty()) {
templ = v8::FunctionTemplate::New(isolate);
templ->InstanceTemplate()->SetInternalFieldCount(1);
T::BuildPrototype(isolate, templ);
data->SetFunctionTemplate(&kWrapperInfo, templ);
}
return templ;
}
protected:
// Init the class with T::BuildPrototype.
void Init(v8::Isolate* isolate) {
v8::Local<v8::FunctionTemplate> templ = GetConstructor(isolate);
// |wrapper| may be empty in some extreme cases, e.g., when
// Object.prototype.constructor is overwritten.
v8::Local<v8::Object> wrapper;
if (!templ->InstanceTemplate()->NewInstance(
isolate->GetCurrentContext()).ToLocal(&wrapper)) {
// The current wrappable object will be no longer managed by V8. Delete
// this now.
delete this;
return;
}
InitWith(isolate, wrapper);
}
private:
static gin::WrapperInfo kWrapperInfo;
DISALLOW_COPY_AND_ASSIGN(Wrappable);
};
// static
template<typename T>
gin::WrapperInfo Wrappable<T>::kWrapperInfo = { gin::kEmbedderNativeGin };
// This converter handles any subclass of Wrappable.
template <typename T>
struct Converter<T*,
typename std::enable_if<
std::is_convertible<T*, WrappableBase*>::value>::type> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, T* val) {
if (val)
return val->GetWrapper();
else
return v8::Null(isolate);
}
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val, T** out) {
*out = static_cast<T*>(static_cast<WrappableBase*>(
internal::FromV8Impl(isolate, val)));
return *out != nullptr;
}
};
} // namespace mate
#endif // NATIVE_MATE_WRAPPABLE_H_

Просмотреть файл

@ -0,0 +1,61 @@
#ifndef NATIVE_MATE_WRAPPABLE_BASE_H_
#define NATIVE_MATE_WRAPPABLE_BASE_H_
namespace mate {
namespace internal {
struct Destroyable;
}
// Wrappable is a base class for C++ objects that have corresponding v8 wrapper
// objects. To retain a Wrappable object on the stack, use a gin::Handle.
//
// USAGE:
// // my_class.h
// class MyClass : Wrappable<MyClass> {
// public:
// ...
// };
//
// 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 WrappableBase {
public:
WrappableBase();
virtual ~WrappableBase();
// Retrieve the v8 wrapper object cooresponding to this object.
v8::Local<v8::Object> GetWrapper() const;
// Returns the Isolate this object is created in.
v8::Isolate* isolate() const { return isolate_; }
protected:
// Called after the "_init" method gets called in JavaScript.
virtual void AfterInit(v8::Isolate* isolate) {}
// Bind the C++ class to the JS wrapper.
// This method should only be called by classes using Constructor.
virtual void InitWith(v8::Isolate* isolate, v8::Local<v8::Object> wrapper);
private:
friend struct internal::Destroyable;
static void FirstWeakCallback(
const v8::WeakCallbackInfo<WrappableBase>& data);
static void SecondWeakCallback(
const v8::WeakCallbackInfo<WrappableBase>& data);
v8::Isolate* isolate_;
v8::Global<v8::Object> wrapper_; // Weak
DISALLOW_COPY_AND_ASSIGN(WrappableBase);
};
} // namespace mate
#endif // NATIVE_MATE_WRAPPABLE_BASE_H_

Просмотреть файл

@ -0,0 +1,26 @@
{
'variables': {
'native_mate_files': [
'native_mate/arguments.cc',
'native_mate/arguments.h',
'native_mate/constructor.h',
'native_mate/converter.cc',
'native_mate/converter.h',
'native_mate/dictionary.cc',
'native_mate/dictionary.h',
'native_mate/function_template.cc',
'native_mate/function_template.h',
'native_mate/handle.h',
'native_mate/object_template_builder.cc',
'native_mate/object_template_builder.h',
'native_mate/persistent_dictionary.cc',
'native_mate/persistent_dictionary.h',
'native_mate/scoped_persistent.h',
'native_mate/wrappable.cc',
'native_mate/wrappable.h',
'native_mate/wrappable_base.h',
'native_mate/promise.h',
'native_mate/promise.cc',
],
},
}

855
script/pump.py Executable file
Просмотреть файл

@ -0,0 +1,855 @@
#!/usr/bin/env python
#
# Copyright 2008, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""pump v0.2.0 - Pretty Useful for Meta Programming.
A tool for preprocessor meta programming. Useful for generating
repetitive boilerplate code. Especially useful for writing C++
classes, functions, macros, and templates that need to work with
various number of arguments.
USAGE:
pump.py SOURCE_FILE
EXAMPLES:
pump.py foo.cc.pump
Converts foo.cc.pump to foo.cc.
GRAMMAR:
CODE ::= ATOMIC_CODE*
ATOMIC_CODE ::= $var ID = EXPRESSION
| $var ID = [[ CODE ]]
| $range ID EXPRESSION..EXPRESSION
| $for ID SEPARATOR [[ CODE ]]
| $($)
| $ID
| $(EXPRESSION)
| $if EXPRESSION [[ CODE ]] ELSE_BRANCH
| [[ CODE ]]
| RAW_CODE
SEPARATOR ::= RAW_CODE | EMPTY
ELSE_BRANCH ::= $else [[ CODE ]]
| $elif EXPRESSION [[ CODE ]] ELSE_BRANCH
| EMPTY
EXPRESSION has Python syntax.
"""
__author__ = 'wan@google.com (Zhanyong Wan)'
import os
import re
import sys
TOKEN_TABLE = [
(re.compile(r'\$var\s+'), '$var'),
(re.compile(r'\$elif\s+'), '$elif'),
(re.compile(r'\$else\s+'), '$else'),
(re.compile(r'\$for\s+'), '$for'),
(re.compile(r'\$if\s+'), '$if'),
(re.compile(r'\$range\s+'), '$range'),
(re.compile(r'\$[_A-Za-z]\w*'), '$id'),
(re.compile(r'\$\(\$\)'), '$($)'),
(re.compile(r'\$'), '$'),
(re.compile(r'\[\[\n?'), '[['),
(re.compile(r'\]\]\n?'), ']]'),
]
class Cursor:
"""Represents a position (line and column) in a text file."""
def __init__(self, line=-1, column=-1):
self.line = line
self.column = column
def __eq__(self, rhs):
return self.line == rhs.line and self.column == rhs.column
def __ne__(self, rhs):
return not self == rhs
def __lt__(self, rhs):
return self.line < rhs.line or (
self.line == rhs.line and self.column < rhs.column)
def __le__(self, rhs):
return self < rhs or self == rhs
def __gt__(self, rhs):
return rhs < self
def __ge__(self, rhs):
return rhs <= self
def __str__(self):
if self == Eof():
return 'EOF'
else:
return '%s(%s)' % (self.line + 1, self.column)
def __add__(self, offset):
return Cursor(self.line, self.column + offset)
def __sub__(self, offset):
return Cursor(self.line, self.column - offset)
def Clone(self):
"""Returns a copy of self."""
return Cursor(self.line, self.column)
# Special cursor to indicate the end-of-file.
def Eof():
"""Returns the special cursor to denote the end-of-file."""
return Cursor(-1, -1)
class Token:
"""Represents a token in a Pump source file."""
def __init__(self, start=None, end=None, value=None, token_type=None):
if start is None:
self.start = Eof()
else:
self.start = start
if end is None:
self.end = Eof()
else:
self.end = end
self.value = value
self.token_type = token_type
def __str__(self):
return 'Token @%s: \'%s\' type=%s' % (
self.start, self.value, self.token_type)
def Clone(self):
"""Returns a copy of self."""
return Token(self.start.Clone(), self.end.Clone(), self.value,
self.token_type)
def StartsWith(lines, pos, string):
"""Returns True iff the given position in lines starts with 'string'."""
return lines[pos.line][pos.column:].startswith(string)
def FindFirstInLine(line, token_table):
best_match_start = -1
for (regex, token_type) in token_table:
m = regex.search(line)
if m:
# We found regex in lines
if best_match_start < 0 or m.start() < best_match_start:
best_match_start = m.start()
best_match_length = m.end() - m.start()
best_match_token_type = token_type
if best_match_start < 0:
return None
return (best_match_start, best_match_length, best_match_token_type)
def FindFirst(lines, token_table, cursor):
"""Finds the first occurrence of any string in strings in lines."""
start = cursor.Clone()
cur_line_number = cursor.line
for line in lines[start.line:]:
if cur_line_number == start.line:
line = line[start.column:]
m = FindFirstInLine(line, token_table)
if m:
# We found a regex in line.
(start_column, length, token_type) = m
if cur_line_number == start.line:
start_column += start.column
found_start = Cursor(cur_line_number, start_column)
found_end = found_start + length
return MakeToken(lines, found_start, found_end, token_type)
cur_line_number += 1
# We failed to find str in lines
return None
def SubString(lines, start, end):
"""Returns a substring in lines."""
if end == Eof():
end = Cursor(len(lines) - 1, len(lines[-1]))
if start >= end:
return ''
if start.line == end.line:
return lines[start.line][start.column:end.column]
result_lines = ([lines[start.line][start.column:]] +
lines[start.line + 1:end.line] +
[lines[end.line][:end.column]])
return ''.join(result_lines)
def StripMetaComments(_str):
"""Strip meta comments from each line in the given string."""
# First, completely remove lines containing nothing but a meta
# comment, including the trailing \n.
_str = re.sub(r'^\s*\$\$.*\n', '', _str)
# Then, remove meta comments from contentful lines.
return re.sub(r'\s*\$\$.*', '', _str)
def MakeToken(lines, start, end, token_type):
"""Creates a new instance of Token."""
return Token(start, end, SubString(lines, start, end), token_type)
def ParseToken(lines, pos, regex, token_type):
line = lines[pos.line][pos.column:]
m = regex.search(line)
if m and not m.start():
return MakeToken(lines, pos, pos + m.end(), token_type)
else:
print 'ERROR: %s expected at %s.' % (token_type, pos)
sys.exit(1)
ID_REGEX = re.compile(r'[_A-Za-z]\w*')
EQ_REGEX = re.compile(r'=')
REST_OF_LINE_REGEX = re.compile(r'.*?(?=$|\$\$)')
OPTIONAL_WHITE_SPACES_REGEX = re.compile(r'\s*')
WHITE_SPACE_REGEX = re.compile(r'\s')
DOT_DOT_REGEX = re.compile(r'\.\.')
def Skip(lines, pos, regex):
line = lines[pos.line][pos.column:]
m = re.search(regex, line)
if m and not m.start():
return pos + m.end()
else:
return pos
def SkipUntil(lines, pos, regex, token_type):
line = lines[pos.line][pos.column:]
m = re.search(regex, line)
if m:
return pos + m.start()
else:
print ('ERROR: %s expected on line %s after column %s.' %
(token_type, pos.line + 1, pos.column))
sys.exit(1)
def ParseExpTokenInParens(lines, pos):
def ParseInParens(pos):
pos = Skip(lines, pos, OPTIONAL_WHITE_SPACES_REGEX)
pos = Skip(lines, pos, r'\(')
pos = Parse(pos)
pos = Skip(lines, pos, r'\)')
return pos
def Parse(pos):
pos = SkipUntil(lines, pos, r'\(|\)', ')')
if SubString(lines, pos, pos + 1) == '(':
pos = Parse(pos + 1)
pos = Skip(lines, pos, r'\)')
return Parse(pos)
else:
return pos
start = pos.Clone()
pos = ParseInParens(pos)
return MakeToken(lines, start, pos, 'exp')
def RStripNewLineFromToken(token):
if token.value.endswith('\n'):
return Token(token.start, token.end, token.value[:-1], token.token_type)
else:
return token
def TokenizeLines(lines, pos):
while True:
found = FindFirst(lines, TOKEN_TABLE, pos)
if not found:
yield MakeToken(lines, pos, Eof(), 'code')
return
if found.start == pos:
prev_token = None
prev_token_rstripped = None
else:
prev_token = MakeToken(lines, pos, found.start, 'code')
prev_token_rstripped = RStripNewLineFromToken(prev_token)
if found.token_type == '$var':
if prev_token_rstripped:
yield prev_token_rstripped
yield found
id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
yield id_token
pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX)
eq_token = ParseToken(lines, pos, EQ_REGEX, '=')
yield eq_token
pos = Skip(lines, eq_token.end, r'\s*')
if SubString(lines, pos, pos + 2) != '[[':
exp_token = ParseToken(lines, pos, REST_OF_LINE_REGEX, 'exp')
yield exp_token
pos = Cursor(exp_token.end.line + 1, 0)
elif found.token_type == '$for':
if prev_token_rstripped:
yield prev_token_rstripped
yield found
id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
yield id_token
pos = Skip(lines, id_token.end, WHITE_SPACE_REGEX)
elif found.token_type == '$range':
if prev_token_rstripped:
yield prev_token_rstripped
yield found
id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
yield id_token
pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX)
dots_pos = SkipUntil(lines, pos, DOT_DOT_REGEX, '..')
yield MakeToken(lines, pos, dots_pos, 'exp')
yield MakeToken(lines, dots_pos, dots_pos + 2, '..')
pos = dots_pos + 2
new_pos = Cursor(pos.line + 1, 0)
yield MakeToken(lines, pos, new_pos, 'exp')
pos = new_pos
elif found.token_type == '$':
if prev_token:
yield prev_token
yield found
exp_token = ParseExpTokenInParens(lines, found.end)
yield exp_token
pos = exp_token.end
elif (found.token_type == ']]' or found.token_type == '$if' or
found.token_type == '$elif' or found.token_type == '$else'):
if prev_token_rstripped:
yield prev_token_rstripped
yield found
pos = found.end
else:
if prev_token:
yield prev_token
yield found
pos = found.end
def Tokenize(s):
"""A generator that yields the tokens in the given string."""
if s != '':
lines = s.splitlines(True)
for token in TokenizeLines(lines, Cursor(0, 0)):
yield token
class CodeNode:
def __init__(self, atomic_code_list=None):
self.atomic_code = atomic_code_list
class VarNode:
def __init__(self, identifier=None, atomic_code=None):
self.identifier = identifier
self.atomic_code = atomic_code
class RangeNode:
def __init__(self, identifier=None, exp1=None, exp2=None):
self.identifier = identifier
self.exp1 = exp1
self.exp2 = exp2
class ForNode:
def __init__(self, identifier=None, sep=None, code=None):
self.identifier = identifier
self.sep = sep
self.code = code
class ElseNode:
def __init__(self, else_branch=None):
self.else_branch = else_branch
class IfNode:
def __init__(self, exp=None, then_branch=None, else_branch=None):
self.exp = exp
self.then_branch = then_branch
self.else_branch = else_branch
class RawCodeNode:
def __init__(self, token=None):
self.raw_code = token
class LiteralDollarNode:
def __init__(self, token):
self.token = token
class ExpNode:
def __init__(self, token, python_exp):
self.token = token
self.python_exp = python_exp
def PopFront(a_list):
head = a_list[0]
a_list[:1] = []
return head
def PushFront(a_list, elem):
a_list[:0] = [elem]
def PopToken(a_list, token_type=None):
token = PopFront(a_list)
if token_type is not None and token.token_type != token_type:
print 'ERROR: %s expected at %s' % (token_type, token.start)
print 'ERROR: %s found instead' % (token,)
sys.exit(1)
return token
def PeekToken(a_list):
if not a_list:
return None
return a_list[0]
def ParseExpNode(token):
python_exp = re.sub(r'([_A-Za-z]\w*)', r'self.GetValue("\1")', token.value)
return ExpNode(token, python_exp)
def ParseElseNode(tokens):
def Pop(token_type=None):
return PopToken(tokens, token_type)
_next = PeekToken(tokens)
if not next:
return None
if _next.token_type == '$else':
Pop('$else')
Pop('[[')
code_node = ParseCodeNode(tokens)
Pop(']]')
return code_node
elif _next.token_type == '$elif':
Pop('$elif')
exp = Pop('code')
Pop('[[')
code_node = ParseCodeNode(tokens)
Pop(']]')
inner_else_node = ParseElseNode(tokens)
return CodeNode([IfNode(ParseExpNode(exp), code_node, inner_else_node)])
elif not _next.value.strip():
Pop('code')
return ParseElseNode(tokens)
else:
return None
def ParseAtomicCodeNode(tokens):
def Pop(token_type=None):
return PopToken(tokens, token_type)
head = PopFront(tokens)
t = head.token_type
if t == 'code':
return RawCodeNode(head)
elif t == '$var':
id_token = Pop('id')
Pop('=')
_next = PeekToken(tokens)
if _next.token_type == 'exp':
exp_token = Pop()
return VarNode(id_token, ParseExpNode(exp_token))
Pop('[[')
code_node = ParseCodeNode(tokens)
Pop(']]')
return VarNode(id_token, code_node)
elif t == '$for':
id_token = Pop('id')
next_token = PeekToken(tokens)
if next_token.token_type == 'code':
sep_token = next_token
Pop('code')
else:
sep_token = None
Pop('[[')
code_node = ParseCodeNode(tokens)
Pop(']]')
return ForNode(id_token, sep_token, code_node)
elif t == '$if':
exp_token = Pop('code')
Pop('[[')
code_node = ParseCodeNode(tokens)
Pop(']]')
else_node = ParseElseNode(tokens)
return IfNode(ParseExpNode(exp_token), code_node, else_node)
elif t == '$range':
id_token = Pop('id')
exp1_token = Pop('exp')
Pop('..')
exp2_token = Pop('exp')
return RangeNode(id_token, ParseExpNode(exp1_token),
ParseExpNode(exp2_token))
elif t == '$id':
return ParseExpNode(Token(head.start + 1, head.end, head.value[1:], 'id'))
elif t == '$($)':
return LiteralDollarNode(head)
elif t == '$':
exp_token = Pop('exp')
return ParseExpNode(exp_token)
elif t == '[[':
code_node = ParseCodeNode(tokens)
Pop(']]')
return code_node
else:
PushFront(tokens, head)
return None
def ParseCodeNode(tokens):
atomic_code_list = []
while True:
if not tokens:
break
atomic_code_node = ParseAtomicCodeNode(tokens)
if atomic_code_node:
atomic_code_list.append(atomic_code_node)
else:
break
return CodeNode(atomic_code_list)
def ParseToAST(pump_src_text):
"""Convert the given Pump source text into an AST."""
tokens = list(Tokenize(pump_src_text))
code_node = ParseCodeNode(tokens)
return code_node
class Env:
def __init__(self):
self.variables = []
self.ranges = []
def Clone(self):
clone = Env()
clone.variables = self.variables[:]
clone.ranges = self.ranges[:]
return clone
def PushVariable(self, var, value):
# If value looks like an int, store it as an int.
try:
int_value = int(value)
if ('%s' % int_value) == value:
value = int_value
except Exception:
pass
self.variables[:0] = [(var, value)]
def PopVariable(self):
self.variables[:1] = []
def PushRange(self, var, lower, upper):
self.ranges[:0] = [(var, lower, upper)]
def PopRange(self):
self.ranges[:1] = []
def GetValue(self, identifier):
for (var, value) in self.variables:
if identifier == var:
return value
print 'ERROR: meta variable %s is undefined.' % (identifier,)
sys.exit(1)
def EvalExp(self, exp):
try:
result = eval(exp.python_exp)
except Exception, e:
print 'ERROR: caught exception %s: %s' % (e.__class__.__name__, e)
print ('ERROR: failed to evaluate meta expression %s at %s' %
(exp.python_exp, exp.token.start))
sys.exit(1)
return result
def GetRange(self, identifier):
for (var, lower, upper) in self.ranges:
if identifier == var:
return (lower, upper)
print 'ERROR: range %s is undefined.' % (identifier,)
sys.exit(1)
class Output:
def __init__(self):
self.string = ''
def GetLastLine(self):
index = self.string.rfind('\n')
if index < 0:
return ''
return self.string[index + 1:]
def Append(self, s):
self.string += s
def RunAtomicCode(env, node, output):
if isinstance(node, VarNode):
identifier = node.identifier.value.strip()
result = Output()
RunAtomicCode(env.Clone(), node.atomic_code, result)
value = result.string
env.PushVariable(identifier, value)
elif isinstance(node, RangeNode):
identifier = node.identifier.value.strip()
lower = int(env.EvalExp(node.exp1))
upper = int(env.EvalExp(node.exp2))
env.PushRange(identifier, lower, upper)
elif isinstance(node, ForNode):
identifier = node.identifier.value.strip()
if node.sep is None:
sep = ''
else:
sep = node.sep.value
(lower, upper) = env.GetRange(identifier)
for i in range(lower, upper + 1):
new_env = env.Clone()
new_env.PushVariable(identifier, i)
RunCode(new_env, node.code, output)
if i != upper:
output.Append(sep)
elif isinstance(node, RawCodeNode):
output.Append(node.raw_code.value)
elif isinstance(node, IfNode):
cond = env.EvalExp(node.exp)
if cond:
RunCode(env.Clone(), node.then_branch, output)
elif node.else_branch is not None:
RunCode(env.Clone(), node.else_branch, output)
elif isinstance(node, ExpNode):
value = env.EvalExp(node)
output.Append('%s' % (value,))
elif isinstance(node, LiteralDollarNode):
output.Append('$')
elif isinstance(node, CodeNode):
RunCode(env.Clone(), node, output)
else:
print 'BAD'
print node
sys.exit(1)
def RunCode(env, code_node, output):
for atomic_code in code_node.atomic_code:
RunAtomicCode(env, atomic_code, output)
def IsSingleLineComment(cur_line):
return '//' in cur_line
def IsInPreprocessorDirective(prev_lines, cur_line):
if cur_line.lstrip().startswith('#'):
return True
return prev_lines and prev_lines[-1].endswith('\\')
def WrapComment(line, output):
loc = line.find('//')
before_comment = line[:loc].rstrip()
if before_comment == '':
indent = loc
else:
output.append(before_comment)
indent = len(before_comment) - len(before_comment.lstrip())
prefix = indent*' ' + '// '
max_len = 80 - len(prefix)
comment = line[loc + 2:].strip()
segs = [seg for seg in re.split(r'(\w+\W*)', comment) if seg != '']
cur_line = ''
for seg in segs:
if len((cur_line + seg).rstrip()) < max_len:
cur_line += seg
else:
if cur_line.strip() != '':
output.append(prefix + cur_line.rstrip())
cur_line = seg.lstrip()
if cur_line.strip() != '':
output.append(prefix + cur_line.strip())
def WrapCode(line, line_concat, output):
indent = len(line) - len(line.lstrip())
prefix = indent*' ' # Prefix of the current line
max_len = 80 - indent - len(line_concat) # Maximum length of the current line
new_prefix = prefix + 4*' ' # Prefix of a continuation line
new_max_len = max_len - 4 # Maximum length of a continuation line
# Prefers to wrap a line after a ',' or ';'.
segs = [seg for seg in re.split(r'([^,;]+[,;]?)', line.strip()) if seg != '']
cur_line = '' # The current line without leading spaces.
for seg in segs:
# If the line is still too long, wrap at a space.
while cur_line == '' and len(seg.strip()) > max_len:
seg = seg.lstrip()
split_at = seg.rfind(' ', 0, max_len)
output.append(prefix + seg[:split_at].strip() + line_concat)
seg = seg[split_at + 1:]
prefix = new_prefix
max_len = new_max_len
if len((cur_line + seg).rstrip()) < max_len:
cur_line = (cur_line + seg).lstrip()
else:
output.append(prefix + cur_line.rstrip() + line_concat)
prefix = new_prefix
max_len = new_max_len
cur_line = seg.lstrip()
if cur_line.strip() != '':
output.append(prefix + cur_line.strip())
def WrapPreprocessorDirective(line, output):
WrapCode(line, ' \\', output)
def WrapPlainCode(line, output):
WrapCode(line, '', output)
def IsMultiLineIWYUPragma(line):
return re.search(r'/\* IWYU pragma: ', line)
def IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
return (re.match(r'^#(ifndef|define|endif\s*//)\s*[\w_]+\s*$', line) or
re.match(r'^#include\s', line) or
# Don't break IWYU pragmas, either; that causes iwyu.py problems.
re.search(r'// IWYU pragma: ', line))
def WrapLongLine(line, output):
line = line.rstrip()
if len(line) <= 80:
output.append(line)
elif IsSingleLineComment(line):
if IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
# The style guide made an exception to allow long header guard lines,
# includes and IWYU pragmas.
output.append(line)
else:
WrapComment(line, output)
elif IsInPreprocessorDirective(output, line):
if IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
# The style guide made an exception to allow long header guard lines,
# includes and IWYU pragmas.
output.append(line)
else:
WrapPreprocessorDirective(line, output)
elif IsMultiLineIWYUPragma(line):
output.append(line)
else:
WrapPlainCode(line, output)
def BeautifyCode(string):
lines = string.splitlines()
output = []
for line in lines:
WrapLongLine(line, output)
output2 = [line.rstrip() for line in output]
return '\n'.join(output2) + '\n'
def ConvertFromPumpSource(src_text):
"""Return the text generated from the given Pump source text."""
ast = ParseToAST(StripMetaComments(src_text))
output = Output()
RunCode(Env(), ast, output)
return BeautifyCode(output.string)
def main(argv):
if len(argv) == 1:
print __doc__
sys.exit(1)
file_path = argv[-1]
output_str = ConvertFromPumpSource(file(file_path, 'r').read())
if file_path.endswith('.pump'):
output_file_path = file_path[:-5]
else:
output_file_path = '-'
if output_file_path == '-':
print output_str,
else:
output_file = file(output_file_path, 'w')
output_file.write('// This file was GENERATED by command:\n')
output_file.write('// %s %s\n' %
(os.path.basename(__file__), os.path.basename(file_path)))
output_file.write('// DO NOT EDIT BY HAND!!!\n\n')
output_file.write(output_str)
output_file.close()
if __name__ == '__main__':
main(sys.argv)

1
vendor/native_mate поставляемый

@ -1 +0,0 @@
Subproject commit 875706f66008e03a0c7a699de16d7e2bde0efb90