support two-way identity mapping

This commit is contained in:
Charles Lowell 2012-06-11 05:06:07 -05:00
parent 6dbd647680
commit 6157d35d4a
5 changed files with 78 additions and 16 deletions

View File

@ -2,11 +2,18 @@
namespace rr {
void Template::Init() {
ClassBuilder("Template");
ClassBuilder("Template").
defineMethod("Set", &Set);
ObjectTemplate::Init();
FunctionTemplate::Init();
}
VALUE Template::Set(int argc, VALUE argv[], VALUE self) {
VALUE name; VALUE value; VALUE attributes;
rb_scan_args(argc, argv, "21", &name, &value, &attributes);
Void(Template(self)->Set(*String(name), *Value(value), PropertyAttribute(attributes)));
}
void ObjectTemplate::Init() {
ClassBuilder("ObjectTemplate", "Template").
defineSingletonMethod("New", &New).

View File

@ -1,6 +1,6 @@
module V8
class Context
attr_reader :native
attr_reader :native, :conversion
def initialize
@native = V8::C::Context::New()
@ -15,6 +15,14 @@ module V8
@conversion.to_v8(ruby_object)
end
def link(ruby_object, v8_object)
@conversion.equate ruby_object, v8_object
end
def self.link(*args)
current.link *args
end
def enter(&block)
if !entered?
lock_scope_and_enter(&block)

View File

@ -1,30 +1,57 @@
class V8::Conversion
module Identity
def to_ruby(v8_object)
v8_idmap.lookup(v8_object) {super}
v8_idmap[v8_object] || super
end
def to_v8(ruby_object)
rb_idmap[ruby_object] || super
end
def equate(ruby_object, v8_object)
v8_idmap.equate(v8_object, ruby_object)
rb_idmap.equate(ruby_object, v8_object)
end
def v8_idmap
@v8_idmap ||= V8IDMap.new
end
class V8IDMap
def rb_idmap
@ruby_idmap ||= RubyIDMap.new
end
class IDMap
def initialize
@storage = {}
@map = {}
end
def lookup(v8_object)
if v8_object.is_a?(V8::C::Object)
weakref = @storage[v8_object.GetIdentityHash()]
if weakref && weakref.weakref_alive?
weakref.__getobj__
else
@storage[v8_object.GetIdentityHash()] = WeakRef.new(yield)
end
else
yield
def [](object)
weakref = @map[to_key(object)]
if weakref && weakref.weakref_alive?
weakref.__getobj__
end
end
def equate(key_object, value_object)
@map[to_key(key_object)] = WeakRef.new(value_object)
end
end
class RubyIDMap < IDMap
def to_key(object)
object.object_id
end
end
class V8IDMap < IDMap
def to_key(object)
object.GetIdentityHash()
end
def [](v8_object)
super if v8_object.is_a?(V8::C::Object)
end
end
end
end

View File

@ -1,12 +1,31 @@
class V8::Conversion
module Object
def to_v8
V8::C::Object::New()
template = V8::C::ObjectTemplate::New()
template.SetNamedPropertyHandler(Get, nil, nil, nil, nil, V8::C::External::New(self))
instance = template.NewInstance()
V8::Context.link self, instance
return instance
end
def to_ruby
self
end
class Get
def self.call(property, info)
context = V8::Context.current
object = info.Data().Value()
name = property.Utf8Value()
if object.respond_to?(name) && object.method(name).arity <= 0
context.to_v8 object.send(name)
else
V8::C::Value::Empty
end
rescue Exception => e
warn "uncaught exception: #{e.class}: #{e.message} while accessing object property: #{e.backtrace.join('\n')}"
end
end
end
module NativeObject

View File

@ -6,6 +6,7 @@ class V8::Object
def initialize(native = nil)
@context = V8::Context.current or fail "tried to initialize a #{self.class} without being in an entered V8::Context"
@native = native || V8::C::Object::New()
@context.link self, @native
end
def [](key)