erlang-terms 1.1.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.editorconfig +20 -0
  4. data/.gitignore +10 -18
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +15 -3
  8. data/.yardopts +6 -0
  9. data/CHANGELOG.md +9 -0
  10. data/Gemfile +21 -1
  11. data/LICENSE.txt +1 -1
  12. data/README.md +95 -17
  13. data/Rakefile +8 -3
  14. data/erlang-terms.gemspec +14 -11
  15. data/lib/erlang-terms.rb +1 -0
  16. data/lib/erlang/associable.rb +98 -0
  17. data/lib/erlang/atom.rb +257 -0
  18. data/lib/erlang/binary.rb +425 -0
  19. data/lib/erlang/bitstring.rb +464 -0
  20. data/lib/erlang/cons.rb +122 -0
  21. data/lib/erlang/enumerable.rb +160 -0
  22. data/lib/erlang/error.rb +4 -0
  23. data/lib/erlang/export.rb +110 -12
  24. data/lib/erlang/float.rb +201 -0
  25. data/lib/erlang/function.rb +259 -0
  26. data/lib/erlang/immutable.rb +101 -0
  27. data/lib/erlang/list.rb +1685 -24
  28. data/lib/erlang/map.rb +935 -21
  29. data/lib/erlang/nil.rb +73 -10
  30. data/lib/erlang/pid.rb +120 -18
  31. data/lib/erlang/port.rb +123 -0
  32. data/lib/erlang/reference.rb +161 -0
  33. data/lib/erlang/string.rb +175 -3
  34. data/lib/erlang/term.rb +24 -0
  35. data/lib/erlang/terms.rb +324 -8
  36. data/lib/erlang/terms/version.rb +1 -1
  37. data/lib/erlang/trie.rb +364 -0
  38. data/lib/erlang/tuple.rb +1582 -14
  39. data/lib/erlang/undefined.rb +32 -0
  40. metadata +49 -71
  41. data/spec/erlang/export_spec.rb +0 -17
  42. data/spec/erlang/list_spec.rb +0 -39
  43. data/spec/erlang/map_spec.rb +0 -24
  44. data/spec/erlang/nil_spec.rb +0 -18
  45. data/spec/erlang/pid_spec.rb +0 -21
  46. data/spec/erlang/string_spec.rb +0 -11
  47. data/spec/erlang/terms_spec.rb +0 -7
  48. data/spec/erlang/tuple_spec.rb +0 -20
  49. data/spec/spec_helper.rb +0 -7
@@ -0,0 +1,257 @@
1
+ module Erlang
2
+ # An `Atom` is a literal constant with a name.
3
+ #
4
+ # Symbols, Booleans (`true` and `false`), and `nil` are considered `Atom`s in Ruby.
5
+ #
6
+ # ### Creating Atoms
7
+ #
8
+ # Erlang::Atom["test"]
9
+ # # => :test
10
+ # Erlang::Atom[:Ω]
11
+ # # => :Ω
12
+ # Erlang::Atom[:Ω, utf8: true]
13
+ # # => Erlang::Atom["Ω", utf8: true]
14
+ # Erlang::Atom[true]
15
+ # # => true
16
+ # Erlang::Atom[false]
17
+ # # => false
18
+ # Erlang::Atom[nil]
19
+ # # => nil
20
+ #
21
+ #
22
+ class Atom
23
+ include Erlang::Term
24
+ include Erlang::Immutable
25
+
26
+ # Return the data for this `Atom`
27
+ # @return [::String]
28
+ attr_reader :data
29
+
30
+ # Return the utf8 flag for this `Atom`
31
+ # @return [::Boolean]
32
+ attr_reader :utf8
33
+
34
+ class << self
35
+ # Create a new `Atom` populated with the given `data` and `utf8` flag.
36
+ # @param data [::String, Symbol, ::Enumerable, Integer] The content of the `Atom`
37
+ # @param utf8 [Boolean] Whether the `Atom` should be considered UTF-8 or not
38
+ # @return [Atom]
39
+ # @raise [ArgumentError] if `data` cannot be coerced to be a `::String`
40
+ def [](*data, utf8: false)
41
+ return EmptyAtom if data.empty?
42
+ if data.size == 1
43
+ return data[0] if data[0].is_a?(Erlang::Atom)
44
+ return FalseAtom if data[0] == false
45
+ return NilAtom if data[0] == nil
46
+ return TrueAtom if data[0] == true
47
+ if data[0].is_a?(::String)
48
+ data = data[0]
49
+ elsif data[0].is_a?(::Symbol)
50
+ data = data[0].to_s
51
+ end
52
+ end
53
+ unless data.is_a?(::String)
54
+ data = Erlang.iolist_to_binary(data).data
55
+ end
56
+ return FalseAtom if data == "false"
57
+ return NilAtom if data == "nil"
58
+ return TrueAtom if data == "true"
59
+ return new(data, utf8)
60
+ end
61
+
62
+ # Return an empty `Atom`. If used on a subclass, returns an empty instance
63
+ # of that class.
64
+ #
65
+ # @return [Atom]
66
+ def empty
67
+ return @empty ||= self.new
68
+ end
69
+
70
+ # Return a false `Atom`.
71
+ #
72
+ # @return [Atom]
73
+ def false
74
+ return @false ||= self.new("false")
75
+ end
76
+
77
+ # Return a nil `Atom`.
78
+ #
79
+ # @return [Atom]
80
+ def nil
81
+ return @nil ||= self.new("nil")
82
+ end
83
+
84
+ # Return a true `Atom`.
85
+ #
86
+ # @return [Atom]
87
+ def true
88
+ return @true ||= self.new("true")
89
+ end
90
+
91
+ # Compares `a` and `b` and returns whether they are less than,
92
+ # equal to, or greater than each other.
93
+ #
94
+ # @param a [Atom] The left argument
95
+ # @param b [Atom] The right argument
96
+ # @return [-1, 0, 1]
97
+ # @raise [ArgumentError] if `a` or `b` is not an `Atom`
98
+ def compare(a, b)
99
+ raise ArgumentError, "'a' must be of Erlang::Atom type" unless a.kind_of?(Erlang::Atom)
100
+ raise ArgumentError, "'b' must be of Erlang::Atom type" unless b.kind_of?(Erlang::Atom)
101
+ return a.data <=> b.data
102
+ end
103
+ end
104
+
105
+ # @private
106
+ def initialize(data = ::String.new.freeze, utf8 = false)
107
+ raise ArgumentError, 'data must be a String' if not data.is_a?(::String)
108
+ @valid_utf8, data = Erlang::Terms.utf8_encoding(data)
109
+ @printable = Erlang::Terms.printable?(data)
110
+ data = Erlang::Terms.binary_encoding(data) if not @printable
111
+ @data = data.freeze
112
+ @utf8 = !!utf8
113
+ if @data == "false"
114
+ @internal = false
115
+ elsif @data == "nil"
116
+ @internal = nil
117
+ elsif @data == "true"
118
+ @internal = true
119
+ else
120
+ @internal = @data.intern
121
+ end
122
+ valid_internal = false
123
+ if @utf8 == false and @valid_utf8 and @printable
124
+ begin
125
+ if @internal == eval(@internal.inspect)
126
+ valid_internal = true
127
+ end
128
+ rescue SyntaxError
129
+ valid_internal = false
130
+ end
131
+ end
132
+ @valid_internal = valid_internal
133
+ end
134
+
135
+ # @private
136
+ def hash
137
+ return @internal.hash
138
+ end
139
+
140
+ # Return true if `other` has the same type and contents as this `Atom`.
141
+ #
142
+ # @param other [Object] The object to compare with
143
+ # @return [Boolean]
144
+ def eql?(other)
145
+ return true if other.equal?(self)
146
+ if instance_of?(other.class)
147
+ return !!(@utf8 == other.utf8 && self.hash == other.hash)
148
+ else
149
+ return !!(Erlang.compare(other, self) == 0)
150
+ end
151
+ end
152
+ alias :== :eql?
153
+
154
+ # Returns the length of this `Atom`.
155
+ #
156
+ # @return [Integer]
157
+ def length
158
+ return @data.bytesize
159
+ end
160
+ alias :size :length
161
+
162
+ # Return the contents of this `Atom` as a Erlang-readable `::String`.
163
+ #
164
+ # @example
165
+ # Erlang::Atom[:test].erlang_inspect
166
+ # # => "'test'"
167
+ # # Pass `utf8: true` for a UTF-8 version of the Atom
168
+ # Erlang::Atom[:Ω].erlang_inspect
169
+ # # => "'\\xCE\\xA9'"
170
+ # Erlang::Atom[:Ω, utf8: true].erlang_inspect
171
+ # # => "'Ω'"
172
+ #
173
+ # @return [::String]
174
+ def erlang_inspect(raw = false)
175
+ if @utf8
176
+ result = '\''
177
+ result << (data.inspect[1..-2].gsub('\''){"\\'"})
178
+ result << '\''
179
+ return result
180
+ else
181
+ result = '\''
182
+ data = @valid_utf8 ? Erlang::Terms.binary_encoding(@data) : @data
183
+ result << (data.inspect[1..-2].gsub('\''){"\\'"})
184
+ result << '\''
185
+ return result
186
+ end
187
+ end
188
+
189
+ # @return [::String] the nicely formatted version of the `Atom`
190
+ def inspect
191
+ if @valid_internal
192
+ return @internal.inspect
193
+ elsif @utf8 == true
194
+ return "Erlang::Atom[#{@data.inspect}, utf8: true]"
195
+ else
196
+ return "Erlang::Atom[#{@data.inspect}]"
197
+ end
198
+ end
199
+
200
+ # @return [self] the `Atom` version of the `Atom`
201
+ def to_atom
202
+ return self
203
+ end
204
+
205
+ # @return [Binary] the `Binary` version of the `Atom`
206
+ def to_binary
207
+ return Erlang::Binary[@data]
208
+ end
209
+
210
+ # @return [List] the `List` version of the `Atom`
211
+ def to_list
212
+ return Erlang::List.from_enum(@data.bytes)
213
+ end
214
+
215
+ # @return [self] the `String` version of the `Atom`
216
+ def to_string
217
+ return Erlang::String[@data]
218
+ end
219
+
220
+ # @return [::String] the string version of the `Atom`
221
+ def to_s
222
+ return @data
223
+ end
224
+ alias :to_str :to_s
225
+
226
+ # @return [::Array]
227
+ # @private
228
+ def marshal_dump
229
+ return [@internal, @utf8]
230
+ end
231
+
232
+ # @private
233
+ def marshal_load(args)
234
+ internal, utf8 = args
235
+ atom = self.class[internal, utf8: utf8]
236
+ initialize(atom.data, atom.utf8)
237
+ __send__(:immutable!)
238
+ return self
239
+ end
240
+ end
241
+
242
+ # The canonical empty `Atom`. Returned by `Atom[]` when
243
+ # invoked with no arguments; also returned by `Atom.empty`. Prefer using this
244
+ # one rather than creating many empty atoms using `Atom.new`.
245
+ #
246
+ # @private
247
+ EmptyAtom = Erlang::Atom.empty
248
+
249
+ # @private
250
+ FalseAtom = Erlang::Atom.false
251
+
252
+ # @private
253
+ NilAtom = Erlang::Atom.nil
254
+
255
+ # @private
256
+ TrueAtom = Erlang::Atom.true
257
+ end
@@ -0,0 +1,425 @@
1
+ module Erlang
2
+ # A `Binary` is a series of bytes.
3
+ #
4
+ # ### Creating Binaries
5
+ #
6
+ # Erlang::Binary["test"]
7
+ # # => Erlang::Binary["test"]
8
+ #
9
+ class Binary
10
+ include Erlang::Term
11
+ include Erlang::Immutable
12
+
13
+ # Return the data for this `Erlang::Binary`
14
+ # @return [::String]
15
+ attr_reader :data
16
+
17
+ # Return the bits for this `Erlang::Binary`
18
+ # @return [::Integer]
19
+ # @!parse attr_reader :bits
20
+ def bits
21
+ return 8
22
+ end
23
+
24
+ class << self
25
+ # Create a new `Binary` populated with the given `data`.
26
+ # @param data [::String, Symbol, ::Enumerable, Integer] The content of the `Binary`
27
+ # @return [Binary]
28
+ # @raise [ArgumentError] if `data` cannot be coerced to be a `::String`
29
+ def [](*data)
30
+ return Erlang.iolist_to_binary(data)
31
+ end
32
+
33
+ # Return an empty `Binary`. If used on a subclass, returns an empty instance
34
+ # of that class.
35
+ #
36
+ # @return [Binary]
37
+ def empty
38
+ return @empty ||= self.new
39
+ end
40
+
41
+ # Compares `a` and `b` and returns whether they are less than,
42
+ # equal to, or greater than each other.
43
+ #
44
+ # @param a [Binary] The left argument
45
+ # @param b [Binary] The right argument
46
+ # @return [-1, 0, 1]
47
+ # @raise [ArgumentError] if `a` or `b` is not a `Binary`
48
+ def compare(a, b)
49
+ return Erlang::Bitstring.compare(a, b)
50
+ end
51
+
52
+ # Concatenates list of `Binary` or `Bitstring` items into a single `Binary` or `Bitstring`.
53
+ #
54
+ # @example
55
+ # Erlang::Binary.concat(Erlang::Bitstring[1, bits: 2], Erlang::Binary[255])
56
+ # # => Erlang::Bitstring[127, 3, bits: 2]
57
+ #
58
+ # @param iodata [Binary, Bitstring] The list of bitstrings
59
+ # @return [Binary, Bitstring]
60
+ def concat(*iodata)
61
+ return iodata.reduce(Erlang::EmptyBinary) { |acc, item| acc.concat(item) }
62
+ end
63
+
64
+ # Returns an unsigned `Integer` which is the `endianness` based version of the `subject`.
65
+ #
66
+ # @param subject [::String, Binary] The string to decode
67
+ # @param endianness [:big, :little] The endianness of the subject
68
+ # @return [Integer]
69
+ # @raise [ArgumentError] if `subject` is not a string or `endianness` is not `:big` or `:little`
70
+ def decode_unsigned(subject, endianness = :big)
71
+ subject = subject.to_s if subject.kind_of?(Erlang::Binary)
72
+ raise ArgumentError, 'subject must be a String' if not subject.is_a?(::String)
73
+ case endianness
74
+ when :big, :little
75
+ bits = 0
76
+ bytes = subject.unpack(Erlang::Terms::UINT8_SPLAT)
77
+ bytes = bytes.reverse if endianness == :big
78
+ return bytes.inject(0) do |unsigned, n|
79
+ unsigned = unsigned + (n << bits)
80
+ bits += 8
81
+ next unsigned
82
+ end
83
+ else
84
+ raise ArgumentError, 'endianness must be :big or :little'
85
+ end
86
+ end
87
+
88
+ # Returns a `::String` which is the `endianness` based version of the unsigned `subject`.
89
+ #
90
+ # @param subject [Integer] The unsigned integer to encode
91
+ # @param endianness [:big, :little] The endianness of the subject
92
+ # @return [::String]
93
+ # @raise [ArgumentError] if `subject` is not an integer or `endianness` is not `:big` or `:little`
94
+ def encode_unsigned(unsigned, endianness = :big)
95
+ raise ArgumentError, 'unsigned must be a non-negative Integer' if not unsigned.is_a?(::Integer) or unsigned < 0
96
+ case endianness
97
+ when :big, :little
98
+ n = unsigned
99
+ bytes = []
100
+ loop do
101
+ bytes << (n & 255)
102
+ break if (n >>= 8) == 0
103
+ end
104
+ bytes = bytes.reverse if endianness == :big
105
+ return bytes.pack(Erlang::Terms::UINT8_SPLAT)
106
+ else
107
+ raise ArgumentError, 'endianness must be :big or :little'
108
+ end
109
+ end
110
+ end
111
+
112
+ # @private
113
+ def initialize(data = nil)
114
+ data = ::String.new if data.nil?
115
+ data = data.data if data.is_a?(Erlang::Binary)
116
+ raise ArgumentError, 'data must be a String' if not data.is_a?(::String)
117
+ _, data = Erlang::Terms.utf8_encoding(data)
118
+ @printable = Erlang::Terms.printable?(data)
119
+ data = Erlang::Terms.binary_encoding(data) if not @printable
120
+ @data = data.freeze
121
+ end
122
+
123
+ # @private
124
+ def hash
125
+ return @data.hash
126
+ end
127
+
128
+ # Returns the byte at the provided `position`.
129
+ #
130
+ # @param position [Integer] The position of the byte
131
+ # @return [Integer]
132
+ # @raise [ArgumentError] if `position` is not an `Integer`
133
+ def at(position)
134
+ raise ArgumentError, 'position must be an Integer' if not position.is_a?(::Integer)
135
+ return @data.getbyte(position)
136
+ end
137
+ alias :[] :at
138
+
139
+ # @return [Integer] the number of bits in this `Binary`
140
+ def bitsize
141
+ return (bytesize * bits)
142
+ end
143
+
144
+ # Return specific objects from the `Binary`. All overloads return `nil` if
145
+ # the starting index is out of range.
146
+ #
147
+ # @overload bitslice(index)
148
+ # Returns a single bit at the given `index`. If `index` is negative,
149
+ # count backwards from the end.
150
+ #
151
+ # @param index [Integer] The index to retrieve. May be negative.
152
+ # @return [Integer, nil]
153
+ # @example
154
+ # b = Erlang::Binary[1]
155
+ # b.bitslice(0) # => 0
156
+ # b.bitslice(7) # => 1
157
+ # b.bitslice(-1) # => 1
158
+ # b.bitslice(8) # => nil
159
+ #
160
+ # @overload bitslice(index, length)
161
+ # Return a bitstring starting at `index` and continuing for `length`
162
+ # bits or until the end of the `Binary`, whichever occurs first.
163
+ #
164
+ # @param start [Integer] The index to start retrieving bits from. May be
165
+ # negative.
166
+ # @param length [Integer] The number of bits to retrieve.
167
+ # @return [Bitstring, Binary]
168
+ # @example
169
+ # b = Erlang::Binary[117]
170
+ # b.bitslice(0, 3) # => Erlang::Bitstring[3, bits: 3]
171
+ # b.bitslice(3, 5) # => Erlang::Bitstring[21, bits: 5]
172
+ # b.bitslice(9, 1) # => nil
173
+ #
174
+ # @overload bitslice(index..end)
175
+ # Return a bitstring starting at `index` and continuing to index
176
+ # `end` or the end of the `Binary`, whichever occurs first.
177
+ #
178
+ # @param range [Range] The range of bits to retrieve.
179
+ # @return [Bitstring, Binary]
180
+ # @example
181
+ # b = Erlang::Binary[117]
182
+ # b.bitslice(0...3) # => Erlang::Bitstring[3, bits: 3]
183
+ # b.bitslice(3...8) # => Erlang::Bitstring[21, bits: 5]
184
+ # b.bitslice(9..-1) # => nil
185
+ #
186
+ # @see Erlang::Bitstring#bitslice
187
+ def bitslice(*args)
188
+ return Erlang::Bitstring.new(@data, 8).bitslice(*args)
189
+ end
190
+
191
+ # @return [Integer] the number of bytes in this `Binary`
192
+ def bytesize
193
+ return @data.bytesize
194
+ end
195
+ alias :size :bytesize
196
+
197
+ # Concatenates list of `Binary` or `Bitstring` items into a single `Binary` or `Bitstring`.
198
+ #
199
+ # @example
200
+ # Erlang::Binary["a"].concat(Erlang::Bitstring[3, bits: 3]).concat(Erlang::Bitstring[2, bits: 5])
201
+ # # => "ab"
202
+ #
203
+ # @param iodata [Binary, Bitstring] The list of bitstrings
204
+ # @return [Binary, Bitstring]
205
+ def concat(*other)
206
+ if other.size == 1 and (other[0].kind_of?(Erlang::Binary) or other[0].kind_of?(Erlang::Bitstring))
207
+ other = other[0]
208
+ else
209
+ other = Erlang::Binary[*other]
210
+ end
211
+ return other if empty?
212
+ return self if other.empty?
213
+ if other.kind_of?(Erlang::Bitstring) and other.bits != 8
214
+ return Erlang::Bitstring[@data, other.data, bits: other.bits]
215
+ else
216
+ return Erlang::Binary[@data, other.data]
217
+ end
218
+ end
219
+ alias :+ :concat
220
+
221
+ # Returns a new `Binary` containing `n` copies of itself. `n` must be greater than or equal to 0.
222
+ # @param n [Integer] The number of copies
223
+ # @return [Binary]
224
+ # @raise [ArgumentError] if `n` is less than 0
225
+ def copy(n = 1)
226
+ raise ArgumentError, 'n must be a non-negative Integer' if not n.is_a?(::Integer) or n < 0
227
+ return self if n == 1
228
+ return Erlang::Binary[(@data * n)]
229
+ end
230
+
231
+ # Returns an unsigned `Integer` which is the `endianness` based version of this `Binary`.
232
+ # @param endianness [:big, :little] The endianness of this `Binary`
233
+ # @return [Integer]
234
+ # @see Erlang::Binary.decode_unsigned
235
+ def decode_unsigned(endianness = :big)
236
+ return Erlang::Binary.decode_unsigned(@data, endianness)
237
+ end
238
+
239
+ # Call the given block once for each bit in the `Binary`, passing each
240
+ # bit from first to last successively to the block. If no block is given,
241
+ # returns an `Enumerator`.
242
+ #
243
+ # @return [self]
244
+ # @yield [Integer]
245
+ def each_bit
246
+ return enum_for(:each_bit) unless block_given?
247
+ index = 0
248
+ bitsize = self.bitsize
249
+ @data.each_byte do |byte|
250
+ loop do
251
+ break if index == bitsize
252
+ bit = (byte >> (7 - (index & 7))) & 1
253
+ yield bit
254
+ index += 1
255
+ break if (index & 7) == 0
256
+ end
257
+ end
258
+ return self
259
+ end
260
+
261
+ # Split the bits in this `Binary` in groups of `number` bits, and yield
262
+ # each group to the block (as a `List`). If no block is given, returns
263
+ # an `Enumerator`.
264
+ #
265
+ # @example
266
+ # b = Erlang::Binary[117]
267
+ # b.each_bitslice(4).to_a # => [Erlang::Bitstring[7, bits: 4], Erlang::Bitstring[5, bits: 4]]
268
+ #
269
+ # @return [self, Enumerator]
270
+ # @yield [Binary, Bitstring] Once for each bitstring.
271
+ # @see Erlang::Bitstring#each_bitslice
272
+ def each_bitslice(number, &block)
273
+ return enum_for(:each_bitslice, number) unless block_given?
274
+ bitstring = Erlang::Bitstring.new(@data, 8)
275
+ bitstring.each_bitslice(number, &block)
276
+ return self
277
+ end
278
+
279
+ # Call the given block once for each byte in the `Binary`, passing each
280
+ # byte from first to last successively to the block. If no block is given,
281
+ # returns an `Enumerator`.
282
+ #
283
+ # @return [self]
284
+ # @yield [Integer]
285
+ def each_byte(&block)
286
+ return enum_for(:each_byte) unless block_given?
287
+ @data.each_byte(&block)
288
+ return self
289
+ end
290
+
291
+ # Returns true if this `Binary` is empty.
292
+ #
293
+ # @return [Boolean]
294
+ def empty?
295
+ return @data.empty?
296
+ end
297
+
298
+ # Return true if `other` has the same type and contents as this `Binary`.
299
+ #
300
+ # @param other [Object] The object to compare with
301
+ # @return [Boolean]
302
+ def eql?(other)
303
+ return true if other.equal?(self)
304
+ if instance_of?(other.class)
305
+ return @data.eql?(other.data)
306
+ elsif other.kind_of?(Erlang::Bitstring)
307
+ return !!(Erlang::Bitstring.compare(other, self) == 0)
308
+ else
309
+ return !!(Erlang.compare(other, self) == 0)
310
+ end
311
+ end
312
+ alias :== :eql?
313
+
314
+ # Returns the first byte of this `Binary`.
315
+ # @return [Integer]
316
+ # @raise [NotImplementedError] if this `Binary` is empty
317
+ def first
318
+ raise NotImplementedError if empty?
319
+ return at(0)
320
+ end
321
+
322
+ # Returns the last byte of this `Binary`.
323
+ # @return [Integer]
324
+ # @raise [NotImplementedError] if this `Binary` is empty
325
+ def last
326
+ raise NotImplementedError if empty?
327
+ return at(-1)
328
+ end
329
+
330
+ # Returns the section of this `Binary` starting at `position` of `length`.
331
+ #
332
+ # @param position [Integer] The starting position
333
+ # @param length [Integer] The non-negative length
334
+ # @return [Binary]
335
+ # @raise [ArgumentError] if `position` is not an `Integer` or `length` is not a non-negative `Integer`
336
+ def part(position, length)
337
+ raise ArgumentError, 'position must be an Integer' if not position.is_a?(::Integer)
338
+ raise ArgumentError, 'length must be a non-negative Integer' if not length.is_a?(::Integer) or length < 0
339
+ return Erlang::Binary[@data.byteslice(position, length)]
340
+ end
341
+
342
+ # Return the contents of this `Binary` as a Erlang-readable `::String`.
343
+ #
344
+ # @example
345
+ # Erlang::Binary["test"].erlang_inspect
346
+ # # => "<<\"test\"/utf8>>"
347
+ # # Pass `raw` as `true` for the decimal version
348
+ # Erlang::Binary["test"].erlang_inspect(true)
349
+ # # => "<<116,101,115,116>>"
350
+ #
351
+ # @return [::String]
352
+ def erlang_inspect(raw = false)
353
+ result = '<<'
354
+ if raw == false and @printable
355
+ result << @data.inspect
356
+ result << '/utf8'
357
+ else
358
+ result << @data.bytes.join(',')
359
+ end
360
+ result << '>>'
361
+ return result
362
+ end
363
+
364
+ # @return [::String] the nicely formatted version of the `Binary`
365
+ def inspect
366
+ return @data.inspect
367
+ end
368
+
369
+ # @return [Atom] the `Atom` version of the `Binary`
370
+ def to_atom
371
+ return Erlang::Atom[@data]
372
+ end
373
+
374
+ # @return [self] the `Binary` version of the `Binary`
375
+ def to_binary
376
+ return self
377
+ end
378
+
379
+ # @param bits [Integer] The number of bits to keep for the last byte
380
+ # @return [Bitstring, self] the `Bitstring` version of the `Binary`
381
+ def to_bitstring(bits = 8)
382
+ if bits == 8
383
+ return self
384
+ else
385
+ return Erlang::Bitstring[@data, bits: bits]
386
+ end
387
+ end
388
+
389
+ # @return [List] the `List` version of the `Binary`
390
+ def to_list
391
+ return Erlang::List.from_enum(@data.bytes)
392
+ end
393
+
394
+ # @return [String] the `String` version of the `Binary`
395
+ def to_string
396
+ return Erlang::String[@data]
397
+ end
398
+
399
+ # @return [::String] the string version of the `Binary`
400
+ def to_s
401
+ return @data
402
+ end
403
+ alias :to_str :to_s
404
+
405
+ # @return [::String]
406
+ # @private
407
+ def marshal_dump
408
+ return @data
409
+ end
410
+
411
+ # @private
412
+ def marshal_load(data)
413
+ initialize(data)
414
+ __send__(:immutable!)
415
+ return self
416
+ end
417
+ end
418
+
419
+ # The canonical empty `Binary`. Returned by `Binary[]` when
420
+ # invoked with no arguments; also returned by `Binary.empty`. Prefer using this
421
+ # one rather than creating many empty binaries using `Binary.new`.
422
+ #
423
+ # @private
424
+ EmptyBinary = Erlang::Binary.empty
425
+ end