From ed5aec4fb494d7488c1c2bae7bd4316cc382c5f1 Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Tue, 7 Nov 2017 11:18:28 -0800 Subject: [PATCH 01/13] setup for marshal dump --- spec/ruby_marshal_dump_spec.cr | 15 +++++++++++++++ ...-marshal_spec.cr => ruby_marshal_load_spec.cr} | 0 src/ruby-marshal.cr | 8 ++++++++ src/ruby-marshal/exception.cr | 1 + src/ruby-marshal/slice.cr | 12 ++++++++++++ src/ruby-marshal/stream_object_factory.cr | 9 +++++++++ src/ruby-marshal/stream_objects/array.cr | 6 ++++++ src/ruby-marshal/stream_objects/bignum.cr | 6 ++++++ src/ruby-marshal/stream_objects/class.cr | 6 ++++++ .../stream_objects/extended_object.cr | 6 ++++++ src/ruby-marshal/stream_objects/false.cr | 13 +++++++++++-- src/ruby-marshal/stream_objects/float.cr | 6 ++++++ .../stream_objects/four_byte_negative_int.cr | 6 ++++++ .../stream_objects/four_byte_positive_int.cr | 6 ++++++ src/ruby-marshal/stream_objects/hash.cr | 6 ++++++ .../stream_objects/hash_with_default.cr | 6 ++++++ .../stream_objects/instance_object.cr | 6 ++++++ src/ruby-marshal/stream_objects/module.cr | 6 ++++++ src/ruby-marshal/stream_objects/null.cr | 6 ++++-- src/ruby-marshal/stream_objects/object.cr | 6 ++++++ src/ruby-marshal/stream_objects/object_pointer.cr | 6 ++++++ src/ruby-marshal/stream_objects/one_byte_int.cr | 6 ++++++ .../stream_objects/one_byte_negative_int.cr | 6 ++++++ .../stream_objects/one_byte_positive_int.cr | 6 ++++++ src/ruby-marshal/stream_objects/regex.cr | 6 ++++++ src/ruby-marshal/stream_objects/string.cr | 6 ++++++ src/ruby-marshal/stream_objects/struct.cr | 6 ++++++ src/ruby-marshal/stream_objects/symbol.cr | 6 ++++++ src/ruby-marshal/stream_objects/symbol_pointer.cr | 6 ++++++ .../stream_objects/three_byte_negative_int.cr | 6 ++++++ .../stream_objects/three_byte_positive_int.cr | 6 ++++++ src/ruby-marshal/stream_objects/true.cr | 13 +++++++++++-- .../stream_objects/two_byte_negative_int.cr | 6 ++++++ .../stream_objects/two_byte_positive_int.cr | 6 ++++++ src/ruby-marshal/stream_objects/user_class.cr | 6 ++++++ src/ruby-marshal/stream_objects/zero_byte_int.cr | 7 ++++--- 36 files changed, 231 insertions(+), 9 deletions(-) create mode 100644 spec/ruby_marshal_dump_spec.cr rename spec/{ruby-marshal_spec.cr => ruby_marshal_load_spec.cr} (100%) create mode 100644 src/ruby-marshal/slice.cr diff --git a/spec/ruby_marshal_dump_spec.cr b/spec/ruby_marshal_dump_spec.cr new file mode 100644 index 0000000..d7eaac1 --- /dev/null +++ b/spec/ruby_marshal_dump_spec.cr @@ -0,0 +1,15 @@ +require "./spec_helper" + +describe Ruby::Marshal do + + it "#dump true" do + object = Ruby::Marshal.dump(true) + puts object.hexdump + end + + it "#dump false" do + object = Ruby::Marshal.dump(false) + puts object.hexdump + end + +end diff --git a/spec/ruby-marshal_spec.cr b/spec/ruby_marshal_load_spec.cr similarity index 100% rename from spec/ruby-marshal_spec.cr rename to spec/ruby_marshal_load_spec.cr diff --git a/src/ruby-marshal.cr b/src/ruby-marshal.cr index 70538b3..951bdd8 100644 --- a/src/ruby-marshal.cr +++ b/src/ruby-marshal.cr @@ -60,4 +60,12 @@ module Ruby::Marshal return StreamObjectFactory.get(stream) end + def self.dump(obj) : ::Bytes + bytestream = ::Bytes.new(2) + bytestream[0] = UInt8.new(MAJOR_VERSION) + bytestream[1] = UInt8.new(MINOR_VERSION) + result = StreamObjectFactory.from(obj).dump(bytestream) + result.nil? ? bytestream : result + end + end diff --git a/src/ruby-marshal/exception.cr b/src/ruby-marshal/exception.cr index 7653dfc..1414f0c 100644 --- a/src/ruby-marshal/exception.cr +++ b/src/ruby-marshal/exception.cr @@ -2,5 +2,6 @@ module Ruby::Marshal class UnsupportedVersion < Exception ; end class InvalidMarshalData < Exception ; end + class UnsupportedMarshalClass < Exception ; end end \ No newline at end of file diff --git a/src/ruby-marshal/slice.cr b/src/ruby-marshal/slice.cr new file mode 100644 index 0000000..15e4ec9 --- /dev/null +++ b/src/ruby-marshal/slice.cr @@ -0,0 +1,12 @@ +struct Slice(T) + + # Cocatenate the passed slice onto the end of the slice + def concat(slice : ::Slice) + result = ::Slice(T).new(self.size + slice.size) + self.each_with_index { |b, i| result[i] = b } + slice.each_with_index { |b, i| result[i + self.size] = b } + return result + end + +end + diff --git a/src/ruby-marshal/stream_object_factory.cr b/src/ruby-marshal/stream_object_factory.cr index e8f83c0..2d30f1a 100644 --- a/src/ruby-marshal/stream_object_factory.cr +++ b/src/ruby-marshal/stream_object_factory.cr @@ -33,6 +33,15 @@ module Ruby::Marshal end end + def self.from(obj : ::Object) : StreamObject + case obj.class.to_s + when "Bool" + obj = obj.as(Bool) + return obj ? True.new(obj) : False.new(obj) + else raise UnsupportedMarshalClass.new("Do not know how to handle dumping type: #{obj.class}") + end + end + end end diff --git a/src/ruby-marshal/stream_objects/array.cr b/src/ruby-marshal/stream_objects/array.cr index 8d3e248..4052799 100644 --- a/src/ruby-marshal/stream_objects/array.cr +++ b/src/ruby-marshal/stream_objects/array.cr @@ -31,6 +31,12 @@ module Ruby::Marshal end end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/bignum.cr b/src/ruby-marshal/stream_objects/bignum.cr index b3746b3..4151da2 100644 --- a/src/ruby-marshal/stream_objects/bignum.cr +++ b/src/ruby-marshal/stream_objects/bignum.cr @@ -40,6 +40,12 @@ module Ruby::Marshal @size += @length.data * 2 end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/class.cr b/src/ruby-marshal/stream_objects/class.cr index 7f05d3c..1068913 100644 --- a/src/ruby-marshal/stream_objects/class.cr +++ b/src/ruby-marshal/stream_objects/class.cr @@ -26,6 +26,12 @@ module Ruby::Marshal super(source.stream_size) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/extended_object.cr b/src/ruby-marshal/stream_objects/extended_object.cr index bdc9ed0..acacaa4 100644 --- a/src/ruby-marshal/stream_objects/extended_object.cr +++ b/src/ruby-marshal/stream_objects/extended_object.cr @@ -19,6 +19,12 @@ module Ruby::Marshal @extended_by = StreamObjectFactory.get(stream) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/false.cr b/src/ruby-marshal/stream_objects/false.cr index 3f76b20..68d123b 100644 --- a/src/ruby-marshal/stream_objects/false.cr +++ b/src/ruby-marshal/stream_objects/false.cr @@ -5,6 +5,7 @@ module Ruby::Marshal class False < StreamObject @data : Bool + @type_byte = UInt8.new(0x46) getter :data def initialize(stream : Bytes) @@ -12,9 +13,17 @@ module Ruby::Marshal @data = false end - def read(stream : Bytes) - # noop + def initialize(bool : ::Bool) + super(0x00) + @data = false + end + + def dump(bytestream : ::Bytes) + output = ::Bytes.new(1) + output[0] = @type_byte + bytestream.concat(output) end + end end diff --git a/src/ruby-marshal/stream_objects/float.cr b/src/ruby-marshal/stream_objects/float.cr index 36f6ee9..e6d9125 100644 --- a/src/ruby-marshal/stream_objects/float.cr +++ b/src/ruby-marshal/stream_objects/float.cr @@ -26,6 +26,12 @@ module Ruby::Marshal super(source.stream_size) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/four_byte_negative_int.cr b/src/ruby-marshal/stream_objects/four_byte_negative_int.cr index bdc6f73..1ba827e 100644 --- a/src/ruby-marshal/stream_objects/four_byte_negative_int.cr +++ b/src/ruby-marshal/stream_objects/four_byte_negative_int.cr @@ -24,6 +24,12 @@ module Ruby::Marshal @data = -(IO::ByteFormat::BigEndian.decode(Int32, padded_slice) + 1) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/four_byte_positive_int.cr b/src/ruby-marshal/stream_objects/four_byte_positive_int.cr index 6e4197c..4ab2311 100644 --- a/src/ruby-marshal/stream_objects/four_byte_positive_int.cr +++ b/src/ruby-marshal/stream_objects/four_byte_positive_int.cr @@ -13,6 +13,12 @@ module Ruby::Marshal @data = ::IO::ByteFormat::LittleEndian.decode(Int32, stream[1, size]) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/hash.cr b/src/ruby-marshal/stream_objects/hash.cr index 0117972..a6b1d3f 100644 --- a/src/ruby-marshal/stream_objects/hash.cr +++ b/src/ruby-marshal/stream_objects/hash.cr @@ -85,6 +85,12 @@ module Ruby::Marshal raw_hash end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/hash_with_default.cr b/src/ruby-marshal/stream_objects/hash_with_default.cr index 7afaa71..d7fa737 100644 --- a/src/ruby-marshal/stream_objects/hash_with_default.cr +++ b/src/ruby-marshal/stream_objects/hash_with_default.cr @@ -22,6 +22,12 @@ module Ruby::Marshal @default_value = StreamObjectFactory.get(stream) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/instance_object.cr b/src/ruby-marshal/stream_objects/instance_object.cr index cb89f2b..06c32e7 100644 --- a/src/ruby-marshal/stream_objects/instance_object.cr +++ b/src/ruby-marshal/stream_objects/instance_object.cr @@ -46,6 +46,12 @@ module Ruby::Marshal @data.data end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/module.cr b/src/ruby-marshal/stream_objects/module.cr index cb105b0..7bc54c0 100644 --- a/src/ruby-marshal/stream_objects/module.cr +++ b/src/ruby-marshal/stream_objects/module.cr @@ -35,6 +35,12 @@ module Ruby::Marshal @size += @length.data end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/null.cr b/src/ruby-marshal/stream_objects/null.cr index 9fbcfed..349787b 100644 --- a/src/ruby-marshal/stream_objects/null.cr +++ b/src/ruby-marshal/stream_objects/null.cr @@ -17,8 +17,10 @@ module Ruby::Marshal @data = nil end - def read(stream : Bytes) - # noop + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) end end diff --git a/src/ruby-marshal/stream_objects/object.cr b/src/ruby-marshal/stream_objects/object.cr index b1aae49..56d22d3 100644 --- a/src/ruby-marshal/stream_objects/object.cr +++ b/src/ruby-marshal/stream_objects/object.cr @@ -68,6 +68,12 @@ module Ruby::Marshal read_attr(name, true) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/object_pointer.cr b/src/ruby-marshal/stream_objects/object_pointer.cr index 3d2f4ad..0209edc 100644 --- a/src/ruby-marshal/stream_objects/object_pointer.cr +++ b/src/ruby-marshal/stream_objects/object_pointer.cr @@ -21,6 +21,12 @@ module Ruby::Marshal @data = Heap.get_obj(@heap_index).data end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/one_byte_int.cr b/src/ruby-marshal/stream_objects/one_byte_int.cr index 6f9616a..d70770e 100644 --- a/src/ruby-marshal/stream_objects/one_byte_int.cr +++ b/src/ruby-marshal/stream_objects/one_byte_int.cr @@ -29,6 +29,12 @@ module Ruby::Marshal return 2 end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/one_byte_negative_int.cr b/src/ruby-marshal/stream_objects/one_byte_negative_int.cr index e29693a..3a6c80c 100644 --- a/src/ruby-marshal/stream_objects/one_byte_negative_int.cr +++ b/src/ruby-marshal/stream_objects/one_byte_negative_int.cr @@ -16,6 +16,12 @@ module Ruby::Marshal @data = -(Int32.new(complement_slice.join) + 1) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/one_byte_positive_int.cr b/src/ruby-marshal/stream_objects/one_byte_positive_int.cr index 0f1d51e..e722254 100644 --- a/src/ruby-marshal/stream_objects/one_byte_positive_int.cr +++ b/src/ruby-marshal/stream_objects/one_byte_positive_int.cr @@ -13,6 +13,12 @@ module Ruby::Marshal @data = Int32.new(stream[1, size].join) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/regex.cr b/src/ruby-marshal/stream_objects/regex.cr index 981381f..ee693c9 100644 --- a/src/ruby-marshal/stream_objects/regex.cr +++ b/src/ruby-marshal/stream_objects/regex.cr @@ -26,6 +26,12 @@ module Ruby::Marshal super(source.stream_size + source.length.size) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/string.cr b/src/ruby-marshal/stream_objects/string.cr index a163a90..5a5e15e 100644 --- a/src/ruby-marshal/stream_objects/string.cr +++ b/src/ruby-marshal/stream_objects/string.cr @@ -19,6 +19,12 @@ module Ruby::Marshal Heap.add(self) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/struct.cr b/src/ruby-marshal/stream_objects/struct.cr index 0421ba9..0146250 100644 --- a/src/ruby-marshal/stream_objects/struct.cr +++ b/src/ruby-marshal/stream_objects/struct.cr @@ -72,6 +72,12 @@ module Ruby::Marshal read_attr(name, true) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/symbol.cr b/src/ruby-marshal/stream_objects/symbol.cr index b84cf7e..9be1319 100644 --- a/src/ruby-marshal/stream_objects/symbol.cr +++ b/src/ruby-marshal/stream_objects/symbol.cr @@ -25,6 +25,12 @@ module Ruby::Marshal 1 + @symbol_length + size end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/symbol_pointer.cr b/src/ruby-marshal/stream_objects/symbol_pointer.cr index cb5a7fc..4a08f27 100644 --- a/src/ruby-marshal/stream_objects/symbol_pointer.cr +++ b/src/ruby-marshal/stream_objects/symbol_pointer.cr @@ -19,6 +19,12 @@ module Ruby::Marshal @data = Heap.get_sym(@heap_index).data end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/three_byte_negative_int.cr b/src/ruby-marshal/stream_objects/three_byte_negative_int.cr index 6967112..af7ef44 100644 --- a/src/ruby-marshal/stream_objects/three_byte_negative_int.cr +++ b/src/ruby-marshal/stream_objects/three_byte_negative_int.cr @@ -23,6 +23,12 @@ module Ruby::Marshal @data = -(IO::ByteFormat::BigEndian.decode(Int32, padded_slice) + 1) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/three_byte_positive_int.cr b/src/ruby-marshal/stream_objects/three_byte_positive_int.cr index b80140d..0597298 100644 --- a/src/ruby-marshal/stream_objects/three_byte_positive_int.cr +++ b/src/ruby-marshal/stream_objects/three_byte_positive_int.cr @@ -21,6 +21,12 @@ module Ruby::Marshal @data = ::IO::ByteFormat::BigEndian.decode(Int32, padded_slice) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/true.cr b/src/ruby-marshal/stream_objects/true.cr index 1089e46..90131f3 100644 --- a/src/ruby-marshal/stream_objects/true.cr +++ b/src/ruby-marshal/stream_objects/true.cr @@ -5,6 +5,7 @@ module Ruby::Marshal class True < StreamObject @data : Bool + @type_byte = UInt8.new(0x54) getter :data def initialize(stream : Bytes) @@ -12,9 +13,17 @@ module Ruby::Marshal @data = true end - def read(stream : Bytes) - # noop + def initialize(bool : ::Bool) + super(0x00) + @data = true + end + + def dump(bytestream : ::Bytes) + output = ::Bytes.new(1) + output[0] = @type_byte + bytestream.concat(output) end + end end diff --git a/src/ruby-marshal/stream_objects/two_byte_negative_int.cr b/src/ruby-marshal/stream_objects/two_byte_negative_int.cr index f960f43..2ab5205 100644 --- a/src/ruby-marshal/stream_objects/two_byte_negative_int.cr +++ b/src/ruby-marshal/stream_objects/two_byte_negative_int.cr @@ -22,6 +22,12 @@ module Ruby::Marshal @data = -(IO::ByteFormat::BigEndian.decode(Int32, padded_slice) + 1) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/two_byte_positive_int.cr b/src/ruby-marshal/stream_objects/two_byte_positive_int.cr index 2cb7b62..825316a 100644 --- a/src/ruby-marshal/stream_objects/two_byte_positive_int.cr +++ b/src/ruby-marshal/stream_objects/two_byte_positive_int.cr @@ -13,6 +13,12 @@ module Ruby::Marshal @data = Int32.new(::IO::ByteFormat::LittleEndian.decode(UInt16, stream[1, size])) end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/user_class.cr b/src/ruby-marshal/stream_objects/user_class.cr index bde6306..4918b52 100644 --- a/src/ruby-marshal/stream_objects/user_class.cr +++ b/src/ruby-marshal/stream_objects/user_class.cr @@ -25,6 +25,12 @@ module Ruby::Marshal @size += @data.stream_size end + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) + end + end end diff --git a/src/ruby-marshal/stream_objects/zero_byte_int.cr b/src/ruby-marshal/stream_objects/zero_byte_int.cr index 71fe6d1..4d065b4 100644 --- a/src/ruby-marshal/stream_objects/zero_byte_int.cr +++ b/src/ruby-marshal/stream_objects/zero_byte_int.cr @@ -6,11 +6,12 @@ module Ruby::Marshal def initialize(stream : Bytes) super(Int32.new(0x01)) - read(stream) end - def read(stream : Bytes) - # noop + def dump(bytestream : ::Bytes) + #output = ::Bytes.new(1) + #output[0] = @type_byte + #bytestream.concat(output) end end From ff25feba7be54513a2487e291f5c694cf1dfdc50 Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Thu, 9 Nov 2017 23:17:25 -0800 Subject: [PATCH 02/13] wip: marshal dump. nil + class functional. --- spec/ruby_marshal_dump_spec.cr | 19 ++++++++++++ spec/spec_helper.cr | 3 ++ spec/tmp/marshalled-class.out | Bin 0 -> 11 bytes spec/tmp/marshalled-false.out | 1 + spec/tmp/marshalled-nil.out | 1 + spec/tmp/marshalled-true.out | 1 + src/ruby-marshal.cr | 4 +-- src/ruby-marshal/stream_object_factory.cr | 21 ++++++++----- src/ruby-marshal/stream_objects/array.cr | 2 +- src/ruby-marshal/stream_objects/bignum.cr | 2 +- .../stream_objects/byte_sequence.cr | 17 +++++++++++ src/ruby-marshal/stream_objects/class.cr | 28 +++++++++++++----- .../stream_objects/extended_object.cr | 2 +- src/ruby-marshal/stream_objects/false.cr | 4 +-- src/ruby-marshal/stream_objects/float.cr | 2 +- .../stream_objects/four_byte_negative_int.cr | 2 +- .../stream_objects/four_byte_positive_int.cr | 2 +- src/ruby-marshal/stream_objects/hash.cr | 2 +- .../stream_objects/hash_with_default.cr | 2 +- .../stream_objects/instance_object.cr | 2 +- src/ruby-marshal/stream_objects/module.cr | 2 +- src/ruby-marshal/stream_objects/null.cr | 9 +++--- src/ruby-marshal/stream_objects/object.cr | 2 +- .../stream_objects/object_pointer.cr | 2 +- .../stream_objects/one_byte_int.cr | 2 +- .../stream_objects/one_byte_negative_int.cr | 2 +- .../stream_objects/one_byte_positive_int.cr | 2 +- src/ruby-marshal/stream_objects/regex.cr | 2 +- src/ruby-marshal/stream_objects/string.cr | 2 +- src/ruby-marshal/stream_objects/struct.cr | 2 +- src/ruby-marshal/stream_objects/symbol.cr | 2 +- .../stream_objects/symbol_pointer.cr | 2 +- .../stream_objects/three_byte_negative_int.cr | 2 +- .../stream_objects/three_byte_positive_int.cr | 19 +++++++++--- src/ruby-marshal/stream_objects/true.cr | 4 +-- .../stream_objects/two_byte_negative_int.cr | 2 +- .../stream_objects/two_byte_positive_int.cr | 2 +- src/ruby-marshal/stream_objects/user_class.cr | 2 +- .../stream_objects/zero_byte_int.cr | 2 +- 39 files changed, 128 insertions(+), 53 deletions(-) create mode 100644 spec/tmp/marshalled-class.out create mode 100644 spec/tmp/marshalled-false.out create mode 100644 spec/tmp/marshalled-nil.out create mode 100644 spec/tmp/marshalled-true.out diff --git a/spec/ruby_marshal_dump_spec.cr b/spec/ruby_marshal_dump_spec.cr index d7eaac1..693703b 100644 --- a/spec/ruby_marshal_dump_spec.cr +++ b/spec/ruby_marshal_dump_spec.cr @@ -3,13 +3,32 @@ require "./spec_helper" describe Ruby::Marshal do it "#dump true" do + File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-true.out"), "w") { |f| f.write( Ruby::Marshal.dump(true) ) } object = Ruby::Marshal.dump(true) puts object.hexdump end it "#dump false" do + File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-false.out"), "w") { |f| f.write( Ruby::Marshal.dump(false) ) } object = Ruby::Marshal.dump(false) puts object.hexdump end + it "#dump nil" do + File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-nil.out"), "w") { |f| f.write( Ruby::Marshal.dump(nil) ) } + object = Ruby::Marshal.dump(nil) + puts object.hexdump + end + + it "#dump a class" do + File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-class.out"), "w") { |f| f.write( Ruby::Marshal.dump(User) ) } + object = Ruby::Marshal.dump(User) + puts object.hexdump + end + + it "#dump a module" do + object = Ruby::Marshal.dump(TestModule) + puts object.hexdump + end + end diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index ba6206d..09df6e0 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -42,3 +42,6 @@ struct Customer end end +module TestModule + +end diff --git a/spec/tmp/marshalled-class.out b/spec/tmp/marshalled-class.out new file mode 100644 index 0000000000000000000000000000000000000000..64de5e9c95cbc561bccc861d6d082488f68f085d GIT binary patch literal 11 ScmZSKNM>eXU Date: Thu, 9 Nov 2017 23:30:58 -0800 Subject: [PATCH 03/13] Marshal.dump(::Symbol) --- spec/ruby_marshal_dump_spec.cr | 7 +++++ spec/tmp/marshalled-module.out | Bin 0 -> 17 bytes spec/tmp/marshalled-symbol.out | Bin 0 -> 18 bytes src/ruby-marshal/stream_object_factory.cr | 4 +++ src/ruby-marshal/stream_objects/symbol.cr | 27 ++++++++---------- .../stream_objects/three_byte_positive_int.cr | 1 - 6 files changed, 23 insertions(+), 16 deletions(-) create mode 100644 spec/tmp/marshalled-module.out create mode 100644 spec/tmp/marshalled-symbol.out diff --git a/spec/ruby_marshal_dump_spec.cr b/spec/ruby_marshal_dump_spec.cr index 693703b..bd328d6 100644 --- a/spec/ruby_marshal_dump_spec.cr +++ b/spec/ruby_marshal_dump_spec.cr @@ -27,8 +27,15 @@ describe Ruby::Marshal do end it "#dump a module" do + File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-module.out"), "w") { |f| f.write( Ruby::Marshal.dump(TestModule) ) } object = Ruby::Marshal.dump(TestModule) puts object.hexdump end + it "#dump a symbol" do + File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-symbol.out"), "w") { |f| f.write( Ruby::Marshal.dump(:test_symbol) ) } + object = Ruby::Marshal.dump(:test_symbol) + puts object.hexdump + end + end diff --git a/spec/tmp/marshalled-module.out b/spec/tmp/marshalled-module.out new file mode 100644 index 0000000000000000000000000000000000000000..414aaa6a1f333f0324701049574dab4b87143028 GIT binary patch literal 17 YcmZSKNM`0@Uk literal 0 HcmV?d00001 diff --git a/spec/tmp/marshalled-symbol.out b/spec/tmp/marshalled-symbol.out new file mode 100644 index 0000000000000000000000000000000000000000..b6c0bd0b820f8fff433b44645f20ead8882370fe GIT binary patch literal 18 ZcmZSKuwv$BU?@o~E{QL$%uUMA0RSPc1quKF literal 0 HcmV?d00001 diff --git a/src/ruby-marshal/stream_object_factory.cr b/src/ruby-marshal/stream_object_factory.cr index 52dc8f6..5994d11 100644 --- a/src/ruby-marshal/stream_object_factory.cr +++ b/src/ruby-marshal/stream_object_factory.cr @@ -49,6 +49,10 @@ module Ruby::Marshal Ruby::Marshal::Class.new(obj) end + def self.from(sym : ::Symbol) : StreamObject + Ruby::Marshal::Symbol.new(sym) + end + end end diff --git a/src/ruby-marshal/stream_objects/symbol.cr b/src/ruby-marshal/stream_objects/symbol.cr index 70fd972..317aaf7 100644 --- a/src/ruby-marshal/stream_objects/symbol.cr +++ b/src/ruby-marshal/stream_objects/symbol.cr @@ -6,29 +6,26 @@ module Ruby::Marshal class Symbol < StreamObject getter :data + @type_byte = UInt8.new(0x3a) + @byte_sequence : ByteSequence def initialize(stream : Bytes) - @data = "" - symbol_length = Integer.get(stream) - @symbol_length = symbol_length.size.as(Int32) - super(symbol_length.data) - stream += @symbol_length - read(stream) + @byte_sequence = ByteSequence.new(stream) + @data = ::String.new(@byte_sequence.data) + super(@byte_sequence.stream_size + 1) Heap.add(self) end - def read(stream : Bytes) - @data = ::String.new(stream[0, size]) - end - - def stream_size - 1 + @symbol_length + size + def initialize(sym : ::Symbol) + @data = sym.to_s + @byte_sequence = ByteSequence.new(@data) + super(@byte_sequence.stream_size) end def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(1) + output[0] = @type_byte + output.concat(@byte_sequence.dump) end end diff --git a/src/ruby-marshal/stream_objects/three_byte_positive_int.cr b/src/ruby-marshal/stream_objects/three_byte_positive_int.cr index f6e75da..cf08fa3 100644 --- a/src/ruby-marshal/stream_objects/three_byte_positive_int.cr +++ b/src/ruby-marshal/stream_objects/three_byte_positive_int.cr @@ -30,7 +30,6 @@ module Ruby::Marshal def dump output = ::Bytes.new(1) output[0] = UInt8.new(0x03) # 3 - puts @data.inspect io = ::IO::Memory.new(0x03) @data.to_io(io, ::IO::ByteFormat::LittleEndian) data_slice = ::Bytes.new(3) From 552e51002a01831bfd6b15e6617400714d7d6050 Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Sat, 11 Nov 2017 23:56:14 -0800 Subject: [PATCH 04/13] wip: integer dump formats. --- spec/ruby_marshal_dump_spec.cr | 104 ++++++++++++++++++ spec/tmp/marshalled-one-byte-int-lower.out | 1 + spec/tmp/marshalled-one-byte-int-upper.out | 1 + spec/tmp/marshalled-one-byte-int.out | 1 + ...marshalled-one-byte-negative-int-lower.out | Bin 0 -> 5 bytes ...marshalled-one-byte-negative-int-upper.out | 1 + ...marshalled-one-byte-positive-int-lower.out | 1 + ...marshalled-one-byte-positive-int-upper.out | 1 + ...rshalled-three-byte-negative-int-lower.out | Bin 0 -> 7 bytes ...rshalled-three-byte-negative-int-upper.out | 1 + ...rshalled-three-byte-positive-int-lower.out | Bin 0 -> 7 bytes ...rshalled-three-byte-positive-int-upper.out | 1 + ...marshalled-two-byte-negative-int-lower.out | Bin 0 -> 6 bytes ...marshalled-two-byte-negative-int-upper.out | 1 + ...marshalled-two-byte-positive-int-lower.out | Bin 0 -> 6 bytes ...marshalled-two-byte-positive-int-upper.out | 1 + spec/tmp/marshalled-zero-byte-int-lower.out | 1 + spec/tmp/marshalled-zero-byte-int-upper.out | 1 + spec/tmp/marshalled-zero.out | Bin 0 -> 4 bytes src/ruby-marshal.cr | 5 +- src/ruby-marshal/stream_object_factory.cr | 8 +- .../stream_objects/byte_sequence.cr | 8 +- src/ruby-marshal/stream_objects/integer.cr | 23 ++++ .../stream_objects/one_byte_int.cr | 27 +++-- .../stream_objects/one_byte_negative_int.cr | 19 ++-- .../stream_objects/one_byte_positive_int.cr | 17 ++- .../stream_objects/three_byte_negative_int.cr | 22 ++-- .../stream_objects/three_byte_positive_int.cr | 7 +- .../stream_objects/two_byte_negative_int.cr | 22 ++-- .../stream_objects/two_byte_positive_int.cr | 20 +++- .../stream_objects/zero_byte_int.cr | 11 +- 31 files changed, 247 insertions(+), 58 deletions(-) create mode 100644 spec/tmp/marshalled-one-byte-int-lower.out create mode 100644 spec/tmp/marshalled-one-byte-int-upper.out create mode 100644 spec/tmp/marshalled-one-byte-int.out create mode 100644 spec/tmp/marshalled-one-byte-negative-int-lower.out create mode 100644 spec/tmp/marshalled-one-byte-negative-int-upper.out create mode 100644 spec/tmp/marshalled-one-byte-positive-int-lower.out create mode 100644 spec/tmp/marshalled-one-byte-positive-int-upper.out create mode 100644 spec/tmp/marshalled-three-byte-negative-int-lower.out create mode 100644 spec/tmp/marshalled-three-byte-negative-int-upper.out create mode 100644 spec/tmp/marshalled-three-byte-positive-int-lower.out create mode 100644 spec/tmp/marshalled-three-byte-positive-int-upper.out create mode 100644 spec/tmp/marshalled-two-byte-negative-int-lower.out create mode 100644 spec/tmp/marshalled-two-byte-negative-int-upper.out create mode 100644 spec/tmp/marshalled-two-byte-positive-int-lower.out create mode 100644 spec/tmp/marshalled-two-byte-positive-int-upper.out create mode 100644 spec/tmp/marshalled-zero-byte-int-lower.out create mode 100644 spec/tmp/marshalled-zero-byte-int-upper.out create mode 100644 spec/tmp/marshalled-zero.out diff --git a/spec/ruby_marshal_dump_spec.cr b/spec/ruby_marshal_dump_spec.cr index bd328d6..571820d 100644 --- a/spec/ruby_marshal_dump_spec.cr +++ b/spec/ruby_marshal_dump_spec.cr @@ -38,4 +38,108 @@ describe Ruby::Marshal do puts object.hexdump end + it "#dump 0" do + File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-zero.out"), "w") { |f| f.write( Ruby::Marshal.dump(0) ) } + object = Ruby::Marshal.dump(0) + puts object.hexdump + end + + it "#dump 122" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-zero-byte-int-upper.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(122) ) } + object = Ruby::Marshal.dump(122) + Ruby::Marshal.load( File.open(f) ).data.should eq(122) + end + + it "#dump -122" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-zero-byte-int-lower.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-122) ) } + object = Ruby::Marshal.dump(-122) + Ruby::Marshal.load( File.open(f) ).data.should eq(-122) + end + + it "#dump -123" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-one-byte-negative-int-upper.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-123) ) } + object = Ruby::Marshal.dump(-123) + Ruby::Marshal.load( File.open(f) ).data.should eq(-123) + end + + it "#dump 123" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-one-byte-positive-int-lower.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(123) ) } + object = Ruby::Marshal.dump(123) + Ruby::Marshal.load( File.open(f) ).data.should eq(123) + end + + it "#dump 255" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-one-byte-positive-int-upper.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(255) ) } + object = Ruby::Marshal.dump(255) + Ruby::Marshal.load( File.open(f) ).data.should eq(255) + end + + it "#dump -256" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-one-byte-negative-int-lower.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-256) ) } + object = Ruby::Marshal.dump(-256) + Ruby::Marshal.load( File.open(f) ).data.should eq(-256) + end + + it "#dump 256" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-two-byte-positive-int-lower.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(256) ) } + object = Ruby::Marshal.dump(256) + Ruby::Marshal.load( File.open(f) ).data.should eq(256) + end + + it "#dump -257" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-two-byte-negative-int-upper.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-257) ) } + object = Ruby::Marshal.dump(-257) + Ruby::Marshal.load( File.open(f) ).data.should eq(-257) + end + + it "#dump 65_535" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-two-byte-positive-int-upper.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(65_535) ) } + object = Ruby::Marshal.dump(65_535) + Ruby::Marshal.load( File.open(f) ).data.should eq(65_535) + end + + it "#dump -65_536" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-two-byte-negative-int-lower.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-65_536) ) } + object = Ruby::Marshal.dump(-65_536) + Ruby::Marshal.load( File.open(f) ).data.should eq(-65_536) + end + + it "#dump 65_536" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-three-byte-positive-int-lower.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(65_536) ) } + object = Ruby::Marshal.dump(65_536) + Ruby::Marshal.load( File.open(f) ).data.should eq(65_536) + end + + it "#dump 16_777_215" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-three-byte-positive-int-upper.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(16_777_215) ) } + object = Ruby::Marshal.dump(16_777_215) + Ruby::Marshal.load( File.open(f) ).data.should eq(16_777_215) + end + + it "#dump -65_537" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-three-byte-negative-int-upper.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-65_537) ) } + object = Ruby::Marshal.dump(-65_537) + Ruby::Marshal.load( File.open(f) ).data.should eq(-65_537) + end + + it "#dump -16_777_216" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-three-byte-negative-int-lower.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-16_777_216) ) } + object = Ruby::Marshal.dump(-16_777_216) + Ruby::Marshal.load( File.open(f) ).data.should eq(-16_777_216) + end + end diff --git a/spec/tmp/marshalled-one-byte-int-lower.out b/spec/tmp/marshalled-one-byte-int-lower.out new file mode 100644 index 0000000..592b54c --- /dev/null +++ b/spec/tmp/marshalled-one-byte-int-lower.out @@ -0,0 +1 @@ +i \ No newline at end of file diff --git a/spec/tmp/marshalled-one-byte-int-upper.out b/spec/tmp/marshalled-one-byte-int-upper.out new file mode 100644 index 0000000..f6df4c5 --- /dev/null +++ b/spec/tmp/marshalled-one-byte-int-upper.out @@ -0,0 +1 @@ +i \ No newline at end of file diff --git a/spec/tmp/marshalled-one-byte-int.out b/spec/tmp/marshalled-one-byte-int.out new file mode 100644 index 0000000..f6df4c5 --- /dev/null +++ b/spec/tmp/marshalled-one-byte-int.out @@ -0,0 +1 @@ +i \ No newline at end of file diff --git a/spec/tmp/marshalled-one-byte-negative-int-lower.out b/spec/tmp/marshalled-one-byte-negative-int-lower.out new file mode 100644 index 0000000000000000000000000000000000000000..c6d33e0e28afbecd78e8c9d8ced4d4bb883971e0 GIT binary patch literal 5 McmZSK$o$U$00VLXbpQYW literal 0 HcmV?d00001 diff --git a/spec/tmp/marshalled-one-byte-negative-int-upper.out b/spec/tmp/marshalled-one-byte-negative-int-upper.out new file mode 100644 index 0000000..67c589f --- /dev/null +++ b/spec/tmp/marshalled-one-byte-negative-int-upper.out @@ -0,0 +1 @@ +i \ No newline at end of file diff --git a/spec/tmp/marshalled-one-byte-positive-int-lower.out b/spec/tmp/marshalled-one-byte-positive-int-lower.out new file mode 100644 index 0000000..5aaade4 --- /dev/null +++ b/spec/tmp/marshalled-one-byte-positive-int-lower.out @@ -0,0 +1 @@ +i{ \ No newline at end of file diff --git a/spec/tmp/marshalled-one-byte-positive-int-upper.out b/spec/tmp/marshalled-one-byte-positive-int-upper.out new file mode 100644 index 0000000..1a92e1e --- /dev/null +++ b/spec/tmp/marshalled-one-byte-positive-int-upper.out @@ -0,0 +1 @@ +i \ No newline at end of file diff --git a/spec/tmp/marshalled-three-byte-negative-int-lower.out b/spec/tmp/marshalled-three-byte-negative-int-lower.out new file mode 100644 index 0000000000000000000000000000000000000000..738d830ee3c2d2bb7c2820525f496a6e457a6c5c GIT binary patch literal 7 OcmZSK$o$K|zyJUSQ~`4U literal 0 HcmV?d00001 diff --git a/spec/tmp/marshalled-three-byte-negative-int-upper.out b/spec/tmp/marshalled-three-byte-negative-int-upper.out new file mode 100644 index 0000000..ec55db2 --- /dev/null +++ b/spec/tmp/marshalled-three-byte-negative-int-upper.out @@ -0,0 +1 @@ +i \ No newline at end of file diff --git a/spec/tmp/marshalled-three-byte-positive-int-lower.out b/spec/tmp/marshalled-three-byte-positive-int-lower.out new file mode 100644 index 0000000000000000000000000000000000000000..df869d7d0ca82167935c7f7600d0f3d4fb55f5b7 GIT binary patch literal 7 OcmZSK$Yf?= -122 && int <= 122 + return OneByteInt.new(int) + elsif int <= -123 && int >= -256 + return OneByteNegativeInt.new(int) + elsif int >= 123 && int <= 255 + return OneBytePositiveInt.new(int) + elsif int <= -257 && int >= -65_536 + return TwoByteNegativeInt.new(int) + elsif int >= 256 && int <= 65_535 + return TwoBytePositiveInt.new(int) + elsif int <= -65_537 && int >= -16_777_216- + return ThreeByteNegativeInt.new(int) + elsif int >= 65_536 && int <= 16_777_215 + return ThreeBytePositiveInt.new(int) + else + return ZeroByteInt.new + end + end + def self.get(stream : Bytes) case stream.first when 0x00 diff --git a/src/ruby-marshal/stream_objects/one_byte_int.cr b/src/ruby-marshal/stream_objects/one_byte_int.cr index b74b461..d83ff8b 100644 --- a/src/ruby-marshal/stream_objects/one_byte_int.cr +++ b/src/ruby-marshal/stream_objects/one_byte_int.cr @@ -6,10 +6,6 @@ module Ruby::Marshal def initialize(stream : Bytes) super(Int32.new(0x01)) - read(stream) - end - - def read(stream : Bytes) data_bytes = stream[0, size] # negative if first bit is 1 if ((data_bytes[0] & (1 << 7)) != 0) @@ -20,19 +16,26 @@ module Ruby::Marshal # subtracting 5 from the value. @data = Int32.new(Int8.new(data_bytes[0] - 5)) end - @data end - def stream_size - # 1 for 8-bit identifier "i" - # 1 for the 1 byte value - return 2 + def initialize(int : ::Int32) + super(Int32.new(0x01)) + @data = int end def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(2) + output[0] = UInt8.new(Integer::TYPE_BYTE) + if @data < 0 + output[1] = UInt8.new((@data - 5)) | (1 << 7) + else + output[1] = UInt8.new(@data + 5) + end + output + end + + def stream_size + 2 end end diff --git a/src/ruby-marshal/stream_objects/one_byte_negative_int.cr b/src/ruby-marshal/stream_objects/one_byte_negative_int.cr index f8e1bcf..933c626 100644 --- a/src/ruby-marshal/stream_objects/one_byte_negative_int.cr +++ b/src/ruby-marshal/stream_objects/one_byte_negative_int.cr @@ -4,22 +4,27 @@ module Ruby::Marshal class OneByteNegativeInt < Integer + SUB_TYPE_BYTE = UInt8.new(0xff) + def initialize(stream : Bytes) super(Int32.new(0x01)) - read(stream) - end - - def read(stream : Bytes) data_bytes = stream[1, size] complement_slice = Slice(UInt8).new(size) data_bytes.each_with_index { |byte, index| complement_slice[index] = ~byte } @data = -(Int32.new(complement_slice.join) + 1) end + def initialize(int : ::Int32) + super(Int32.new(0x01)) + @data = int + end + def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(3) + output[0] = UInt8.new(Integer::TYPE_BYTE) + output[1] = UInt8.new(SUB_TYPE_BYTE) + output[2] = ~UInt8.new(-@data - 1) + output end end diff --git a/src/ruby-marshal/stream_objects/one_byte_positive_int.cr b/src/ruby-marshal/stream_objects/one_byte_positive_int.cr index c2ce8fb..53fa635 100644 --- a/src/ruby-marshal/stream_objects/one_byte_positive_int.cr +++ b/src/ruby-marshal/stream_objects/one_byte_positive_int.cr @@ -4,19 +4,24 @@ module Ruby::Marshal class OneBytePositiveInt < Integer + SUB_TYPE_BYTE = UInt8.new(0x01) + def initialize(stream : Bytes) super(Int32.new(0x01)) - read(stream) + @data = Int32.new(stream[1, size].join) end - def read(stream : Bytes) - @data = Int32.new(stream[1, size].join) + def initialize(int : ::Int32) + super(Int32.new(0x01)) + @data = int end def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(3) + output[0] = UInt8.new(Integer::TYPE_BYTE) + output[1] = UInt8.new(SUB_TYPE_BYTE) + output[2] = UInt8.new(@data) + output end end diff --git a/src/ruby-marshal/stream_objects/three_byte_negative_int.cr b/src/ruby-marshal/stream_objects/three_byte_negative_int.cr index 6d371ad..ce11ba3 100644 --- a/src/ruby-marshal/stream_objects/three_byte_negative_int.cr +++ b/src/ruby-marshal/stream_objects/three_byte_negative_int.cr @@ -4,12 +4,10 @@ module Ruby::Marshal class ThreeByteNegativeInt < Integer + SUB_TYPE_BYTE = UInt8.new(0xfd) + def initialize(stream : Bytes) super(Int32.new(0x03)) - read(stream) - end - - def read(stream : Bytes) stream += 1 data_bytes = Slice(UInt8).new(size) data_bytes.copy_from(stream.to_unsafe, size) @@ -23,10 +21,20 @@ module Ruby::Marshal @data = -(IO::ByteFormat::BigEndian.decode(Int32, padded_slice) + 1) end + def initialize(int : ::Int32) + super(Int32.new(0x02)) + @data = int + end + def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(2) + output[0] = Integer::TYPE_BYTE + output[1] = SUB_TYPE_BYTE + data_slice = ::Bytes.new(3) + io = ::IO::Memory.new(0x03) + @data.to_io(io, ::IO::ByteFormat::LittleEndian) + io.rewind.read(data_slice) + output.concat(data_slice) end end diff --git a/src/ruby-marshal/stream_objects/three_byte_positive_int.cr b/src/ruby-marshal/stream_objects/three_byte_positive_int.cr index cf08fa3..bcb2e4a 100644 --- a/src/ruby-marshal/stream_objects/three_byte_positive_int.cr +++ b/src/ruby-marshal/stream_objects/three_byte_positive_int.cr @@ -4,6 +4,8 @@ module Ruby::Marshal class ThreeBytePositiveInt < Integer + SUB_TYPE_BYTE = UInt8.new(0x03) + def initialize(stream : Bytes) @data = Int32.new(0x00) super(Int32.new(0x03)) @@ -28,8 +30,9 @@ module Ruby::Marshal end def dump - output = ::Bytes.new(1) - output[0] = UInt8.new(0x03) # 3 + output = ::Bytes.new(2) + output[0] = Integer::TYPE_BYTE # 3 + output[1] = SUB_TYPE_BYTE # 3 io = ::IO::Memory.new(0x03) @data.to_io(io, ::IO::ByteFormat::LittleEndian) data_slice = ::Bytes.new(3) diff --git a/src/ruby-marshal/stream_objects/two_byte_negative_int.cr b/src/ruby-marshal/stream_objects/two_byte_negative_int.cr index 6aa7874..82829ca 100644 --- a/src/ruby-marshal/stream_objects/two_byte_negative_int.cr +++ b/src/ruby-marshal/stream_objects/two_byte_negative_int.cr @@ -4,12 +4,10 @@ module Ruby::Marshal class TwoByteNegativeInt < Integer + SUB_TYPE_BYTE = UInt8.new(0xfe) + def initialize(stream : Bytes) super(Int32.new(0x02)) - read(stream) - end - - def read(stream : Bytes) stream += 1 data_bytes = Slice(UInt8).new(size) data_bytes.copy_from(stream.to_unsafe, size) @@ -22,10 +20,20 @@ module Ruby::Marshal @data = -(IO::ByteFormat::BigEndian.decode(Int32, padded_slice) + 1) end + def initialize(int : ::Int32) + super(Int32.new(0x02)) + @data = int + end + def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(2) + output[0] = Integer::TYPE_BYTE + output[1] = SUB_TYPE_BYTE + data_slice = ::Bytes.new(2) + io = ::IO::Memory.new(0x02) + @data.to_io(io, ::IO::ByteFormat::LittleEndian) + io.rewind.read(data_slice) + output.concat(data_slice) end end diff --git a/src/ruby-marshal/stream_objects/two_byte_positive_int.cr b/src/ruby-marshal/stream_objects/two_byte_positive_int.cr index ffbf21e..6799849 100644 --- a/src/ruby-marshal/stream_objects/two_byte_positive_int.cr +++ b/src/ruby-marshal/stream_objects/two_byte_positive_int.cr @@ -4,19 +4,27 @@ module Ruby::Marshal class TwoBytePositiveInt < Integer + SUB_TYPE_BYTE = UInt8.new(0x02) + def initialize(stream : Bytes) super(Int32.new(0x02)) - read(stream) + @data = Int32.new(::IO::ByteFormat::LittleEndian.decode(UInt16, stream[1, size])) end - def read(stream : Bytes) - @data = Int32.new(::IO::ByteFormat::LittleEndian.decode(UInt16, stream[1, size])) + def initialize(int : ::Int32) + super(Int32.new(0x02)) + @data = int end def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(2) + output[0] = UInt8.new(Integer::TYPE_BYTE) + output[1] = UInt8.new(SUB_TYPE_BYTE) + io = ::IO::Memory.new(0x02) + @data.to_io(io, ::IO::ByteFormat::LittleEndian) + data_slice = ::Bytes.new(2) + io.rewind.read(data_slice) + output.concat(data_slice) end end diff --git a/src/ruby-marshal/stream_objects/zero_byte_int.cr b/src/ruby-marshal/stream_objects/zero_byte_int.cr index fda7d31..d8b0ff2 100644 --- a/src/ruby-marshal/stream_objects/zero_byte_int.cr +++ b/src/ruby-marshal/stream_objects/zero_byte_int.cr @@ -8,10 +8,15 @@ module Ruby::Marshal super(Int32.new(0x01)) end + def initialize + super(Int32.new(0x01)) + end + def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(2) + output[0] = UInt8.new(Integer::TYPE_BYTE) + output[1] = UInt8.new(0x00) + output end end From ccd055ea0f2175bd2509a615ec16e27402d8369b Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Sat, 11 Nov 2017 23:58:30 -0800 Subject: [PATCH 05/13] remove trailing hyphen causing weird type inference issue. --- src/ruby-marshal.cr | 5 ++--- src/ruby-marshal/stream_object_factory.cr | 2 +- src/ruby-marshal/stream_objects/integer.cr | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ruby-marshal.cr b/src/ruby-marshal.cr index 099d4b5..56f6151 100644 --- a/src/ruby-marshal.cr +++ b/src/ruby-marshal.cr @@ -64,9 +64,8 @@ module Ruby::Marshal bytestream = ::Bytes.new(2) bytestream[0] = UInt8.new(MAJOR_VERSION) bytestream[1] = UInt8.new(MINOR_VERSION) - result = StreamObjectFactory.from(obj) - t = (!result.nil?) ? result.dump : ::Bytes.new(0) - bytestream.concat(t || ::Bytes.new(0)) + result = StreamObjectFactory.from(obj).dump || ::Bytes.new(0) + bytestream.concat(result) end end diff --git a/src/ruby-marshal/stream_object_factory.cr b/src/ruby-marshal/stream_object_factory.cr index 980b9dc..cc14f89 100644 --- a/src/ruby-marshal/stream_object_factory.cr +++ b/src/ruby-marshal/stream_object_factory.cr @@ -49,7 +49,7 @@ module Ruby::Marshal Ruby::Marshal::Symbol.new(sym) end - def self.from(sym : ::UInt8 |::Int8 | ::UInt16 | ::Int16 | ::UInt32 | ::Int32 | ::UInt64 | ::Int64) : StreamObject | Nil + def self.from(sym : ::UInt8 |::Int8 | ::UInt16 | ::Int16 | ::UInt32 | ::Int32 | ::UInt64 | ::Int64) : StreamObject Ruby::Marshal::Integer.get(sym) end diff --git a/src/ruby-marshal/stream_objects/integer.cr b/src/ruby-marshal/stream_objects/integer.cr index 640a88e..92df5d2 100644 --- a/src/ruby-marshal/stream_objects/integer.cr +++ b/src/ruby-marshal/stream_objects/integer.cr @@ -14,7 +14,7 @@ module Ruby::Marshal @data = Int32.new(0x00) end - def self.get(int : ::UInt8 |::Int8 | ::UInt16 | ::Int16 | ::UInt32 | ::Int32 | ::UInt64 | ::Int64) : StreamObject | Nil + def self.get(int : ::UInt8 |::Int8 | ::UInt16 | ::Int16 | ::UInt32 | ::Int32 | ::UInt64 | ::Int64) : StreamObject if int == 0 return ZeroByteInt.new elsif int >= -122 && int <= 122 @@ -27,7 +27,7 @@ module Ruby::Marshal return TwoByteNegativeInt.new(int) elsif int >= 256 && int <= 65_535 return TwoBytePositiveInt.new(int) - elsif int <= -65_537 && int >= -16_777_216- + elsif int <= -65_537 && int >= -16_777_216 return ThreeByteNegativeInt.new(int) elsif int >= 65_536 && int <= 16_777_215 return ThreeBytePositiveInt.new(int) From 4f2c97f540a5271c94ac4aed8f87245a0a170f42 Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Sun, 12 Nov 2017 00:21:46 -0800 Subject: [PATCH 06/13] finish integer dumps. switch byte sequence to dump with best integer format. --- spec/ruby_marshal_dump_spec.cr | 28 ++++++++++++++++++ spec/tmp/marshalled-class.out | Bin 11 -> 8 bytes ...arshalled-four-byte-negative-int-lower.out | Bin 0 -> 8 bytes ...arshalled-four-byte-negative-int-upper.out | 1 + ...arshalled-four-byte-positive-int-lower.out | Bin 0 -> 8 bytes ...arshalled-four-byte-positive-int-upper.out | 1 + spec/tmp/marshalled-module.out | Bin 17 -> 14 bytes spec/tmp/marshalled-symbol.out | Bin 18 -> 15 bytes .../stream_objects/byte_sequence.cr | 2 +- .../stream_objects/four_byte_negative_int.cr | 22 +++++++++----- .../stream_objects/four_byte_positive_int.cr | 20 +++++++++---- src/ruby-marshal/stream_objects/integer.cr | 4 +++ .../stream_objects/three_byte_positive_int.cr | 14 ++++----- 13 files changed, 69 insertions(+), 23 deletions(-) create mode 100644 spec/tmp/marshalled-four-byte-negative-int-lower.out create mode 100644 spec/tmp/marshalled-four-byte-negative-int-upper.out create mode 100644 spec/tmp/marshalled-four-byte-positive-int-lower.out create mode 100644 spec/tmp/marshalled-four-byte-positive-int-upper.out diff --git a/spec/ruby_marshal_dump_spec.cr b/spec/ruby_marshal_dump_spec.cr index 571820d..e2ce068 100644 --- a/spec/ruby_marshal_dump_spec.cr +++ b/spec/ruby_marshal_dump_spec.cr @@ -142,4 +142,32 @@ describe Ruby::Marshal do Ruby::Marshal.load( File.open(f) ).data.should eq(-16_777_216) end + it "#dump 16_777_216" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-four-byte-positive-int-lower.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(16_777_216) ) } + object = Ruby::Marshal.dump(16_777_216) + Ruby::Marshal.load( File.open(f) ).data.should eq(16_777_216) + end + + it "#dump 1_073_741_823" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-four-byte-positive-int-upper.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(1_073_741_823) ) } + object = Ruby::Marshal.dump(1_073_741_823) + Ruby::Marshal.load( File.open(f) ).data.should eq(1_073_741_823) + end + + it "#dump -16_777_217" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-four-byte-negative-int-upper.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-16_777_217) ) } + object = Ruby::Marshal.dump(-16_777_217) + Ruby::Marshal.load( File.open(f) ).data.should eq(-16_777_217) + end + + it "#dump -1_073_741_824-" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-four-byte-negative-int-lower.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-1_073_741_824) ) } + object = Ruby::Marshal.dump(-1_073_741_824) + Ruby::Marshal.load( File.open(f) ).data.should eq(-1_073_741_824) + end + end diff --git a/spec/tmp/marshalled-class.out b/spec/tmp/marshalled-class.out index 64de5e9c95cbc561bccc861d6d082488f68f085d..bd371216b5594c0176146352ee51270c2f6054e4 100644 GIT binary patch literal 8 PcmZSKNahSJPAvie2FL;! literal 11 ScmZSKNM>eXUk diff --git a/spec/tmp/marshalled-symbol.out b/spec/tmp/marshalled-symbol.out index b6c0bd0b820f8fff433b44645f20ead8882370fe..fd035bfe88eff4aa18f1ac9b1d1afb9d793e9119 100644 GIT binary patch literal 15 WcmZSKuo5UqEiQ>KuFOr!&jA1+(gh3v literal 18 ZcmZSKuwv$BU?@o~E{QL$%uUMA0RSPc1quKF diff --git a/src/ruby-marshal/stream_objects/byte_sequence.cr b/src/ruby-marshal/stream_objects/byte_sequence.cr index cad6898..9153695 100644 --- a/src/ruby-marshal/stream_objects/byte_sequence.cr +++ b/src/ruby-marshal/stream_objects/byte_sequence.cr @@ -13,7 +13,7 @@ module Ruby::Marshal end def initialize(str : ::String) - @length = ThreeBytePositiveInt.new(str.size) + @length = Integer.get(str.size) bytes = str.bytes i = 0 result = ::Bytes.new(bytes.size) diff --git a/src/ruby-marshal/stream_objects/four_byte_negative_int.cr b/src/ruby-marshal/stream_objects/four_byte_negative_int.cr index c15f512..a35e227 100644 --- a/src/ruby-marshal/stream_objects/four_byte_negative_int.cr +++ b/src/ruby-marshal/stream_objects/four_byte_negative_int.cr @@ -4,12 +4,10 @@ module Ruby::Marshal class FourByteNegativeInt < Integer + SUB_TYPE_BYTE = UInt8.new(0xfc) + def initialize(stream : Bytes) super(Int32.new(0x04)) - read(stream) - end - - def read(stream : Bytes) stream += 1 data_bytes = Slice(UInt8).new(size) data_bytes.copy_from(stream.to_unsafe, size) @@ -24,10 +22,20 @@ module Ruby::Marshal @data = -(IO::ByteFormat::BigEndian.decode(Int32, padded_slice) + 1) end + def initialize(int : ::Int32) + super(Int32.new(0x02)) + @data = int + end + def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(2) + output[0] = Integer::TYPE_BYTE + output[1] = SUB_TYPE_BYTE + data_slice = ::Bytes.new(4) + io = ::IO::Memory.new(0x04) + @data.to_io(io, ::IO::ByteFormat::LittleEndian) + io.rewind.read(data_slice) + output.concat(data_slice) end end diff --git a/src/ruby-marshal/stream_objects/four_byte_positive_int.cr b/src/ruby-marshal/stream_objects/four_byte_positive_int.cr index 8b1e9ab..9445837 100644 --- a/src/ruby-marshal/stream_objects/four_byte_positive_int.cr +++ b/src/ruby-marshal/stream_objects/four_byte_positive_int.cr @@ -4,19 +4,27 @@ module Ruby::Marshal class FourBytePositiveInt < Integer + SUB_TYPE_BYTE = UInt8.new(0x04) + def initialize(stream : Bytes) super(Int32.new(0x04)) - read(stream) + @data = ::IO::ByteFormat::LittleEndian.decode(Int32, stream[1, size]) end - def read(stream : Bytes) - @data = ::IO::ByteFormat::LittleEndian.decode(Int32, stream[1, size]) + def initialize(int : ::Int32) + super(Int32.new(0x04)) + @data = int end def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(2) + output[0] = Integer::TYPE_BYTE # 3 + output[1] = SUB_TYPE_BYTE # 3 + io = ::IO::Memory.new(0x04) + @data.to_io(io, ::IO::ByteFormat::LittleEndian) + data_slice = ::Bytes.new(4) + io.rewind.read(data_slice) + output.concat(data_slice) end end diff --git a/src/ruby-marshal/stream_objects/integer.cr b/src/ruby-marshal/stream_objects/integer.cr index 92df5d2..ef8ae07 100644 --- a/src/ruby-marshal/stream_objects/integer.cr +++ b/src/ruby-marshal/stream_objects/integer.cr @@ -31,6 +31,10 @@ module Ruby::Marshal return ThreeByteNegativeInt.new(int) elsif int >= 65_536 && int <= 16_777_215 return ThreeBytePositiveInt.new(int) + elsif int <= -16_777_217 && int >= -1_073_741_824 + return FourByteNegativeInt.new(int) + elsif int >= 16_777_216 && int <= 1_073_741_823 + return FourBytePositiveInt.new(int) else return ZeroByteInt.new end diff --git a/src/ruby-marshal/stream_objects/three_byte_positive_int.cr b/src/ruby-marshal/stream_objects/three_byte_positive_int.cr index bcb2e4a..61a839f 100644 --- a/src/ruby-marshal/stream_objects/three_byte_positive_int.cr +++ b/src/ruby-marshal/stream_objects/three_byte_positive_int.cr @@ -9,15 +9,6 @@ module Ruby::Marshal def initialize(stream : Bytes) @data = Int32.new(0x00) super(Int32.new(0x03)) - read(stream) - end - - def initialize(int : ::Int32) - super(Int32.new(0x03)) - @data = int - end - - def read(stream : Bytes) stream += 1 data_bytes = Slice(UInt8).new(size) data_bytes.copy_from(stream.to_unsafe, size) @@ -29,6 +20,11 @@ module Ruby::Marshal @data = ::IO::ByteFormat::BigEndian.decode(Int32, padded_slice) end + def initialize(int : ::Int32) + super(Int32.new(0x03)) + @data = int + end + def dump output = ::Bytes.new(2) output[0] = Integer::TYPE_BYTE # 3 From ab50d20f11e0b948eb0bf6127bb3120341a56092 Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Sun, 12 Nov 2017 00:28:36 -0800 Subject: [PATCH 07/13] dump spec cleanup. --- spec/ruby_marshal_dump_spec.cr | 35 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/spec/ruby_marshal_dump_spec.cr b/spec/ruby_marshal_dump_spec.cr index e2ce068..ae0a8eb 100644 --- a/spec/ruby_marshal_dump_spec.cr +++ b/spec/ruby_marshal_dump_spec.cr @@ -3,45 +3,52 @@ require "./spec_helper" describe Ruby::Marshal do it "#dump true" do - File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-true.out"), "w") { |f| f.write( Ruby::Marshal.dump(true) ) } + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-true.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(true) ) } object = Ruby::Marshal.dump(true) - puts object.hexdump + Ruby::Marshal.load( File.open(f) ).data.should be_true end it "#dump false" do - File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-false.out"), "w") { |f| f.write( Ruby::Marshal.dump(false) ) } + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-false.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(false) ) } object = Ruby::Marshal.dump(false) - puts object.hexdump + Ruby::Marshal.load( File.open(f) ).data.should be_false end it "#dump nil" do - File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-nil.out"), "w") { |f| f.write( Ruby::Marshal.dump(nil) ) } + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-nil.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(nil) ) } object = Ruby::Marshal.dump(nil) - puts object.hexdump + Ruby::Marshal.load( File.open(f) ).data.should be_nil end it "#dump a class" do - File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-class.out"), "w") { |f| f.write( Ruby::Marshal.dump(User) ) } + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-class.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(User) ) } object = Ruby::Marshal.dump(User) - puts object.hexdump + Ruby::Marshal.load( File.open(f) ).data.should eq("User") end it "#dump a module" do - File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-module.out"), "w") { |f| f.write( Ruby::Marshal.dump(TestModule) ) } + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-module.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(TestModule) ) } object = Ruby::Marshal.dump(TestModule) - puts object.hexdump + Ruby::Marshal.load( File.open(f) ).data.should eq("TestModule") end it "#dump a symbol" do - File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-symbol.out"), "w") { |f| f.write( Ruby::Marshal.dump(:test_symbol) ) } + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-symbol.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(:test_symbol) ) } object = Ruby::Marshal.dump(:test_symbol) - puts object.hexdump + Ruby::Marshal.load( File.open(f) ).data.should eq("test_symbol") end it "#dump 0" do - File.open( File.join(File.dirname( __FILE__ ), "tmp", "marshalled-zero.out"), "w") { |f| f.write( Ruby::Marshal.dump(0) ) } + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-zero.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(0) ) } object = Ruby::Marshal.dump(0) - puts object.hexdump + Ruby::Marshal.load( File.open(f) ).data.should eq(0) end it "#dump 122" do From d8af054a72f63320ff91f8973d05a3bbd24cff59 Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Sun, 12 Nov 2017 15:48:18 -0800 Subject: [PATCH 08/13] float, array, string dump. --- spec/data/generate-marshalled-objects.rb | 2 +- spec/data/marshalled-complex-array.out | Bin 61 -> 67 bytes spec/ruby_marshal_dump_spec.cr | 25 ++++++++++++++- spec/ruby_marshal_load_spec.cr | 2 +- spec/tmp/marshalled-array.out | 1 + spec/tmp/marshalled-float.out | 1 + spec/tmp/marshalled-string.out | 1 + src/ruby-marshal/stream_object_factory.cr | 16 ++++++++-- src/ruby-marshal/stream_objects/array.cr | 30 +++++++++++++++--- src/ruby-marshal/stream_objects/class.cr | 4 +-- src/ruby-marshal/stream_objects/float.cr | 20 ++++++++---- .../stream_objects/instance_object.cr | 4 +-- src/ruby-marshal/stream_objects/string.cr | 20 ++++++++---- 13 files changed, 101 insertions(+), 25 deletions(-) create mode 100644 spec/tmp/marshalled-array.out create mode 100644 spec/tmp/marshalled-float.out create mode 100644 spec/tmp/marshalled-string.out diff --git a/spec/data/generate-marshalled-objects.rb b/spec/data/generate-marshalled-objects.rb index 92d489e..e4765f9 100755 --- a/spec/data/generate-marshalled-objects.rb +++ b/spec/data/generate-marshalled-objects.rb @@ -74,7 +74,7 @@ class UserHash < Hash ; end File.open( File.join(File.dirname( __FILE__ ), 'marshalled-string.out'), 'w') { |f| f.write(Marshal.dump("test_string")) } File.open( File.join(File.dirname( __FILE__ ), 'marshalled-symbol.out'), 'w') { |f| f.write(Marshal.dump(:test_symbol)) } File.open( File.join(File.dirname( __FILE__ ), 'marshalled-symbol-array.out'), 'w') { |f| f.write(Marshal.dump([:hello, :hello])) } -File.open( File.join(File.dirname( __FILE__ ), 'marshalled-complex-array.out'), 'w') { |f| f.write(Marshal.dump([:hello, :hello, [:hello, :test, 1, nil],1_000_000, true, false, nil, "string", "string"])) } +File.open( File.join(File.dirname( __FILE__ ), 'marshalled-complex-array.out'), 'w') { |f| f.write(Marshal.dump([:hello, :hello, [:hello, :test, 1, nil],1_000_000, true, false, nil, "string", "string", -1.2])) } File.open( File.join(File.dirname( __FILE__ ), 'marshalled-hash.out'), 'w') { |f| f.write(Marshal.dump({:simple => 'hash'})) } hash_with_default = Hash.new("default_value") hash_with_default['key'] = 1 diff --git a/spec/data/marshalled-complex-array.out b/spec/data/marshalled-complex-array.out index d93c0602dc1968043e6742ea1c054c831b024ea5..9c48405d357e2a0a9bd12e2be24eba224c13e0e8 100644 GIT binary patch delta 17 YcmcC@W?|uo=AX!7$(F{cYp7=g02(<0`~Uy| delta 10 RcmZ>^Wntln=9|c32>=N!0muLV diff --git a/spec/ruby_marshal_dump_spec.cr b/spec/ruby_marshal_dump_spec.cr index ae0a8eb..3321fd1 100644 --- a/spec/ruby_marshal_dump_spec.cr +++ b/spec/ruby_marshal_dump_spec.cr @@ -170,11 +170,34 @@ describe Ruby::Marshal do Ruby::Marshal.load( File.open(f) ).data.should eq(-16_777_217) end - it "#dump -1_073_741_824-" do + it "#dump -1_073_741_824" do f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-four-byte-negative-int-lower.out") File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-1_073_741_824) ) } object = Ruby::Marshal.dump(-1_073_741_824) Ruby::Marshal.load( File.open(f) ).data.should eq(-1_073_741_824) end + it "#dump -1.26479" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-float.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-1.26479) ) } + object = Ruby::Marshal.dump(-1.26479) + Ruby::Marshal.load( File.open(f) ).data.should eq(-1.26479) + end + + it "#dump \"a string\"" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-string.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump("a string") ) } + object = Ruby::Marshal.dump("a string") + Ruby::Marshal.load( File.open(f) ).data.should eq("a string") + end + + it "#dump an array" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-array.out") + a = ["string", 1, -1.2, nil, true, false, [true, nil, :symbol]] + b = ["string", 1, -1.2, nil, true, false, [true, nil, "symbol"]] + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) } + object = Ruby::Marshal.dump(a) + Ruby::Marshal.load( File.open(f) ).data.should eq(b) + end + end diff --git a/spec/ruby_marshal_load_spec.cr b/spec/ruby_marshal_load_spec.cr index ed960bb..4ca645b 100644 --- a/spec/ruby_marshal_load_spec.cr +++ b/spec/ruby_marshal_load_spec.cr @@ -193,7 +193,7 @@ describe Ruby::Marshal do #puts `xxd #{SPEC_ROOT}/data/marshalled-complex-array.out` object = Ruby::Marshal.load( File.read( "#{SPEC_ROOT}/data/marshalled-complex-array.out" ) ) object.should be_a(Ruby::Marshal::Array) - object.data.should eq(["hello", "hello", ["hello", "test", 1, nil], 1_000_000, true, false, nil, "string", "string"]) + object.data.should eq(["hello", "hello", ["hello", "test", 1, nil], 1_000_000, true, false, nil, "string", "string", -1.2]) end it "should read a marshalled string" do diff --git a/spec/tmp/marshalled-array.out b/spec/tmp/marshalled-array.out new file mode 100644 index 0000000..3ea3036 --- /dev/null +++ b/spec/tmp/marshalled-array.out @@ -0,0 +1 @@ +[ " stringif -1.20TF[T0: symbol \ No newline at end of file diff --git a/spec/tmp/marshalled-float.out b/spec/tmp/marshalled-float.out new file mode 100644 index 0000000..2c52d77 --- /dev/null +++ b/spec/tmp/marshalled-float.out @@ -0,0 +1 @@ +f -1.26479 \ No newline at end of file diff --git a/spec/tmp/marshalled-string.out b/spec/tmp/marshalled-string.out new file mode 100644 index 0000000..495fdd5 --- /dev/null +++ b/spec/tmp/marshalled-string.out @@ -0,0 +1 @@ +" a string \ No newline at end of file diff --git a/src/ruby-marshal/stream_object_factory.cr b/src/ruby-marshal/stream_object_factory.cr index cc14f89..804ba01 100644 --- a/src/ruby-marshal/stream_object_factory.cr +++ b/src/ruby-marshal/stream_object_factory.cr @@ -49,8 +49,20 @@ module Ruby::Marshal Ruby::Marshal::Symbol.new(sym) end - def self.from(sym : ::UInt8 |::Int8 | ::UInt16 | ::Int16 | ::UInt32 | ::Int32 | ::UInt64 | ::Int64) : StreamObject - Ruby::Marshal::Integer.get(sym) + def self.from(int : ::UInt8 |::Int8 | ::UInt16 | ::Int16 | ::UInt32 | ::Int32 | ::UInt64 | ::Int64) : StreamObject + Ruby::Marshal::Integer.get(int) + end + + def self.from(float : ::Float) : StreamObject + Ruby::Marshal::Float.new(float) + end + + def self.from(string : ::String) : StreamObject + Ruby::Marshal::String.new(string) + end + + def self.from(array : ::Array) : StreamObject + Ruby::Marshal::Array.new(array) end end diff --git a/src/ruby-marshal/stream_objects/array.cr b/src/ruby-marshal/stream_objects/array.cr index 232d8aa..573ed1a 100644 --- a/src/ruby-marshal/stream_objects/array.cr +++ b/src/ruby-marshal/stream_objects/array.cr @@ -8,6 +8,7 @@ module Ruby::Marshal alias RubyStreamArray = StreamObject | ::Regex | ::Bytes | ::Float64 | ::Bool | ::Int32 | ::String | ::Nil | ::Array(RubyStreamArray) | ::Hash(StreamObject, StreamObject) @data : RubyStreamArray @num_objects : Int32 + TYPE_BYTE = ::UInt8.new(0x5b) def initialize(stream : Bytes) array_length = Integer.get(stream) @@ -21,7 +22,6 @@ module Ruby::Marshal def read(stream : Bytes) obj_index = 0 - obj_size = 0 while(obj_index < @num_objects) object = StreamObjectFactory.get(stream) @data.as(::Array(RubyStreamArray)) << object.data @@ -31,10 +31,32 @@ module Ruby::Marshal end end + def initialize(array : ::Array) + obj_count = Integer.get(array.size) + @num_objects = obj_count.data + @data = ::Array(RubyStreamArray).new(@num_objects) + s = obj_count.size + obj_index = 0 + while(obj_index < @num_objects) + object = StreamObjectFactory.from(array[obj_index]) + @data.as(::Array(RubyStreamArray)) << object + obj_index += 1 + s += object.stream_size + end + super(s) + end + def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + result = ::Bytes.new(1) + result[0] = TYPE_BYTE + result = result.concat(Integer.get(@num_objects).dump + 1) + obj_index = 0 + while(obj_index < @num_objects) + dumped_obj = @data.as(::Array(RubyStreamArray))[obj_index].as(StreamObject).dump || ::Bytes.new(0) + result = result.concat(dumped_obj) + obj_index += 1 + end + result end end diff --git a/src/ruby-marshal/stream_objects/class.cr b/src/ruby-marshal/stream_objects/class.cr index 6d86323..0b31ecd 100644 --- a/src/ruby-marshal/stream_objects/class.cr +++ b/src/ruby-marshal/stream_objects/class.cr @@ -20,7 +20,7 @@ module Ruby::Marshal getter :data @data : ::String @byte_sequence : ByteSequence - @type_byte = UInt8.new(0x63) + TYPE_BYTE = UInt8.new(0x63) def initialize(stream : Bytes) @byte_sequence = ByteSequence.new(stream) @@ -42,7 +42,7 @@ module Ruby::Marshal def dump result = ::Bytes.new(1) - result[0] = UInt8.new(0x63) + result[0] = TYPE_BYTE result.concat(@byte_sequence.dump) end diff --git a/src/ruby-marshal/stream_objects/float.cr b/src/ruby-marshal/stream_objects/float.cr index 4a6ac94..80eead7 100644 --- a/src/ruby-marshal/stream_objects/float.cr +++ b/src/ruby-marshal/stream_objects/float.cr @@ -17,19 +17,27 @@ module Ruby::Marshal class Float < StreamObject @data : ::Float64 + @byte_sequence : ByteSequence getter :data + TYPE_BYTE = UInt8.new(0x66) def initialize(stream : Bytes) - source = ByteSequence.new(stream) - float_io = ::IO::Memory.new(source.data) + @byte_sequence = ByteSequence.new(stream) + float_io = ::IO::Memory.new(@byte_sequence.data) @data = ::Float64.new(float_io.to_s) - super(source.stream_size) + super(@byte_sequence.stream_size + @byte_sequence.length.size) + end + + def initialize(float : ::Float64) + @byte_sequence = ByteSequence.new(float.to_s) + @data = float + super(@byte_sequence.stream_size) end def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + result = ::Bytes.new(1) + result[0] = UInt8.new(TYPE_BYTE) + result.concat(@byte_sequence.dump) end end diff --git a/src/ruby-marshal/stream_objects/instance_object.cr b/src/ruby-marshal/stream_objects/instance_object.cr index f3449e8..bd9db96 100644 --- a/src/ruby-marshal/stream_objects/instance_object.cr +++ b/src/ruby-marshal/stream_objects/instance_object.cr @@ -18,10 +18,10 @@ module Ruby::Marshal def initialize(stream : Bytes) super(0x00) @data = StreamObjectFactory.get(stream) - stream += 1 + @data.as(Ruby::Marshal::StreamObject).stream_size + stream += @data.as(Ruby::Marshal::StreamObject).stream_size @num_instance_variables = Integer.get(stream) @instance_variables = ::Hash(::String, StreamObject).new - @size = 1 + @data.as(Ruby::Marshal::StreamObject).stream_size + @num_instance_variables.size + @size = @data.as(Ruby::Marshal::StreamObject).stream_size + @num_instance_variables.size stream += @num_instance_variables.size read(stream) Heap.add(self) diff --git a/src/ruby-marshal/stream_objects/string.cr b/src/ruby-marshal/stream_objects/string.cr index 2b0a28c..e88e759 100644 --- a/src/ruby-marshal/stream_objects/string.cr +++ b/src/ruby-marshal/stream_objects/string.cr @@ -11,18 +11,26 @@ module Ruby::Marshal getter :data @data : ::String + @byte_sequence : ByteSequence + TYPE_BYTE = UInt8.new(0x22) def initialize(stream : Bytes) - source = ByteSequence.new(stream) - @data = ::String.new(source.data) - super(source.stream_size) + @byte_sequence = ByteSequence.new(stream) + @data = ::String.new(@byte_sequence.data) + super(@byte_sequence.stream_size + @byte_sequence.length.size) Heap.add(self) end + def initialize(string : ::String) + @byte_sequence = ByteSequence.new(string) + @data = string + super(@byte_sequence.stream_size) + end + def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + result = ::Bytes.new(1) + result[0] = TYPE_BYTE + result.concat(@byte_sequence.dump) end end From 65fd7a378869f44ad96e36611577631d64cc9877 Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Sun, 12 Nov 2017 16:35:38 -0800 Subject: [PATCH 09/13] refactor ByteSequence.stream_size to include the length byte size. --- src/ruby-marshal/stream_objects/byte_sequence.cr | 4 ++-- src/ruby-marshal/stream_objects/float.cr | 2 +- src/ruby-marshal/stream_objects/regex.cr | 9 +++++---- src/ruby-marshal/stream_objects/string.cr | 2 +- src/ruby-marshal/stream_objects/symbol.cr | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/ruby-marshal/stream_objects/byte_sequence.cr b/src/ruby-marshal/stream_objects/byte_sequence.cr index 9153695..9319328 100644 --- a/src/ruby-marshal/stream_objects/byte_sequence.cr +++ b/src/ruby-marshal/stream_objects/byte_sequence.cr @@ -25,13 +25,13 @@ module Ruby::Marshal end def stream_size - @length.data + @length.data + @length.size end def dump : ::Bytes result = @length.dump if result - result[1, result.size - 1].concat(@data) # strip the "i" type byte + (result + 1).concat(@data) # strip the "i" type byte else ::Bytes.new(0).concat(@data) end diff --git a/src/ruby-marshal/stream_objects/float.cr b/src/ruby-marshal/stream_objects/float.cr index 80eead7..a94b28c 100644 --- a/src/ruby-marshal/stream_objects/float.cr +++ b/src/ruby-marshal/stream_objects/float.cr @@ -25,7 +25,7 @@ module Ruby::Marshal @byte_sequence = ByteSequence.new(stream) float_io = ::IO::Memory.new(@byte_sequence.data) @data = ::Float64.new(float_io.to_s) - super(@byte_sequence.stream_size + @byte_sequence.length.size) + super(@byte_sequence.stream_size) end def initialize(float : ::Float64) diff --git a/src/ruby-marshal/stream_objects/regex.cr b/src/ruby-marshal/stream_objects/regex.cr index 72722f8..5dd86fd 100644 --- a/src/ruby-marshal/stream_objects/regex.cr +++ b/src/ruby-marshal/stream_objects/regex.cr @@ -4,7 +4,7 @@ module Ruby::Marshal # “/” represents a regular expression. Following the # type byte is a byte sequence containing the regular - # expression source. Following the type byte is a byte + # expression @byte_sequence. Following the type byte is a byte # containing the regular expression options (case- # insensitive, etc.) as a signed 8-bit value. # @@ -17,13 +17,14 @@ module Ruby::Marshal getter :data @data : ::Regex + @byte_sequence : ByteSequence def initialize(stream : Bytes, @data : ::Regex = ::Regex.new("")) - source = ByteSequence.new(stream) + @byte_sequence = ByteSequence.new(stream) # The flags are a lie. Ruby does not marshal the option data :( #flags = ByteSequence.new(stream) - @data = ::Regex.new(::String.new(source.data)) - super(source.stream_size + source.length.size) + @data = ::Regex.new(::String.new(@byte_sequence.data)) + super(@byte_sequence.stream_size) end def dump diff --git a/src/ruby-marshal/stream_objects/string.cr b/src/ruby-marshal/stream_objects/string.cr index e88e759..2d1b181 100644 --- a/src/ruby-marshal/stream_objects/string.cr +++ b/src/ruby-marshal/stream_objects/string.cr @@ -17,7 +17,7 @@ module Ruby::Marshal def initialize(stream : Bytes) @byte_sequence = ByteSequence.new(stream) @data = ::String.new(@byte_sequence.data) - super(@byte_sequence.stream_size + @byte_sequence.length.size) + super(@byte_sequence.stream_size) Heap.add(self) end diff --git a/src/ruby-marshal/stream_objects/symbol.cr b/src/ruby-marshal/stream_objects/symbol.cr index 317aaf7..3b94154 100644 --- a/src/ruby-marshal/stream_objects/symbol.cr +++ b/src/ruby-marshal/stream_objects/symbol.cr @@ -12,7 +12,7 @@ module Ruby::Marshal def initialize(stream : Bytes) @byte_sequence = ByteSequence.new(stream) @data = ::String.new(@byte_sequence.data) - super(@byte_sequence.stream_size + 1) + super(@byte_sequence.stream_size) Heap.add(self) end From c65473cfb9556df534fff11afa38da7b5515921e Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Mon, 13 Nov 2017 00:27:49 -0800 Subject: [PATCH 10/13] refactor ruby_marshal_properties to Ruby::Marshal.mapping macro to match crystal convention. --- README.md | 7 +++--- spec/ruby_marshal_dump_spec.cr | 30 +++++++++++++++++------ spec/spec_helper.cr | 20 +++++++-------- spec/tmp/marshalled-regex.out | 1 + src/ruby-marshal/mapping.cr | 28 +++++++++++++++++++++ src/ruby-marshal/stream_object_factory.cr | 4 +++ src/ruby-marshal/stream_objects/object.cr | 19 -------------- src/ruby-marshal/stream_objects/regex.cr | 13 +++++++--- 8 files changed, 78 insertions(+), 44 deletions(-) create mode 100644 spec/tmp/marshalled-regex.out create mode 100644 src/ruby-marshal/mapping.cr diff --git a/README.md b/README.md index 3975e1f..372768b 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,7 @@ puts obj.raw_hash.inspect #### Object `Ruby::Marshal.load(::Class, IO)` and `Ruby::Marshal.load(::Class, ::String)` are provided as convenience methods for unmarshalling straight into a Crystal object. Any class passed to these methods must implement `#initialize(obj : ::Ruby::Marshal::StreamObject)` in order to read the marshalled data. -The `ruby_marshal_properties` macro is provided as a convenience for simple marshalled objects. It will auto-unmarshal for you provided the correct schema for the data. +The `Ruby::Marshal.mapping` macro is provided as a convenience for simple marshalled objects. It will auto-unmarshal for you provided the correct schema for the data. Unlike the other datatypes, `#data` in the case of objects will return a `Ruby::Marshall::Null` object. To use an unmarshalled object, cast to `Ruby::Marshal::Object`. You can then reach the data by means of `#read_raw_attr(::String)` or `#read_attr(::String)`. @@ -284,10 +284,9 @@ obj = Ruby::Marshal.load( User, File.read("marshalled-valid.out") ) puts obj.inspect #=> # -# As a convenience to setting these classes up, use the `ruby_marshal_properties` helper macro +# As a convenience to setting these classes up, use the `Ruby::Marshal.mapping` helper macro class User - property :id, :name - ruby_marshal_properties({ id: ::Int32, name: ::String }) + Ruby::Marshal.mapping({ id: ::Int32, name: ::String }) end ``` diff --git a/spec/ruby_marshal_dump_spec.cr b/spec/ruby_marshal_dump_spec.cr index 3321fd1..211c9ee 100644 --- a/spec/ruby_marshal_dump_spec.cr +++ b/spec/ruby_marshal_dump_spec.cr @@ -184,13 +184,6 @@ describe Ruby::Marshal do Ruby::Marshal.load( File.open(f) ).data.should eq(-1.26479) end - it "#dump \"a string\"" do - f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-string.out") - File.open(f, "w") { |f| f.write( Ruby::Marshal.dump("a string") ) } - object = Ruby::Marshal.dump("a string") - Ruby::Marshal.load( File.open(f) ).data.should eq("a string") - end - it "#dump an array" do f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-array.out") a = ["string", 1, -1.2, nil, true, false, [true, nil, :symbol]] @@ -200,4 +193,27 @@ describe Ruby::Marshal do Ruby::Marshal.load( File.open(f) ).data.should eq(b) end + pending "#dump an instance" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-instance-object.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump("a string") ) } + object = Ruby::Marshal.dump("a string") + Ruby::Marshal.load( File.open(f) ).data.should eq("a string") + end + + # TODO - these should dump InstanceObjects + it "#dump an regex" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-regex.out") + a = /[A-Za-z0-9]+/ + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) } + object = Ruby::Marshal.dump(a) + Ruby::Marshal.load( File.open(f) ).data.should eq(a) + end + + it "#dump \"a string\"" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-string.out") + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump("a string") ) } + object = Ruby::Marshal.dump("a string") + Ruby::Marshal.load( File.open(f) ).data.should eq("a string") + end + end diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 09df6e0..35bf93e 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -26,20 +26,18 @@ class User end class ExtendedUser - property :id - ruby_marshal_properties({ id: ::Int32 }) + Ruby::Marshal.mapping({ + id: ::Int32, + }) end struct Customer - property :name, :address, :valid, :age - - def initialize(obj : ::Ruby::Marshal::StreamObject) - obj = obj.as(::Ruby::Marshal::Struct) - @name = obj.read_raw_attr("name").as(::String) - @address = obj.read_raw_attr("address").as(::String) - @valid = obj.read_raw_attr("valid").as(::Bool) - @age = obj.read_raw_attr("age").as(::Int32) - end + Ruby::Marshal.mapping({ + name: ::String, + address: ::String, + valid: ::Bool, + age: ::Int32, + }) end module TestModule diff --git a/spec/tmp/marshalled-regex.out b/spec/tmp/marshalled-regex.out new file mode 100644 index 0000000..89338a9 --- /dev/null +++ b/spec/tmp/marshalled-regex.out @@ -0,0 +1 @@ +/[A-Za-z0-9]+ \ No newline at end of file diff --git a/src/ruby-marshal/mapping.cr b/src/ruby-marshal/mapping.cr new file mode 100644 index 0000000..5ecac6a --- /dev/null +++ b/src/ruby-marshal/mapping.cr @@ -0,0 +1,28 @@ +require "./exception" + +module Ruby::Marshal + + macro mapping(properties) + + {% for prop, klass in properties %} + property :{{ prop.id }} + + def read_ruby_marshalled_{{ prop.id }}(obj : ::Ruby::Marshal::Object | ::Ruby::Marshal::Struct) : {{klass}} + obj.read_raw_attr("{{ prop.id }}").as({{ klass }}) + end + {% end %} + + def initialize(obj : ::Ruby::Marshal::StreamObject) + {% for prop, klass in properties %} + if self.is_a?(::Struct) + @{{ prop.id }} = read_ruby_marshalled_{{ prop.id }}(obj.as(::Ruby::Marshal::Struct)).as({{ klass }}) + elsif self.is_a?(::Object) + @{{ prop.id }} = read_ruby_marshalled_{{ prop.id }}(obj.as(::Ruby::Marshal::Object)).as({{ klass }}) + else; raise Ruby::Marshal::UnsupportedMarshalClass.new + end + {% end %} + end + + end + +end diff --git a/src/ruby-marshal/stream_object_factory.cr b/src/ruby-marshal/stream_object_factory.cr index 804ba01..0aefa08 100644 --- a/src/ruby-marshal/stream_object_factory.cr +++ b/src/ruby-marshal/stream_object_factory.cr @@ -65,6 +65,10 @@ module Ruby::Marshal Ruby::Marshal::Array.new(array) end + def self.from(regex : ::Regex) : StreamObject + Ruby::Marshal::Regex.new(regex) + end + end end diff --git a/src/ruby-marshal/stream_objects/object.cr b/src/ruby-marshal/stream_objects/object.cr index 89116f5..18672fd 100644 --- a/src/ruby-marshal/stream_objects/object.cr +++ b/src/ruby-marshal/stream_objects/object.cr @@ -77,22 +77,3 @@ module Ruby::Marshal end end - -macro ruby_marshal_properties(prop_hash) - - {% for prop, klass in prop_hash %} - @{{ prop.id }} : {{ klass }} - - def read_ruby_marshalled_{{ prop.id }}(marshalled_object : ::Ruby::Marshal::Object) : {{klass}} - marshalled_object.read_raw_attr("{{ prop.id }}").as({{ klass }}) - end - {% end %} - - def initialize(marshalled_object : ::Ruby::Marshal::StreamObject) - marshalled_object = marshalled_object.as(::Ruby::Marshal::Object) - {% for prop, klass in prop_hash %} - @{{ prop.id }} = read_ruby_marshalled_{{ prop.id }}(marshalled_object).as({{ klass }}) - {% end %} - end - -end diff --git a/src/ruby-marshal/stream_objects/regex.cr b/src/ruby-marshal/stream_objects/regex.cr index 5dd86fd..cea414c 100644 --- a/src/ruby-marshal/stream_objects/regex.cr +++ b/src/ruby-marshal/stream_objects/regex.cr @@ -18,6 +18,7 @@ module Ruby::Marshal getter :data @data : ::Regex @byte_sequence : ByteSequence + TYPE_BYTE = UInt8.new(0x2f) def initialize(stream : Bytes, @data : ::Regex = ::Regex.new("")) @byte_sequence = ByteSequence.new(stream) @@ -27,10 +28,16 @@ module Ruby::Marshal super(@byte_sequence.stream_size) end + def initialize(regex : ::Regex) + @byte_sequence = ByteSequence.new(regex.source) + @data = regex + super(@byte_sequence.stream_size) + end + def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + result = ::Bytes.new(1) + result[0] = TYPE_BYTE + result.concat(@byte_sequence.dump) end end From b0f88293869814e8481efc9072111e39fbf16230 Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Mon, 13 Nov 2017 23:22:05 -0800 Subject: [PATCH 11/13] hash#dump + prep for struct dump. --- spec/ruby_marshal_dump_spec.cr | 10 +++++++ spec/tmp/marshalled-hash.out | 1 + src/ruby-marshal/mapping.cr | 12 +++++++++ src/ruby-marshal/stream_object_factory.cr | 8 ++++++ src/ruby-marshal/stream_objects/hash.cr | 33 ++++++++++++++++++----- src/ruby-marshal/stream_objects/struct.cr | 18 ++++++++++--- 6 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 spec/tmp/marshalled-hash.out diff --git a/spec/ruby_marshal_dump_spec.cr b/spec/ruby_marshal_dump_spec.cr index 211c9ee..77f199b 100644 --- a/spec/ruby_marshal_dump_spec.cr +++ b/spec/ruby_marshal_dump_spec.cr @@ -193,6 +193,16 @@ describe Ruby::Marshal do Ruby::Marshal.load( File.open(f) ).data.should eq(b) end + it "#dump a hash" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-hash.out") + a = { "simple" => 1, :hash => -1.2 } + b = { "simple" => 1, "hash" => -1.2 } + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) } + `xxd #{f}` + object = Ruby::Marshal.dump(a) + Ruby::Marshal.load( File.open(f) ).as(Ruby::Marshal::Hash).raw_hash.should eq(b) + end + pending "#dump an instance" do f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-instance-object.out") File.open(f, "w") { |f| f.write( Ruby::Marshal.dump("a string") ) } diff --git a/spec/tmp/marshalled-hash.out b/spec/tmp/marshalled-hash.out new file mode 100644 index 0000000..e6d82cd --- /dev/null +++ b/spec/tmp/marshalled-hash.out @@ -0,0 +1 @@ +{" simplei: hashf -1.2 \ No newline at end of file diff --git a/src/ruby-marshal/mapping.cr b/src/ruby-marshal/mapping.cr index 5ecac6a..00d6e9c 100644 --- a/src/ruby-marshal/mapping.cr +++ b/src/ruby-marshal/mapping.cr @@ -4,6 +4,18 @@ module Ruby::Marshal macro mapping(properties) + def num_instance_vars + Ruby::Marshal::Integer.get({{ properties.size }}) + end + + def instance_vars + Ruby::Marshal::StreamObjectFactory.from({ + {% for prop, klass in properties %} + "{{ prop.id }}" => @{{ prop.id }}, + {% end %} + }) + end + {% for prop, klass in properties %} property :{{ prop.id }} diff --git a/src/ruby-marshal/stream_object_factory.cr b/src/ruby-marshal/stream_object_factory.cr index 0aefa08..7dcc2f4 100644 --- a/src/ruby-marshal/stream_object_factory.cr +++ b/src/ruby-marshal/stream_object_factory.cr @@ -69,6 +69,14 @@ module Ruby::Marshal Ruby::Marshal::Regex.new(regex) end + def self.from(hash : ::Hash) : StreamObject + Ruby::Marshal::Hash.new(hash) + end + + def self.from(str : ::Struct) : StreamObject + Ruby::Marshal::Struct.new(str) + end + end end diff --git a/src/ruby-marshal/stream_objects/hash.cr b/src/ruby-marshal/stream_objects/hash.cr index 1ccd0d0..e8598d6 100644 --- a/src/ruby-marshal/stream_objects/hash.cr +++ b/src/ruby-marshal/stream_objects/hash.cr @@ -14,14 +14,16 @@ module Ruby::Marshal # all the pairs. class Hash < StreamObject - alias RawHashObjects = StreamObject | ::Regex | ::Bytes | ::Bool | ::Int32 | ::String | ::Nil | ::Array(Ruby::Marshal::Array::RubyStreamArray) | ::Hash(Ruby::Marshal::StreamObject, Ruby::Marshal::StreamObject) | ::Float64 | ::Hash(RawHashObjects, RawHashObjects) + alias RawHashObjects = StreamObject | ::Symbol | ::Regex | ::Bytes | ::Bool | ::Int32 | ::String | ::Nil | ::Array(Ruby::Marshal::Array::RubyStreamArray) | ::Hash(Ruby::Marshal::StreamObject, Ruby::Marshal::StreamObject) | ::Float64 | ::Hash(RawHashObjects, RawHashObjects) getter :data, :default_value @data : ::Hash(StreamObject, StreamObject) @num_keys : Integer @default_value : StreamObject | Null + TYPE_BYTE = UInt8.new(0x7b) def initialize(stream : Bytes) + @size = 0 @default_value = Null.new @num_keys = Integer.get(stream) @data = ::Hash(StreamObject, StreamObject).new @@ -31,7 +33,6 @@ module Ruby::Marshal Heap.add(self) end - # instantiate the class if it exists and assign to @data def read(stream : Bytes) i = 0 while(i < @num_keys.data) @@ -44,7 +45,21 @@ module Ruby::Marshal @data[instance_var_name] = instance_var_value i += 1 end - return stream + stream + end + + def initialize(hash : ::Hash(RawHashObjects, RawHashObjects)) + @default_value = Null.new + @data = ::Hash(StreamObject, StreamObject).new + @num_keys = Integer.get(hash.keys.size) + super(@num_keys.size) + hash.each do |key, value| + instance_var_name = StreamObjectFactory.from(key) + @size += instance_var_name.stream_size + instance_var_value = StreamObjectFactory.from(value) + @size += instance_var_value.stream_size + @data[instance_var_name] = instance_var_value + end end def each(&block) @@ -86,9 +101,15 @@ module Ruby::Marshal end def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(1) + output[0] = TYPE_BYTE + output = output.concat(@num_keys.dump + 1) + null = Null.new + @data.each do |(key, value)| + output = output.concat(key.dump || null.dump) + output = output.concat(value.dump || null.dump) + end + output end end diff --git a/src/ruby-marshal/stream_objects/struct.cr b/src/ruby-marshal/stream_objects/struct.cr index d801e06..fd0f083 100644 --- a/src/ruby-marshal/stream_objects/struct.cr +++ b/src/ruby-marshal/stream_objects/struct.cr @@ -22,6 +22,7 @@ module Ruby::Marshal @struct_name : Symbol @num_members : Integer @members : ::Hash(::String, StreamObject) + TYPE_BYTE = UInt8.new(0x53) def initialize(stream : Bytes) super(0x00) @@ -72,10 +73,21 @@ module Ruby::Marshal read_attr(name, true) end + def initialize(str : ::Struct) + @size = 0 + super(@size) + @data = Null.new + @num_members = str.num_instance_vars + @members = str.instance_vars + @struct_name = Symbol.new(str.class.to_s) + end + def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = ::Bytes.new(1) + output[0] = TYPE_BYTE + output = output.concat(@struct_name.dump) + .concat(@num_members.dump) + # .concat(@members.dump) end end From fc7ea439e9d23629753a6dd0c5b1a440ab57ad48 Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Sun, 19 Nov 2017 00:14:58 -0800 Subject: [PATCH 12/13] refactor dump, prep for objects. --- spec/ruby_marshal_dump_spec.cr | 35 +++++++-- spec/spec_helper.cr | 13 ++++ spec/tmp/marshalled-hash-with-default.out | 1 + spec/tmp/marshalled-instance-object.out | 1 + src/ruby-marshal.cr | 10 ++- src/ruby-marshal/hash.cr | 8 ++ src/ruby-marshal/mapping.cr | 4 +- src/ruby-marshal/ruby_marshal_dump.cr | 73 +++++++++++++++++++ src/ruby-marshal/stream_object_factory.cr | 44 ----------- src/ruby-marshal/stream_objects/array.cr | 2 +- src/ruby-marshal/stream_objects/hash.cr | 9 ++- .../stream_objects/hash_with_default.cr | 27 ++++++- .../stream_objects/instance_object.cr | 35 ++++----- src/ruby-marshal/stream_objects/object.cr | 29 ++------ 14 files changed, 186 insertions(+), 105 deletions(-) create mode 100644 spec/tmp/marshalled-hash-with-default.out create mode 100644 spec/tmp/marshalled-instance-object.out create mode 100644 src/ruby-marshal/hash.cr create mode 100644 src/ruby-marshal/ruby_marshal_dump.cr diff --git a/spec/ruby_marshal_dump_spec.cr b/spec/ruby_marshal_dump_spec.cr index 77f199b..493ee0f 100644 --- a/spec/ruby_marshal_dump_spec.cr +++ b/spec/ruby_marshal_dump_spec.cr @@ -198,16 +198,37 @@ describe Ruby::Marshal do a = { "simple" => 1, :hash => -1.2 } b = { "simple" => 1, "hash" => -1.2 } File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) } - `xxd #{f}` object = Ruby::Marshal.dump(a) Ruby::Marshal.load( File.open(f) ).as(Ruby::Marshal::Hash).raw_hash.should eq(b) end - pending "#dump an instance" do + it "#dump a hash with default value" do + f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-hash-with-default.out") + a = Hash(String, String | Int32).new("Default") + a["simple"] = 1 + #puts a["nonexistent"] + File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) } + #puts `xxd #{f}` + object = Ruby::Marshal.dump(a) + r = Ruby::Marshal.load( File.open(f) ).as(Ruby::Marshal::HashWithDefault).raw_hash + r.should eq(a) + r["nada"].should eq("Default") + end + + it "#dump an instance" do f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-instance-object.out") - File.open(f, "w") { |f| f.write( Ruby::Marshal.dump("a string") ) } - object = Ruby::Marshal.dump("a string") - Ruby::Marshal.load( File.open(f) ).data.should eq("a string") + object = DumpTestUser.new + object.id = 1 + object.name = "string name" + object.valid = false + object.opts = { "this" => "hash" } + write = Ruby::Marshal.dump(object) + File.open(f, "w") { |f| f.write(write) } + puts write.inspect + puts `xxd #{f}` + #result = Ruby::Marshal.load( DumpTestUser, File.open(f) ) + #puts result.inspect + #result.should eq(object) end # TODO - these should dump InstanceObjects @@ -216,7 +237,9 @@ describe Ruby::Marshal do a = /[A-Za-z0-9]+/ File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) } object = Ruby::Marshal.dump(a) - Ruby::Marshal.load( File.open(f) ).data.should eq(a) + result = Ruby::Marshal.load( File.open(f) ) + #puts result.inspect + result.data.should eq(a) end it "#dump \"a string\"" do diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 35bf93e..3434aeb 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -26,6 +26,7 @@ class User end class ExtendedUser + Ruby::Marshal.mapping({ id: ::Int32, }) @@ -43,3 +44,15 @@ end module TestModule end + +class DumpTestUser + + def initialize ; end + + Ruby::Marshal.mapping({ + id: ::Int32, + name: ::String, + valid: ::Bool, + opts: ::Hash(String, String), + }) +end diff --git a/spec/tmp/marshalled-hash-with-default.out b/spec/tmp/marshalled-hash-with-default.out new file mode 100644 index 0000000..32adf06 --- /dev/null +++ b/spec/tmp/marshalled-hash-with-default.out @@ -0,0 +1 @@ +}" simplei" simplei0 \ No newline at end of file diff --git a/spec/tmp/marshalled-instance-object.out b/spec/tmp/marshalled-instance-object.out new file mode 100644 index 0000000..e0dcc82 --- /dev/null +++ b/spec/tmp/marshalled-instance-object.out @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/ruby-marshal.cr b/src/ruby-marshal.cr index 56f6151..0aacef2 100644 --- a/src/ruby-marshal.cr +++ b/src/ruby-marshal.cr @@ -18,7 +18,7 @@ module Ruby::Marshal end def self.load(klass : ::Class, source : IO) - klass.new( self._load(source.get_to_end) ) + klass.new( self._load(source.gets_to_end.to_slice) ) end # The first two bytes of the stream contain the major and minor version, each as @@ -61,11 +61,15 @@ module Ruby::Marshal end def self.dump(obj) : ::Bytes + obj_bytes = obj.ruby_marshal_dump.dump + version_bytes.concat(obj_bytes || Null.new.dump) + end + + def self.version_bytes bytestream = ::Bytes.new(2) bytestream[0] = UInt8.new(MAJOR_VERSION) bytestream[1] = UInt8.new(MINOR_VERSION) - result = StreamObjectFactory.from(obj).dump || ::Bytes.new(0) - bytestream.concat(result) + bytestream end end diff --git a/src/ruby-marshal/hash.cr b/src/ruby-marshal/hash.cr new file mode 100644 index 0000000..b14fc91 --- /dev/null +++ b/src/ruby-marshal/hash.cr @@ -0,0 +1,8 @@ +class Hash(K, V) + + def default_value + return (fetch("nonexistent") rescue nil) + fetch(nil) rescue nil + end + +end \ No newline at end of file diff --git a/src/ruby-marshal/mapping.cr b/src/ruby-marshal/mapping.cr index 00d6e9c..fa72f3b 100644 --- a/src/ruby-marshal/mapping.cr +++ b/src/ruby-marshal/mapping.cr @@ -9,11 +9,11 @@ module Ruby::Marshal end def instance_vars - Ruby::Marshal::StreamObjectFactory.from({ + { {% for prop, klass in properties %} "{{ prop.id }}" => @{{ prop.id }}, {% end %} - }) + }.ruby_marshal_dump end {% for prop, klass in properties %} diff --git a/src/ruby-marshal/ruby_marshal_dump.cr b/src/ruby-marshal/ruby_marshal_dump.cr new file mode 100644 index 0000000..9797bca --- /dev/null +++ b/src/ruby-marshal/ruby_marshal_dump.cr @@ -0,0 +1,73 @@ +class Object + def ruby_marshal_dump + Ruby::Marshal::InstanceObject.from(self) + end +end + +struct Nil + def ruby_marshal_dump + Ruby::Marshal::Null.new + end +end + +struct Bool + def ruby_marshal_dump + self ? Ruby::Marshal::True.new(self) : Ruby::Marshal::False.new(self) + end +end + +class Class + def ruby_marshal_dump + Ruby::Marshal::Class.new(self) + end +end + +struct Symbol + def ruby_marshal_dump + Ruby::Marshal::Symbol.new(self) + end +end + +struct Int + def ruby_marshal_dump + Ruby::Marshal::Integer.get(self) + end +end + +struct Float + def ruby_marshal_dump + Ruby::Marshal::Float.new(self) + end +end + +class String + def ruby_marshal_dump + Ruby::Marshal::String.new(self) + end +end + +class Array + def ruby_marshal_dump + Ruby::Marshal::Array.new(self) + end +end + +class Regex + def ruby_marshal_dump + Ruby::Marshal::Regex.new(self) + end +end + +class Hash + def ruby_marshal_dump + self.default_value ? + Ruby::Marshal::HashWithDefault.new(self) : + Ruby::Marshal::Hash.new(self) + end +end + +struct Struct + def ruby_marshal_dump + Ruby::Marshal::Struct.new(self) + end +end diff --git a/src/ruby-marshal/stream_object_factory.cr b/src/ruby-marshal/stream_object_factory.cr index 7dcc2f4..e8f83c0 100644 --- a/src/ruby-marshal/stream_object_factory.cr +++ b/src/ruby-marshal/stream_object_factory.cr @@ -33,50 +33,6 @@ module Ruby::Marshal end end - def self.from(obj : ::Bool) : StreamObject - obj ? True.new(obj) : False.new(obj) - end - - def self.from(obj : ::Nil) : StreamObject - Null.new - end - - def self.from(obj : ::Class) : StreamObject - Ruby::Marshal::Class.new(obj) - end - - def self.from(sym : ::Symbol) : StreamObject - Ruby::Marshal::Symbol.new(sym) - end - - def self.from(int : ::UInt8 |::Int8 | ::UInt16 | ::Int16 | ::UInt32 | ::Int32 | ::UInt64 | ::Int64) : StreamObject - Ruby::Marshal::Integer.get(int) - end - - def self.from(float : ::Float) : StreamObject - Ruby::Marshal::Float.new(float) - end - - def self.from(string : ::String) : StreamObject - Ruby::Marshal::String.new(string) - end - - def self.from(array : ::Array) : StreamObject - Ruby::Marshal::Array.new(array) - end - - def self.from(regex : ::Regex) : StreamObject - Ruby::Marshal::Regex.new(regex) - end - - def self.from(hash : ::Hash) : StreamObject - Ruby::Marshal::Hash.new(hash) - end - - def self.from(str : ::Struct) : StreamObject - Ruby::Marshal::Struct.new(str) - end - end end diff --git a/src/ruby-marshal/stream_objects/array.cr b/src/ruby-marshal/stream_objects/array.cr index 573ed1a..8b44d32 100644 --- a/src/ruby-marshal/stream_objects/array.cr +++ b/src/ruby-marshal/stream_objects/array.cr @@ -38,7 +38,7 @@ module Ruby::Marshal s = obj_count.size obj_index = 0 while(obj_index < @num_objects) - object = StreamObjectFactory.from(array[obj_index]) + object = array[obj_index].ruby_marshal_dump @data.as(::Array(RubyStreamArray)) << object obj_index += 1 s += object.stream_size diff --git a/src/ruby-marshal/stream_objects/hash.cr b/src/ruby-marshal/stream_objects/hash.cr index e8598d6..9209912 100644 --- a/src/ruby-marshal/stream_objects/hash.cr +++ b/src/ruby-marshal/stream_objects/hash.cr @@ -1,5 +1,6 @@ require "./stream_object" require "./array" +require "../hash" require "./object_pointer" module Ruby::Marshal @@ -16,7 +17,7 @@ module Ruby::Marshal alias RawHashObjects = StreamObject | ::Symbol | ::Regex | ::Bytes | ::Bool | ::Int32 | ::String | ::Nil | ::Array(Ruby::Marshal::Array::RubyStreamArray) | ::Hash(Ruby::Marshal::StreamObject, Ruby::Marshal::StreamObject) | ::Float64 | ::Hash(RawHashObjects, RawHashObjects) - getter :data, :default_value + getter :data, :default_value, :num_keys @data : ::Hash(StreamObject, StreamObject) @num_keys : Integer @default_value : StreamObject | Null @@ -49,14 +50,15 @@ module Ruby::Marshal end def initialize(hash : ::Hash(RawHashObjects, RawHashObjects)) + @size = 0 @default_value = Null.new @data = ::Hash(StreamObject, StreamObject).new @num_keys = Integer.get(hash.keys.size) super(@num_keys.size) hash.each do |key, value| - instance_var_name = StreamObjectFactory.from(key) + instance_var_name = key.ruby_marshal_dump @size += instance_var_name.stream_size - instance_var_value = StreamObjectFactory.from(value) + instance_var_value = value.ruby_marshal_dump @size += instance_var_value.stream_size @data[instance_var_name] = instance_var_value end @@ -103,6 +105,7 @@ module Ruby::Marshal def dump output = ::Bytes.new(1) output[0] = TYPE_BYTE + #puts @default_value output = output.concat(@num_keys.dump + 1) null = Null.new @data.each do |(key, value)| diff --git a/src/ruby-marshal/stream_objects/hash_with_default.cr b/src/ruby-marshal/stream_objects/hash_with_default.cr index 2e7e431..a3afb29 100644 --- a/src/ruby-marshal/stream_objects/hash_with_default.cr +++ b/src/ruby-marshal/stream_objects/hash_with_default.cr @@ -7,7 +7,10 @@ module Ruby::Marshal # all the pairs. class HashWithDefault < Hash + TYPE_BYTE = UInt8.new(0x7d) + def initialize(stream : Bytes) + @num_keys = Integer.get(0) @default_value = Null.new super(stream) data_with_default = ::Hash(StreamObject, StreamObject).new { @default_value } @@ -22,10 +25,28 @@ module Ruby::Marshal @default_value = StreamObjectFactory.get(stream) end + def initialize(hash : ::Hash(RawHashObjects, RawHashObjects)) + @size = 0 + tmp_default = hash.default_value + @default_value = tmp_default.ruby_marshal_dump + #puts @default_value.inspect + #puts @default_value.dump + @data = ::Hash(StreamObject, StreamObject).new + @num_keys = Integer.get(hash.keys.size) + super(hash) + hash.each do |key, value| + instance_var_name = key.ruby_marshal_dump + @size += instance_var_name.stream_size + instance_var_value = value.ruby_marshal_dump + @size += instance_var_value.stream_size + @data[instance_var_name] = instance_var_value + end + end + def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + output = super() + output[0] = TYPE_BYTE + output.concat(@default_value.dump || ::Bytes.new(0)) end end diff --git a/src/ruby-marshal/stream_objects/instance_object.cr b/src/ruby-marshal/stream_objects/instance_object.cr index bd9db96..74b7298 100644 --- a/src/ruby-marshal/stream_objects/instance_object.cr +++ b/src/ruby-marshal/stream_objects/instance_object.cr @@ -13,33 +13,28 @@ module Ruby::Marshal getter :data @num_instance_variables : Integer - @instance_variables : ::Hash(::String, StreamObject) + @instance_variables : Hash def initialize(stream : Bytes) super(0x00) @data = StreamObjectFactory.get(stream) - stream += @data.as(Ruby::Marshal::StreamObject).stream_size - @num_instance_variables = Integer.get(stream) - @instance_variables = ::Hash(::String, StreamObject).new - @size = @data.as(Ruby::Marshal::StreamObject).stream_size + @num_instance_variables.size - stream += @num_instance_variables.size - read(stream) + stream += @data.stream_size + @instance_variables = Hash.new(stream) + @num_instance_variables = @instance_variables.num_keys + @size = @instance_variables.stream_size + @data.stream_size - 1 Heap.add(self) end - # read instance variables - def read(stream : Bytes) - i = 0 - while(i < @num_instance_variables.data) - instance_var_name = StreamObjectFactory.get(stream) - stream += instance_var_name.stream_size - @size += instance_var_name.stream_size - instance_var_value = StreamObjectFactory.get(stream) - stream += instance_var_value.stream_size - @size += instance_var_value.stream_size - @instance_variables[instance_var_name.data.as(::String)] = instance_var_value - i += 1 - end + def initialize(num_vars : Integer, vars : Hash) + super(0x00) + @data = Null.new + @num_instance_variables = num_vars + @instance_variables = vars + @size = @num_instance_variables.stream_size + @instance_variables.stream_size - 1 + end + + def self.from(obj : ::Object) + InstanceObject.new(obj.num_instance_vars, obj.instance_vars) end def data diff --git a/src/ruby-marshal/stream_objects/object.cr b/src/ruby-marshal/stream_objects/object.cr index 18672fd..a1aeca2 100644 --- a/src/ruby-marshal/stream_objects/object.cr +++ b/src/ruby-marshal/stream_objects/object.cr @@ -16,43 +16,26 @@ module Ruby::Marshal getter :data @class_name : Symbol @num_instance_variables : Integer - @instance_variables : ::Hash(::String, StreamObject) + @instance_variables : Hash def initialize(stream : Bytes) super(0x00) @class_name = StreamObjectFactory.get(stream).as(Symbol) @data = Null.new(stream) stream += @class_name.stream_size - @num_instance_variables = Integer.get(stream) - @instance_variables = ::Hash(::String, StreamObject).new - stream += @num_instance_variables.size - @size = @num_instance_variables.size + @class_name.stream_size - read(stream) + @instance_variables = Hash.new(stream) + @num_instance_variables = @instance_variables.num_keys + @size = @instance_variables.stream_size + @class_name.stream_size - 1 Heap.add(self) end - def read(stream : Bytes) - i = 0 - while(i < @num_instance_variables.data) - instance_var_name = StreamObjectFactory.get(stream) - stream += instance_var_name.stream_size - @size += instance_var_name.stream_size - instance_var_value = StreamObjectFactory.get(stream) - stream += instance_var_value.stream_size - @size += instance_var_value.stream_size - @instance_variables[instance_var_name.data.as(::String)] = instance_var_value - i += 1 - end - return stream - end - def populate_class(klass : ::Object) klass.new(self) end def read_attr(name : ::String, raw = false) - key = @instance_variables.has_key?(name) ? name : "@#{name}" - attr = @instance_variables.has_key?(key) ? @instance_variables[key] : nil + key = @instance_variables.raw_hash.has_key?(name) ? name : "@#{name}" + attr = @instance_variables.raw_hash.has_key?(key) ? @instance_variables[key] : nil if(raw && !attr.nil?) if (attr.is_a?(::Hash)) return attr.raw_hash From 13db5bdda2f8138cac26ec6d51a1d2c86e3f2f8c Mon Sep 17 00:00:00 2001 From: Derek Decker Date: Mon, 20 Nov 2017 00:41:10 -0800 Subject: [PATCH 13/13] objects partially working, instance variables that are hashes break casting. --- spec/ruby_marshal_dump_spec.cr | 8 ++- spec/ruby_marshal_load_spec.cr | 25 ++++------ spec/spec_helper.cr | 12 ++--- spec/tmp/marshalled-array.out | 2 +- spec/tmp/marshalled-hash-with-default.out | 2 +- spec/tmp/marshalled-hash.out | 2 +- spec/tmp/marshalled-instance-object.out | 4 +- src/ruby-marshal/mapping.cr | 4 +- src/ruby-marshal/ruby_marshal_dump.cr | 2 +- src/ruby-marshal/stream_objects/array.cr | 13 +++-- src/ruby-marshal/stream_objects/hash.cr | 43 ++++++---------- .../stream_objects/hash_with_default.cr | 18 +++---- .../stream_objects/instance_object.cr | 2 +- src/ruby-marshal/stream_objects/object.cr | 38 ++++++++------ .../stream_objects/object_pointer.cr | 8 +-- src/ruby-marshal/stream_objects/struct.cr | 50 +++++-------------- src/ruby-marshal/stream_objects/symbol.cr | 2 +- src/ruby-marshal/stream_objects/user_class.cr | 12 ++--- 18 files changed, 97 insertions(+), 150 deletions(-) diff --git a/spec/ruby_marshal_dump_spec.cr b/spec/ruby_marshal_dump_spec.cr index 493ee0f..385b3d5 100644 --- a/spec/ruby_marshal_dump_spec.cr +++ b/spec/ruby_marshal_dump_spec.cr @@ -199,7 +199,7 @@ describe Ruby::Marshal do b = { "simple" => 1, "hash" => -1.2 } File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) } object = Ruby::Marshal.dump(a) - Ruby::Marshal.load( File.open(f) ).as(Ruby::Marshal::Hash).raw_hash.should eq(b) + Ruby::Marshal.load( File.open(f) ).as(Ruby::Marshal::Hash).data.should eq(b) end it "#dump a hash with default value" do @@ -210,7 +210,7 @@ describe Ruby::Marshal do File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) } #puts `xxd #{f}` object = Ruby::Marshal.dump(a) - r = Ruby::Marshal.load( File.open(f) ).as(Ruby::Marshal::HashWithDefault).raw_hash + r = Ruby::Marshal.load( File.open(f) ).as(Ruby::Marshal::HashWithDefault).data r.should eq(a) r["nada"].should eq("Default") end @@ -221,11 +221,9 @@ describe Ruby::Marshal do object.id = 1 object.name = "string name" object.valid = false - object.opts = { "this" => "hash" } + #object.opts = { "this" => "hash" } write = Ruby::Marshal.dump(object) File.open(f, "w") { |f| f.write(write) } - puts write.inspect - puts `xxd #{f}` #result = Ruby::Marshal.load( DumpTestUser, File.open(f) ) #puts result.inspect #result.should eq(object) diff --git a/spec/ruby_marshal_load_spec.cr b/spec/ruby_marshal_load_spec.cr index 4ca645b..bc50ebd 100644 --- a/spec/ruby_marshal_load_spec.cr +++ b/spec/ruby_marshal_load_spec.cr @@ -209,12 +209,12 @@ describe Ruby::Marshal do object.read_attr("id", true).should eq(1) object.read_attr("name", true).should eq("Test") object.read_attr("valid", true).should eq(true) - data_hash = object.read_attr("data").as(Ruby::Marshal::Hash) - data_hash["some"].data.should eq(true) - data_hash[1].data.should eq("extra") - data_hash.data.each do |(k, v)| - if(k.class == Ruby::Marshal::Hash) - v.data.should eq(0x01) + data_hash = object.read_attr("data").as(Hash) + data_hash["some"].should eq(true) + data_hash[1].should eq("extra") + data_hash.each do |(k, v)| + if(k.class == Hash) + v.should eq(0x01) end end end @@ -238,16 +238,14 @@ describe Ruby::Marshal do it "should read a marshalled hash" do #puts `xxd #{SPEC_ROOT}/data/marshalled-hash.out` object = Ruby::Marshal.load( File.read( "#{SPEC_ROOT}/data/marshalled-hash.out" ) ) - object.as(::Ruby::Marshal::Hash)["simple"].data.should eq("hash") + object.as(::Ruby::Marshal::Hash)["simple"].should eq("hash") end it "should read a marshalled hash with a default" do #puts `xxd #{SPEC_ROOT}/data/marshalled-hash-with-default.out` object = Ruby::Marshal.load( File.read( "#{SPEC_ROOT}/data/marshalled-hash-with-default.out" ) ).as(Ruby::Marshal::Hash) - object["key"].data.should eq(1) - object.default_value.data.should eq("default_value") - raw_hash = object.raw_hash - raw_hash["new_key"].should eq("default_value") + object["key"].should eq(1) + object.default_value.should eq("default_value") end it "should read a marshalled class" do @@ -295,9 +293,8 @@ describe Ruby::Marshal do object.should be_a(Ruby::Marshal::UserClass) object = object.as(Ruby::Marshal::UserClass) object.class_name.data.should eq("UserHash") - object.data.should be_a(Ruby::Marshal::HashWithDefault) - wrapped_object = object.data.as(Ruby::Marshal::HashWithDefault) - wrapped_object["data"].data.should eq(123) + wrapped_object = object.data.as(Hash) + wrapped_object["data"].should eq(123) end end diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 3434aeb..34c9393 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -13,14 +13,10 @@ class User @name = marshalled_object.read_raw_attr("name").as(::String) @valid = marshalled_object.read_raw_attr("valid").as(::Bool) @data = ::Hash(::String | ::Int32 | ::Hash(::String, ::Int32), ::Bool | ::String | ::Int32).new - raw_data = marshalled_object.read_attr("data").as(::Ruby::Marshal::Hash) - @data["some"] = raw_data["some"].data.as(::Bool) - @data[1] = raw_data[1].data.as(::String) - raw_data.each do |(k,v )| - if(k.class == Ruby::Marshal::Hash) - @data[{"key" => 1}] = v.data.as(::Int32) - end - end + raw_data = marshalled_object.read_attr("data").as(::Hash) + @data["some"] = raw_data["some"].as(::Bool) + @data[1] = raw_data[1].as(::String) + @data[{"key" => 1}] = raw_data[{"key" => 1}].as(Int32) end end diff --git a/spec/tmp/marshalled-array.out b/spec/tmp/marshalled-array.out index 3ea3036..25b31c3 100644 --- a/spec/tmp/marshalled-array.out +++ b/spec/tmp/marshalled-array.out @@ -1 +1 @@ -[ " stringif -1.20TF[T0: symbol \ No newline at end of file +[ " stringif -1.20TF[T0" symbol \ No newline at end of file diff --git a/spec/tmp/marshalled-hash-with-default.out b/spec/tmp/marshalled-hash-with-default.out index 32adf06..d6b84e9 100644 --- a/spec/tmp/marshalled-hash-with-default.out +++ b/spec/tmp/marshalled-hash-with-default.out @@ -1 +1 @@ -}" simplei" simplei0 \ No newline at end of file +}" simplei0 \ No newline at end of file diff --git a/spec/tmp/marshalled-hash.out b/spec/tmp/marshalled-hash.out index e6d82cd..c549eb5 100644 --- a/spec/tmp/marshalled-hash.out +++ b/spec/tmp/marshalled-hash.out @@ -1 +1 @@ -{" simplei: hashf -1.2 \ No newline at end of file +{" simplei" hashf -1.2 \ No newline at end of file diff --git a/spec/tmp/marshalled-instance-object.out b/spec/tmp/marshalled-instance-object.out index e0dcc82..56a5662 100644 --- a/spec/tmp/marshalled-instance-object.out +++ b/spec/tmp/marshalled-instance-object.out @@ -1 +1,3 @@ -0 \ No newline at end of file +o:DumpTestUser "@idi" +@name"string name" @validF" +@opts0 \ No newline at end of file diff --git a/src/ruby-marshal/mapping.cr b/src/ruby-marshal/mapping.cr index fa72f3b..08cfc0c 100644 --- a/src/ruby-marshal/mapping.cr +++ b/src/ruby-marshal/mapping.cr @@ -11,7 +11,7 @@ module Ruby::Marshal def instance_vars { {% for prop, klass in properties %} - "{{ prop.id }}" => @{{ prop.id }}, + :"@{{ prop.id }}" => @{{ prop.id }}, {% end %} }.ruby_marshal_dump end @@ -20,7 +20,7 @@ module Ruby::Marshal property :{{ prop.id }} def read_ruby_marshalled_{{ prop.id }}(obj : ::Ruby::Marshal::Object | ::Ruby::Marshal::Struct) : {{klass}} - obj.read_raw_attr("{{ prop.id }}").as({{ klass }}) + {{ klass }}.cast(obj.read_raw_attr("{{ prop.id }}")) end {% end %} diff --git a/src/ruby-marshal/ruby_marshal_dump.cr b/src/ruby-marshal/ruby_marshal_dump.cr index 9797bca..484b211 100644 --- a/src/ruby-marshal/ruby_marshal_dump.cr +++ b/src/ruby-marshal/ruby_marshal_dump.cr @@ -1,6 +1,6 @@ class Object def ruby_marshal_dump - Ruby::Marshal::InstanceObject.from(self) + Ruby::Marshal::Object.from(self) end end diff --git a/src/ruby-marshal/stream_objects/array.cr b/src/ruby-marshal/stream_objects/array.cr index 8b44d32..0c9575e 100644 --- a/src/ruby-marshal/stream_objects/array.cr +++ b/src/ruby-marshal/stream_objects/array.cr @@ -5,15 +5,14 @@ module Ruby::Marshal class Array < StreamObject getter :data - alias RubyStreamArray = StreamObject | ::Regex | ::Bytes | ::Float64 | ::Bool | ::Int32 | ::String | ::Nil | ::Array(RubyStreamArray) | ::Hash(StreamObject, StreamObject) - @data : RubyStreamArray + @data : ::Array(Hash::RawHashObjects) @num_objects : Int32 TYPE_BYTE = ::UInt8.new(0x5b) def initialize(stream : Bytes) array_length = Integer.get(stream) @num_objects = array_length.data - @data = ::Array(RubyStreamArray).new(@num_objects) + @data = ::Array(Hash::RawHashObjects).new(@num_objects) super(array_length.size) stream += @size read(stream) @@ -24,7 +23,7 @@ module Ruby::Marshal obj_index = 0 while(obj_index < @num_objects) object = StreamObjectFactory.get(stream) - @data.as(::Array(RubyStreamArray)) << object.data + @data << object.data obj_index += 1 stream += object.stream_size @size += object.stream_size @@ -34,12 +33,12 @@ module Ruby::Marshal def initialize(array : ::Array) obj_count = Integer.get(array.size) @num_objects = obj_count.data - @data = ::Array(RubyStreamArray).new(@num_objects) + @data = ::Array(Hash::RawHashObjects).new(@num_objects) s = obj_count.size obj_index = 0 while(obj_index < @num_objects) object = array[obj_index].ruby_marshal_dump - @data.as(::Array(RubyStreamArray)) << object + @data.as(::Array(Hash::RawHashObjects)) << object.data obj_index += 1 s += object.stream_size end @@ -52,7 +51,7 @@ module Ruby::Marshal result = result.concat(Integer.get(@num_objects).dump + 1) obj_index = 0 while(obj_index < @num_objects) - dumped_obj = @data.as(::Array(RubyStreamArray))[obj_index].as(StreamObject).dump || ::Bytes.new(0) + dumped_obj = @data[obj_index].ruby_marshal_dump.dump || ::Bytes.new(0) result = result.concat(dumped_obj) obj_index += 1 end diff --git a/src/ruby-marshal/stream_objects/hash.cr b/src/ruby-marshal/stream_objects/hash.cr index 9209912..3a93bb1 100644 --- a/src/ruby-marshal/stream_objects/hash.cr +++ b/src/ruby-marshal/stream_objects/hash.cr @@ -15,19 +15,19 @@ module Ruby::Marshal # all the pairs. class Hash < StreamObject - alias RawHashObjects = StreamObject | ::Symbol | ::Regex | ::Bytes | ::Bool | ::Int32 | ::String | ::Nil | ::Array(Ruby::Marshal::Array::RubyStreamArray) | ::Hash(Ruby::Marshal::StreamObject, Ruby::Marshal::StreamObject) | ::Float64 | ::Hash(RawHashObjects, RawHashObjects) + alias RawHashObjects = ::Symbol | ::Float64 | ::Regex | ::Bytes | ::Bool | ::Int32 | ::String | ::Nil | ::Array(RawHashObjects) | ::Hash(RawHashObjects, RawHashObjects) getter :data, :default_value, :num_keys - @data : ::Hash(StreamObject, StreamObject) + @data : ::Hash(RawHashObjects, RawHashObjects) # RawHashObjects # ::Hash(StreamObject, StreamObject) @num_keys : Integer - @default_value : StreamObject | Null + @default_value : RawHashObjects TYPE_BYTE = UInt8.new(0x7b) def initialize(stream : Bytes) @size = 0 - @default_value = Null.new + @default_value = nil @num_keys = Integer.get(stream) - @data = ::Hash(StreamObject, StreamObject).new + @data = ::Hash(RawHashObjects, RawHashObjects).new stream += @num_keys.size super(@num_keys.size) read(stream) @@ -43,7 +43,7 @@ module Ruby::Marshal instance_var_value = StreamObjectFactory.get(stream) stream += instance_var_value.stream_size @size += instance_var_value.stream_size - @data[instance_var_name] = instance_var_value + @data[instance_var_name.data] = instance_var_value.data i += 1 end stream @@ -51,8 +51,8 @@ module Ruby::Marshal def initialize(hash : ::Hash(RawHashObjects, RawHashObjects)) @size = 0 - @default_value = Null.new - @data = ::Hash(StreamObject, StreamObject).new + @default_value = nil + @data = ::Hash(RawHashObjects, RawHashObjects).new @num_keys = Integer.get(hash.keys.size) super(@num_keys.size) hash.each do |key, value| @@ -60,7 +60,7 @@ module Ruby::Marshal @size += instance_var_name.stream_size instance_var_value = value.ruby_marshal_dump @size += instance_var_value.stream_size - @data[instance_var_name] = instance_var_value + @data[instance_var_name.data] = instance_var_value.data end end @@ -72,10 +72,10 @@ module Ruby::Marshal macro add_hash_accessor(klass) def [](requested_key : {{klass}}) - result = Null.new + result = nil @data.each do |(k, v)| - if(k.data.class == {{klass}}) - if k.data.as({{klass}}) == requested_key + if(k.class == {{klass}}) + if k.as({{klass}}) == requested_key result = v break end @@ -88,29 +88,14 @@ module Ruby::Marshal add_hash_accessor ::String add_hash_accessor ::Int32 - def raw_hash : ::Hash(RawHashObjects, RawHashObjects) - unless @default_value.data.nil? - raw_hash = ::Hash(RawHashObjects, RawHashObjects).new { @default_value.data } - else - raw_hash = ::Hash(RawHashObjects, RawHashObjects).new - end - @data.each do |(k, v)| - key = (k.class == Ruby::Marshal::Hash) ? k.as(Hash).raw_hash : k.data - value = (v.class == Ruby::Marshal::Hash) ? v.as(Hash).raw_hash : v.data - raw_hash[key] = value - end - raw_hash - end - def dump output = ::Bytes.new(1) output[0] = TYPE_BYTE - #puts @default_value output = output.concat(@num_keys.dump + 1) null = Null.new @data.each do |(key, value)| - output = output.concat(key.dump || null.dump) - output = output.concat(value.dump || null.dump) + output = output.concat(key.ruby_marshal_dump.dump || null.dump) + output = output.concat(value.ruby_marshal_dump.dump || null.dump) end output end diff --git a/src/ruby-marshal/stream_objects/hash_with_default.cr b/src/ruby-marshal/stream_objects/hash_with_default.cr index a3afb29..7e0a625 100644 --- a/src/ruby-marshal/stream_objects/hash_with_default.cr +++ b/src/ruby-marshal/stream_objects/hash_with_default.cr @@ -11,27 +11,25 @@ module Ruby::Marshal def initialize(stream : Bytes) @num_keys = Integer.get(0) - @default_value = Null.new + @default_value = nil super(stream) - data_with_default = ::Hash(StreamObject, StreamObject).new { @default_value } + data_with_default = ::Hash(RawHashObjects, RawHashObjects).new { @default_value.ruby_marshal_dump.data } data_with_default.merge!(@data) @data = data_with_default - @size += @default_value.stream_size + @size += @default_value.ruby_marshal_dump.stream_size end def read(stream : Bytes) stream = super(stream) # Get the default value - @default_value = StreamObjectFactory.get(stream) + @default_value = StreamObjectFactory.get(stream).data end def initialize(hash : ::Hash(RawHashObjects, RawHashObjects)) @size = 0 tmp_default = hash.default_value - @default_value = tmp_default.ruby_marshal_dump - #puts @default_value.inspect - #puts @default_value.dump - @data = ::Hash(StreamObject, StreamObject).new + @default_value = tmp_default.ruby_marshal_dump.data + @data = ::Hash(RawHashObjects, RawHashObjects).new @num_keys = Integer.get(hash.keys.size) super(hash) hash.each do |key, value| @@ -39,14 +37,14 @@ module Ruby::Marshal @size += instance_var_name.stream_size instance_var_value = value.ruby_marshal_dump @size += instance_var_value.stream_size - @data[instance_var_name] = instance_var_value + @data[instance_var_name.data] = instance_var_value.data end end def dump output = super() output[0] = TYPE_BYTE - output.concat(@default_value.dump || ::Bytes.new(0)) + output.concat(@default_value.ruby_marshal_dump.dump || ::Bytes.new(0)) end end diff --git a/src/ruby-marshal/stream_objects/instance_object.cr b/src/ruby-marshal/stream_objects/instance_object.cr index 74b7298..a0054cd 100644 --- a/src/ruby-marshal/stream_objects/instance_object.cr +++ b/src/ruby-marshal/stream_objects/instance_object.cr @@ -27,9 +27,9 @@ module Ruby::Marshal def initialize(num_vars : Integer, vars : Hash) super(0x00) - @data = Null.new @num_instance_variables = num_vars @instance_variables = vars + @data = vars.dump @size = @num_instance_variables.stream_size + @instance_variables.stream_size - 1 end diff --git a/src/ruby-marshal/stream_objects/object.cr b/src/ruby-marshal/stream_objects/object.cr index a1aeca2..2481819 100644 --- a/src/ruby-marshal/stream_objects/object.cr +++ b/src/ruby-marshal/stream_objects/object.cr @@ -13,38 +13,42 @@ module Ruby::Marshal # variable names. class Object < StreamObject - getter :data + getter :data, :instance_variables @class_name : Symbol @num_instance_variables : Integer + @data : ::Hash(Hash::RawHashObjects, Hash::RawHashObjects) @instance_variables : Hash + TYPE_BYTE = UInt8.new(0x6f) def initialize(stream : Bytes) super(0x00) @class_name = StreamObjectFactory.get(stream).as(Symbol) - @data = Null.new(stream) stream += @class_name.stream_size @instance_variables = Hash.new(stream) + @data = @instance_variables.data @num_instance_variables = @instance_variables.num_keys @size = @instance_variables.stream_size + @class_name.stream_size - 1 Heap.add(self) end + def initialize(@num_instance_variables : Integer, @instance_variables : Hash, @class_name : Symbol) + super(0x00) + @data = @instance_variables.data + @size = @num_instance_variables.stream_size + @instance_variables.stream_size - 1 + Heap.add(self) + end + + def self.from(obj : ::Object) + Object.new(obj.num_instance_vars, obj.instance_vars, Symbol.new(obj.class.to_s)) + end + def populate_class(klass : ::Object) klass.new(self) end def read_attr(name : ::String, raw = false) - key = @instance_variables.raw_hash.has_key?(name) ? name : "@#{name}" - attr = @instance_variables.raw_hash.has_key?(key) ? @instance_variables[key] : nil - if(raw && !attr.nil?) - if (attr.is_a?(::Hash)) - return attr.raw_hash - else - return attr.data - end - else - return attr - end + key = @data.has_key?(name) ? name : "@#{name}" + @data.has_key?(key) ? @data[key] : nil end def read_raw_attr(name : ::String) @@ -52,9 +56,11 @@ module Ruby::Marshal end def dump - #output = ::Bytes.new(1) - #output[0] = @type_byte - #bytestream.concat(output) + result = ::Bytes.new(1) + result[0] = TYPE_BYTE + result = result.concat(@class_name.dump) + .concat(@num_instance_variables.dump + 2) + .concat(@instance_variables.dump + 1) end end diff --git a/src/ruby-marshal/stream_objects/object_pointer.cr b/src/ruby-marshal/stream_objects/object_pointer.cr index c23320b..f8e1b46 100644 --- a/src/ruby-marshal/stream_objects/object_pointer.cr +++ b/src/ruby-marshal/stream_objects/object_pointer.cr @@ -5,19 +5,13 @@ module Ruby::Marshal class ObjectPointer < StreamObject - alias RubyStreamObjects = StreamObject | ::Bytes | ::Regex | ::Bool | ::Int32 | ::String | ::Nil | ::Array(Ruby::Marshal::Array::RubyStreamArray) | ::Hash(Ruby::Marshal::StreamObject, Ruby::Marshal::StreamObject) | ::Float64 - @data : RubyStreamObjects + @data : Hash::RawHashObjects getter :data def initialize(stream : Bytes) - @data = "" pointer_index = Integer.get(stream) super(pointer_index.stream_size) @heap_index = Int32.new(pointer_index.data) - read(stream) - end - - def read(stream : Bytes) @data = Heap.get_obj(@heap_index).data end diff --git a/src/ruby-marshal/stream_objects/struct.cr b/src/ruby-marshal/stream_objects/struct.cr index fd0f083..d31bc6c 100644 --- a/src/ruby-marshal/stream_objects/struct.cr +++ b/src/ruby-marshal/stream_objects/struct.cr @@ -18,55 +18,31 @@ module Ruby::Marshal # marshaled struct an exception should be raised. class Struct < StreamObject - getter :data + getter :data, :instance_variables @struct_name : Symbol + @data : ::Hash(Hash::RawHashObjects, Hash::RawHashObjects) @num_members : Integer - @members : ::Hash(::String, StreamObject) + @instance_variables : Hash TYPE_BYTE = UInt8.new(0x53) def initialize(stream : Bytes) super(0x00) - @data = Null.new @struct_name = StreamObjectFactory.get(stream).as(Symbol) stream += @struct_name.stream_size - @num_members = Integer.get(stream) - @members = ::Hash(::String, StreamObject).new - stream += @num_members.size - @size = @num_members.size + @struct_name.stream_size - read(stream) + @instance_variables = Hash.new(stream) + @data = @instance_variables.data + @num_members = @instance_variables.num_keys + @size = @instance_variables.size + @struct_name.stream_size - 1 Heap.add(self) end - def read(stream : Bytes) - i = 0 - while(i < @num_members.data) - instance_var_name = StreamObjectFactory.get(stream) - stream += instance_var_name.stream_size - @size += instance_var_name.stream_size - instance_var_value = StreamObjectFactory.get(stream) - stream += instance_var_value.stream_size - @size += instance_var_value.stream_size - @members[instance_var_name.data.as(::String)] = instance_var_value - i += 1 - end - end - def populate_class(klass : ::Object) klass.new(self) end def read_attr(name : ::String, raw = false) - key = @members.has_key?(name) ? name : "@#{name}" - attr = @members.has_key?(key) ? @members[key] : nil - if(raw && !attr.nil?) - if (attr.is_a?(::Hash)) - return attr.raw_hash - else - return attr.data - end - else - return attr - end + key = @data.has_key?(name) ? name : "@#{name}" + @data.has_key?(key) ? @data[key] : nil end def read_raw_attr(name : ::String) @@ -76,9 +52,9 @@ module Ruby::Marshal def initialize(str : ::Struct) @size = 0 super(@size) - @data = Null.new @num_members = str.num_instance_vars - @members = str.instance_vars + @instance_variables = str.instance_vars + @data = @instance_variables.data @struct_name = Symbol.new(str.class.to_s) end @@ -86,8 +62,8 @@ module Ruby::Marshal output = ::Bytes.new(1) output[0] = TYPE_BYTE output = output.concat(@struct_name.dump) - .concat(@num_members.dump) - # .concat(@members.dump) + .concat(@num_members.dump + 2) + .concat(@instance_variables.dump + 1) end end diff --git a/src/ruby-marshal/stream_objects/symbol.cr b/src/ruby-marshal/stream_objects/symbol.cr index 3b94154..ef8a1e0 100644 --- a/src/ruby-marshal/stream_objects/symbol.cr +++ b/src/ruby-marshal/stream_objects/symbol.cr @@ -16,7 +16,7 @@ module Ruby::Marshal Heap.add(self) end - def initialize(sym : ::Symbol) + def initialize(sym : ::Symbol | ::String) @data = sym.to_s @byte_sequence = ByteSequence.new(@data) super(@byte_sequence.stream_size) diff --git a/src/ruby-marshal/stream_objects/user_class.cr b/src/ruby-marshal/stream_objects/user_class.cr index ed4aeb0..bcede63 100644 --- a/src/ruby-marshal/stream_objects/user_class.cr +++ b/src/ruby-marshal/stream_objects/user_class.cr @@ -9,20 +9,16 @@ module Ruby::Marshal class UserClass < StreamObject getter :data, :class_name - @data : StreamObject + @data : Hash::RawHashObjects @class_name : Symbol def initialize(stream : Bytes) - @data = Null.new @class_name = StreamObjectFactory.get(stream).as(Symbol) super(@class_name.stream_size) stream += @class_name.stream_size - read(stream) - end - - def read(stream : Bytes) - @data = StreamObjectFactory.get(stream) - @size += @data.stream_size + obj = StreamObjectFactory.get(stream) + @size += obj.stream_size + @data = obj.data end def dump