1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
package org.msgpack.jruby;
import org.jruby.Ruby;
import org.jruby.RubyHash;
import org.jruby.RubyArray;
import org.jruby.RubyModule;
import org.jruby.RubyFixnum;
import org.jruby.RubySymbol;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import java.util.Map;
import java.util.HashMap;
public class ExtensionRegistry {
private final Map<RubyModule, ExtensionEntry> extensionsByModule;
private final Map<RubyModule, ExtensionEntry> extensionsByAncestor;
private final ExtensionEntry[] extensionsByTypeId;
public ExtensionRegistry() {
this(new HashMap<RubyModule, ExtensionEntry>(), new ExtensionEntry[256]);
}
private ExtensionRegistry(Map<RubyModule, ExtensionEntry> extensionsByModule, ExtensionEntry[] extensionsByTypeId) {
this.extensionsByModule = new HashMap<RubyModule, ExtensionEntry>(extensionsByModule);
this.extensionsByAncestor = new HashMap<RubyModule, ExtensionEntry>();
this.extensionsByTypeId = extensionsByTypeId.clone();
}
public ExtensionRegistry dup() {
return new ExtensionRegistry(extensionsByModule, extensionsByTypeId);
}
public IRubyObject toInternalPackerRegistry(ThreadContext ctx) {
RubyHash hash = RubyHash.newHash(ctx.runtime);
for (RubyModule extensionModule : extensionsByModule.keySet()) {
ExtensionEntry entry = extensionsByModule.get(extensionModule);
if (entry.hasPacker()) {
hash.put(extensionModule, entry.toPackerTuple(ctx));
}
}
return hash;
}
public IRubyObject toInternalUnpackerRegistry(ThreadContext ctx) {
RubyHash hash = RubyHash.newHash(ctx.runtime);
for (int typeIdIndex = 0 ; typeIdIndex < 256 ; typeIdIndex++) {
ExtensionEntry entry = extensionsByTypeId[typeIdIndex];
if (entry != null && entry.hasUnpacker()) {
IRubyObject typeId = RubyFixnum.newFixnum(ctx.runtime, typeIdIndex - 128);
hash.put(typeId, entry.toUnpackerTuple(ctx));
}
}
return hash;
}
public void put(RubyModule mod, int typeId, boolean recursive, IRubyObject packerProc, IRubyObject unpackerProc) {
ExtensionEntry entry = new ExtensionEntry(mod, typeId, recursive, packerProc, unpackerProc);
extensionsByModule.put(mod, entry);
extensionsByTypeId[typeId + 128] = entry;
extensionsByAncestor.clear();
}
public ExtensionEntry lookupExtensionByTypeId(int typeId) {
ExtensionEntry e = extensionsByTypeId[typeId + 128];
if (e != null && e.hasUnpacker()) {
return e;
}
return null;
}
public ExtensionEntry lookupExtensionForObject(IRubyObject object) {
RubyModule lookupClass = null;
ExtensionEntry entry = null;
/*
* Objects of type Integer (Fixnum, Bignum), Float, Symbol and frozen
* String have no singleton class and raise a TypeError when trying to get
* it.
*/
lookupClass = object.getMetaClass();
entry = extensionsByModule.get(lookupClass);
if (entry != null && entry.hasPacker()) {
return entry;
}
RubyModule realClass = object.getType();
if (realClass != lookupClass) {
entry = extensionsByModule.get(realClass);
if (entry != null && entry.hasPacker()) {
return entry;
}
}
entry = findEntryByModuleOrAncestor(lookupClass);
if (entry != null && entry.hasPacker()) {
return entry;
}
return null;
}
private ExtensionEntry findEntryByModuleOrAncestor(final RubyModule mod) {
ThreadContext ctx = mod.getRuntime().getCurrentContext();
for (RubyModule extensionModule : extensionsByModule.keySet()) {
RubyArray<?> ancestors = (RubyArray)mod.callMethod(ctx, "ancestors");
if (ancestors.callMethod(ctx, "include?", extensionModule).isTrue()) {
return extensionsByModule.get(extensionModule);
}
}
return null;
}
public static class ExtensionEntry {
private final RubyModule mod;
private final int typeId;
private final boolean recursive;
private final IRubyObject packerProc;
private final IRubyObject unpackerProc;
public ExtensionEntry(RubyModule mod, int typeId, boolean recursive, IRubyObject packerProc, IRubyObject unpackerProc) {
this.mod = mod;
this.typeId = typeId;
this.recursive = recursive;
this.packerProc = packerProc;
this.unpackerProc = unpackerProc;
}
public RubyModule getExtensionModule() {
return mod;
}
public int getTypeId() {
return typeId;
}
public boolean isRecursive() {
return recursive;
}
public boolean hasPacker() {
return packerProc != null && !packerProc.isNil();
}
public boolean hasUnpacker() {
return unpackerProc != null && !unpackerProc.isNil();
}
public IRubyObject getPackerProc() {
return packerProc;
}
public IRubyObject getUnpackerProc() {
return unpackerProc;
}
public RubyArray<?> toPackerTuple(ThreadContext ctx) {
return ctx.runtime.newArray(new IRubyObject[] {ctx.runtime.newFixnum(typeId), packerProc});
}
public RubyArray<?> toUnpackerTuple(ThreadContext ctx) {
return ctx.runtime.newArray(new IRubyObject[] {mod, unpackerProc});
}
public IRubyObject[] toPackerProcTypeIdPair(ThreadContext ctx) {
return new IRubyObject[] {packerProc, ctx.runtime.newFixnum(typeId)};
}
}
}
|