opal/corelib/marshal/write_buffer.rb
# backtick_javascript: true
class ::NilClass
def __marshal__(buffer)
buffer.append('0')
end
end
class ::Boolean
def __marshal__(buffer)
if `self == true`
buffer.append('T')
else
buffer.append('F')
end
end
end
class ::Integer
def __marshal__(buffer)
if self >= -0x40000000 && self < 0x40000000
buffer.append('i')
buffer.write_fixnum(self)
else
buffer.append('l')
buffer.write_bignum(self)
end
end
end
class ::Float
def __marshal__(buffer)
buffer.save_link(self)
buffer.append('f')
buffer.write_float(self)
end
end
class ::String
def __marshal__(buffer)
buffer.save_link(self)
buffer.write_ivars_prefix(self)
buffer.write_extends(self)
buffer.write_user_class(::String, self)
buffer.append('"')
buffer.write_string(self)
end
end
class ::Array
def __marshal__(buffer)
buffer.save_link(self)
buffer.write_ivars_prefix(self)
buffer.write_extends(self)
buffer.write_user_class(::Array, self)
buffer.append('[')
buffer.write_array(self)
buffer.write_ivars_suffix(self)
end
end
class ::Hash
def __marshal__(buffer)
if default_proc
::Kernel.raise ::TypeError, "can't dump hash with default proc"
end
buffer.save_link(self)
buffer.write_ivars_prefix(self)
buffer.write_extends(self)
buffer.write_user_class(Hash, self)
if default
buffer.append('}')
buffer.write_hash(self)
buffer.write(default)
else
buffer.append('{')
buffer.write_hash(self)
end
buffer.write_ivars_suffix(self)
end
end
class ::Regexp
def __marshal__(buffer)
buffer.save_link(self)
buffer.write_ivars_prefix(self)
buffer.write_extends(self)
buffer.write_user_class(::Regexp, self)
buffer.append('/')
buffer.write_regexp(self)
buffer.write_ivars_suffix(self)
end
end
class ::Proc
def __marshal__(buffer)
::Kernel.raise ::TypeError, "no _dump_data is defined for class #{self.class}"
end
end
class ::Method
def __marshal__(buffer)
::Kernel.raise ::TypeError, "no _dump_data is defined for class #{self.class}"
end
end
class ::MatchData
def __marshal__(buffer)
::Kernel.raise ::TypeError, "no _dump_data is defined for class #{self.class}"
end
end
class ::Module
def __marshal__(buffer)
unless name
::Kernel.raise ::TypeError, "can't dump anonymous module"
end
buffer.save_link(self)
buffer.append('m')
buffer.write_module(self)
end
end
class ::Class
def __marshal__(buffer)
unless name
::Kernel.raise ::TypeError, "can't dump anonymous class"
end
if singleton_class?
::Kernel.raise ::TypeError, "singleton class can't be dumped"
end
buffer.save_link(self)
buffer.append('c')
buffer.write_class(self)
end
end
class ::BasicObject
def __marshal__(buffer)
buffer.save_link(self)
buffer.write_extends(self)
buffer.append('o')
buffer.write_object(self)
end
end
class ::Range
def __marshal__(buffer)
buffer.save_link(self)
buffer.write_extends(self)
buffer.append('o')
buffer.append_symbol(self.class.name)
buffer.write_fixnum(3)
buffer.append_symbol('excl')
buffer.write(exclude_end?)
buffer.append_symbol('begin')
buffer.write(self.begin)
buffer.append_symbol('end')
buffer.write(self.end)
end
end
class ::Struct
def __marshal__(buffer)
buffer.save_link(self)
buffer.write_ivars_prefix(self)
buffer.write_extends(self)
buffer.append('S')
buffer.append_symbol(self.class.name)
buffer.write_fixnum(length)
each_pair do |attr_name, value|
buffer.append_symbol(attr_name)
buffer.write(value)
end
buffer.write_ivars_suffix(self)
end
end
module ::Marshal
class self::WriteBuffer
attr_reader :buffer
%x{
function binaryString(s) {
s = new String(s);
s.encoding = #{Encoding::BINARY};
return s;
}
}
def initialize(object)
@object = object
@buffer = ''
@cache = []
@extends = ::Hash.new { |h, k| h[k] = [] }
append(version)
end
def write(object = @object)
if idx = @cache.index(object.object_id)
write_object_link(idx)
elsif object.respond_to?(:marshal_dump)
write_usr_marshal(object)
elsif object.respond_to?(:_dump)
write_userdef(object)
else
case object
when nil, true, false, ::Proc, ::Method, ::MatchData, ::Range, ::Struct,
::Array, ::Class, ::Module, ::Hash, ::Regexp
object.__marshal__(self)
when ::Integer
::Integer.instance_method(:__marshal__).bind(object).call(self)
when ::Float
::Float.instance_method(:__marshal__).bind(object).call(self)
when ::String
::String.instance_method(:__marshal__).bind(object).call(self)
else
::BasicObject.instance_method(:__marshal__).bind(object).call(self)
end
end
`binaryString(#{@buffer})`
end
def write_fixnum(n)
%x{
var s;
if (n == 0) {
s = String.fromCharCode(n);
} else if (n > 0 && n < 123) {
s = String.fromCharCode(n + 5);
} else if (n < 0 && n > -124) {
s = String.fromCharCode(256 + n - 5);
} else {
s = "";
var cnt = 0;
for (var i = 0; i < 4; i++) {
var b = n & 255;
s += String.fromCharCode(b);
n >>= 8
cnt += 1;
if (n === 0 || n === -1) {
break;
}
}
var l_byte;
if (n < 0) {
l_byte = 256 - cnt;
} else {
l_byte = cnt;
}
s = String.fromCharCode(l_byte) + s;
}
#{append(`s`)}
}
end
def write_bignum(n)
sign = n > 0 ? '+' : '-'
append(sign)
num = n > 0 ? n : -n
arr = []
while num > 0
arr << (num & 0xffff)
num = (num / 0x10000).floor
end
write_fixnum(arr.size)
arr.each do |x|
append(`String.fromCharCode(x & 0xff)`)
append(`String.fromCharCode(#{(x / 0x100).floor})`)
end
end
def write_string(s)
write_fixnum(s.length)
append(s)
end
def append_symbol(sym)
append(':')
write_fixnum(sym.length)
append(sym)
end
def write_array(a)
write_fixnum(a.length)
a.each do |item|
write(item)
end
end
def write_hash(h)
write_fixnum(h.length)
h.each do |key, value|
write(key)
write(value)
end
end
def write_object(obj)
append_symbol(obj.class.name)
write_ivars_suffix(obj, true)
end
def write_class(klass)
write_string(klass.name)
end
def write_module(mod)
write_string(mod.name)
end
def write_regexp(regexp)
write_string(regexp.to_s)
append(`String.fromCharCode(#{regexp.options})`)
end
def write_float(f)
if f.equal?(::Float::INFINITY)
write_string('inf')
elsif f.equal?(-::Float::INFINITY)
write_string('-inf')
elsif f.equal?(::Float::NAN)
write_string('nan')
else
write_string(f.to_s)
end
end
def write_ivars_suffix(object, force = false)
if object.instance_variables.empty? && !force
return
end
write_fixnum(object.instance_variables.length)
object.instance_variables.each do |ivar_name|
append_symbol(ivar_name)
write(object.instance_variable_get(ivar_name))
end
end
def write_extends(object)
singleton_mods = object.singleton_class.ancestors.reject { |mod| mod.is_a?(Class) }
class_mods = object.class.ancestors.reject { |mod| mod.is_a?(Class) }
own_mods = singleton_mods - class_mods
unless own_mods.empty?
own_mods.each do |mod|
append('e')
append_symbol(mod.name)
end
end
end
def write_user_class(klass, object)
unless object.class.equal?(klass)
append('C')
append_symbol(object.class.name)
end
end
def write_object_link(idx)
append('@')
write_fixnum(idx)
end
def save_link(object)
@cache << object.object_id
end
def write_usr_marshal(object)
value = object.marshal_dump
klass = object.class
append('U')
namespace = `#{klass}.$$base_module`
if namespace.equal?(::Object)
append_symbol(`#{klass}.$$name`)
else
append_symbol(namespace.name + '::' + `#{klass}.$$name`)
end
write(value)
end
def write_userdef(object)
value = object._dump(0)
unless value.is_a?(::String)
::Kernel.raise ::TypeError, '_dump() must return string'
end
write_ivars_prefix(value)
append('u')
append_symbol(object.class.name)
write_string(value)
end
def write_ivars_prefix(object)
unless object.instance_variables.empty?
append('I')
end
end
def append(s)
`#{@buffer} += #{s}`
end
def version
`String.fromCharCode(#{MAJOR_VERSION}, #{MINOR_VERSION})`
end
end
end