emscripten の bind で JavaScript オブジェクトを返す方法

2017-05-13 | [Programming]

概要

emscripten を使うと,C++ のコードを JavaScript に変換することができる. さらに,Embind を使うと,C++ のコード中の関数などを JavaScript のコードから「自然に」呼び出すことができる. 例えば,C++ の関数の引数や戻り値として JavaScript のオブジェクトを使うことができる. ここでは,C++ から JavaScript オブジェクトを返す方法についてまとめておく.

int, std::string

intstd::string を返す C++ 関数は,そのまま bind できる. JavaScript からは,int は数値型に,std::stringString に見える.

#include <emscripten.h>

#include <emscripten/bind.h>

#include <string>


using namespace emscripten;

int hoge() {
	return 42;
}
std::string fuga() {
	return "fuga";
}
EMSCRIPTEN_BINDINGS(mod) {
	function("hoge", &hoge);
	function("fuga", &fuga);
}

JavaScript オブジェクトの操作

emscripten では,C++ から JavaScript オブジェクトを操作するために emscripten::val 型が用意されている. 使い方は ここ とか ここ に書かれている.

例えば,

#include <emscripten.h>

#include <emscripten/bind.h>


using namespace emscripten;

val hoge(int i) {
	val ret = val::object();
	ret.set("height", val(i + 1));
	ret.set("width", val(i + 100));
	return ret;
}
EMSCRIPTEN_BINDINGS(mod) {
	function("hoge", &hoge);
}

このコードを用いて,JavaScript から Module.hoge(100) を呼び出すと, Object { height: 101, width: 200 } が得られる.

注意点として,プロパティの設定には set を用いないといけない. 例えば,ret.set("height", val(i + 1)); の代わりに ret["height"] = val(i + 1); と書いても,height は正しく設定されない.

配列

配列の要素の設定も,set を用いて行うことができる.

#include <emscripten.h>

#include <emscripten/bind.h>


using namespace emscripten;

val hoge(int i) {
	val ret = val::object();
	ret.set("height", val(i + 1));
	ret.set("width", val(i + 100));
	ret.set("data", val::array());
	for (int x = 0; x < 10; ++x) {
		ret["data"].set(x, x);
	}
	return ret;
}
EMSCRIPTEN_BINDINGS(mod) {
	function("hoge", &hoge);
}

val::call を使えば,push などを使って操作することもできる.

#include <emscripten.h>

#include <emscripten/bind.h>


using namespace emscripten;

val hoge(int i) {
	val ret = val::object();
	ret.set("height", val(i + 1));
	ret.set("width", val(i + 100));
	ret.set("data", val::array());
	for (int x = 0; x < 10; ++x) {
		ret["data"].call<val>("push", val(x));
	}
	return ret;
}
EMSCRIPTEN_BINDINGS(mod) {
	function("hoge", &hoge);
}