Class: Erlectricity::Decoder
- Inherits:
-
Object
- Object
- Erlectricity::Decoder
show all
- Includes:
- External::Types
- Defined in:
- lib/erlectricity/decoder.rb,
ext/decoder.c
Constant Summary
External::Types::ATOM, External::Types::BIN, External::Types::FLOAT, External::Types::FUN, External::Types::INT, External::Types::LARGE_BIGNUM, External::Types::LARGE_TUPLE, External::Types::LIST, External::Types::NEW_FUN, External::Types::NEW_REF, External::Types::NIL, External::Types::PID, External::Types::PORT, External::Types::REF, External::Types::SMALL_BIGNUM, External::Types::SMALL_INT, External::Types::SMALL_TUPLE, External::Types::STRING
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(ins) ⇒ Decoder
Returns a new instance of Decoder.
10
11
12
13
|
# File 'lib/erlectricity/decoder.rb', line 10
def initialize(ins)
@in = ins
@peeked = ""
end
|
Instance Attribute Details
#in ⇒ Object
Returns the value of attribute in.
3
4
5
|
# File 'lib/erlectricity/decoder.rb', line 3
def in
@in
end
|
Class Method Details
.decode(rString) ⇒ Object
381
382
383
|
# File 'ext/decoder.c', line 381
def self.decode(string)
new(StringIO.new(string)).read_any
end
|
Instance Method Details
#fail(str) ⇒ Object
206
207
208
|
# File 'lib/erlectricity/decoder.rb', line 206
def fail(str)
raise DecodeError, str
end
|
#peek(length) ⇒ Object
58
59
60
61
62
63
64
65
66
|
# File 'lib/erlectricity/decoder.rb', line 58
def peek(length)
if length <= @peeked.length
@peeked[0...length]
else
read_bytes = @in.read(length - @peeked.length)
@peeked << read_bytes if read_bytes
@peeked
end
end
|
#peek_1 ⇒ Object
68
69
70
|
# File 'lib/erlectricity/decoder.rb', line 68
def peek_1
peek(1).unpack("C").first
end
|
#peek_2 ⇒ Object
72
73
74
|
# File 'lib/erlectricity/decoder.rb', line 72
def peek_2
peek(2).unpack("n").first
end
|
#read(length) ⇒ Object
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
# File 'lib/erlectricity/decoder.rb', line 41
def read(length)
if length < @peeked.length
result = @peeked[0...length]
@peeked = @peeked[length..-1]
length = 0
else
result = @peeked
@peeked = ''
length -= result.length
end
if length > 0
result << @in.read(length)
end
result
end
|
#read_1 ⇒ Object
76
77
78
|
# File 'lib/erlectricity/decoder.rb', line 76
def read_1
read(1).unpack("C").first
end
|
#read_2 ⇒ Object
80
81
82
|
# File 'lib/erlectricity/decoder.rb', line 80
def read_2
read(2).unpack("n").first
end
|
#read_4 ⇒ Object
84
85
86
|
# File 'lib/erlectricity/decoder.rb', line 84
def read_4
read(4).unpack("N").first
end
|
#read_any ⇒ Object
15
16
17
18
|
# File 'lib/erlectricity/decoder.rb', line 15
def read_any
fail("Bad Magic") unless read_1 == Erlectricity::External::VERSION
read_any_raw
end
|
#read_any_raw ⇒ Object
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
# File 'lib/erlectricity/decoder.rb', line 20
def read_any_raw
case peek_1
when ATOM then read_atom
when SMALL_INT then read_small_int
when INT then read_int
when SMALL_BIGNUM then read_small_bignum
when LARGE_BIGNUM then read_large_bignum
when FLOAT then read_float
when NEW_REF then read_new_reference
when PID then read_pid
when SMALL_TUPLE then read_small_tuple
when LARGE_TUPLE then read_large_tuple
when NIL then read_nil
when STRING then read_erl_string
when LIST then read_list
when BIN then read_bin
else
fail("Unknown term tag: #{peek_1}")
end
end
|
#read_atom ⇒ Object
92
93
94
95
96
97
98
99
100
101
102
103
104
|
# File 'lib/erlectricity/decoder.rb', line 92
def read_atom
fail("Invalid Type, not an atom") unless read_1 == ATOM
length = read_2
a = read_string(length)
case a
when "true"
true
when "false"
false
else
a.to_sym
end
end
|
#read_bin ⇒ Object
200
201
202
203
204
|
# File 'lib/erlectricity/decoder.rb', line 200
def read_bin
fail("Invalid Type, not an erlang binary") unless read_1 == BIN
length = read_4
read_string(length)
end
|
#read_erl_string ⇒ Object
186
187
188
189
190
|
# File 'lib/erlectricity/decoder.rb', line 186
def read_erl_string
fail("Invalid Type, not an erlang string") unless read_1 == STRING
length = read_2
read_string(length).unpack('C' * length)
end
|
#read_float ⇒ Object
145
146
147
148
149
|
# File 'lib/erlectricity/decoder.rb', line 145
def read_float
fail("Invalid Type, not a float") unless read_1 == FLOAT
string_value = read_string(31)
result = string_value.to_f
end
|
#read_int ⇒ Object
111
112
113
114
115
116
117
|
# File 'lib/erlectricity/decoder.rb', line 111
def read_int
fail("Invalid Type, not an int") unless read_1 == INT
value = read_4
negative = (value >> 31)[0] == 1
value = (value - (1 << 32)) if negative
value = Fixnum.induced_from(value)
end
|
#read_large_bignum ⇒ Object
132
133
134
135
136
137
138
139
140
141
142
143
|
# File 'lib/erlectricity/decoder.rb', line 132
def read_large_bignum
fail("Invalid Type, not a large bignum") unless read_1 == LARGE_BIGNUM
size = read_4
sign = read_1
bytes = read_string(size).unpack("C" * size)
added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
byte, index = *byte_index
value = (byte * (256 ** index))
sign != 0 ? (result - value) : (result + value)
end
Bignum.induced_from(added)
end
|
#read_large_tuple ⇒ Object
175
176
177
178
179
|
# File 'lib/erlectricity/decoder.rb', line 175
def read_large_tuple
fail("Invalid Type, not a small tuple") unless read_1 == LARGE_TUPLE
arity = read_4
(0...arity).map { |i| read_any_raw }
end
|
#read_list ⇒ Object
192
193
194
195
196
197
198
|
# File 'lib/erlectricity/decoder.rb', line 192
def read_list
fail("Invalid Type, not an erlang list") unless read_1 == LIST
length = read_4
list = (0...length).map { |i| read_any_raw }
read_1
list
end
|
#read_new_reference ⇒ Object
151
152
153
154
155
156
157
158
|
# File 'lib/erlectricity/decoder.rb', line 151
def read_new_reference
fail("Invalid Type, not a new-style reference") unless read_1 == NEW_REF
size = read_2
node = read_atom
creation = read_1
id = (0...size).map { |i| read_4 }
NewReference.new(node, creation, id)
end
|
#read_nil ⇒ Object
181
182
183
184
|
# File 'lib/erlectricity/decoder.rb', line 181
def read_nil
fail("Invalid Type, not a nil list") unless read_1 == NIL
[]
end
|
#read_pid ⇒ Object
160
161
162
163
164
165
166
167
|
# File 'lib/erlectricity/decoder.rb', line 160
def read_pid
fail("Invalid Type, not a pid") unless read_1 == PID
node = read_atom
id = read_4
serial = read_4
creation = read_1
Pid.new(node, id, serial, creation)
end
|
#read_small_bignum ⇒ Object
119
120
121
122
123
124
125
126
127
128
129
130
|
# File 'lib/erlectricity/decoder.rb', line 119
def read_small_bignum
fail("Invalid Type, not a small bignum") unless read_1 == SMALL_BIGNUM
size = read_1
sign = read_1
bytes = read_string(size).unpack("C" * size)
added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
byte, index = *byte_index
value = (byte * (256 ** index))
sign != 0 ? (result - value) : (result + value)
end
Bignum.induced_from(added)
end
|
#read_small_int ⇒ Object
106
107
108
109
|
# File 'lib/erlectricity/decoder.rb', line 106
def read_small_int
fail("Invalid Type, not a small int") unless read_1 == SMALL_INT
read_1
end
|
#read_small_tuple ⇒ Object
169
170
171
172
173
|
# File 'lib/erlectricity/decoder.rb', line 169
def read_small_tuple
fail("Invalid Type, not a small tuple") unless read_1 == SMALL_TUPLE
arity = read_1
(0...arity).map { |i| read_any_raw }
end
|
#read_string(length) ⇒ Object
88
89
90
|
# File 'lib/erlectricity/decoder.rb', line 88
def read_string(length)
read(length)
end
|