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,122 @@
1
+ module Erlang
2
+ # The basic building block for constructing lists
3
+ #
4
+ # A Cons, also known as a "cons cell", has a "head" and a "tail", where
5
+ # the head is an element in the list, and the tail is a reference to the
6
+ # rest of the list. This way a singly linked list can be constructed, with
7
+ # each `Erlang::Cons` holding a single element and a pointer to the next
8
+ # `Erlang::Cons`.
9
+ #
10
+ # The last `Erlang::Cons` instance in the chain has the {Erlang::Nil} as its tail.
11
+ #
12
+ # Licensing
13
+ # =========
14
+ #
15
+ # Portions taken and modified from https://github.com/hamstergem/hamster
16
+ #
17
+ # Copyright (c) 2009-2014 Simon Harris
18
+ #
19
+ # Permission is hereby granted, free of charge, to any person obtaining
20
+ # a copy of this software and associated documentation files (the
21
+ # "Software"), to deal in the Software without restriction, including
22
+ # without limitation the rights to use, copy, modify, merge, publish,
23
+ # distribute, sublicense, and/or sell copies of the Software, and to
24
+ # permit persons to whom the Software is furnished to do so, subject to
25
+ # the following conditions:
26
+ #
27
+ # The above copyright notice and this permission notice shall be
28
+ # included in all copies or substantial portions of the Software.
29
+ #
30
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
34
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
35
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37
+ #
38
+ # @private
39
+ class Cons
40
+ include Erlang::Term
41
+ include Erlang::List
42
+ include Erlang::Immutable
43
+
44
+ attr_reader :head
45
+
46
+ attr_reader :tail
47
+
48
+ class << self
49
+ def inspect
50
+ return Erlang::List.inspect
51
+ end
52
+
53
+ def pretty_inspect
54
+ return Erlang::List.pretty_inspect
55
+ end
56
+
57
+ def pretty_print(q)
58
+ return Erlang::List.pretty_print(q)
59
+ end
60
+ end
61
+
62
+ def initialize(head, tail = Erlang::Nil)
63
+ @head = Erlang.from(head)
64
+ @tail = Erlang.from(tail)
65
+ @improper = @tail.kind_of?(Erlang::List) ? @tail.improper? : true
66
+ end
67
+
68
+ def empty?
69
+ return false
70
+ end
71
+
72
+ def improper?
73
+ return !!@improper
74
+ end
75
+
76
+ # Return the number of items in this `Erlang::List`.
77
+ # @return [Integer]
78
+ def size
79
+ raise Erlang::ImproperListError if improper?
80
+ return 0 if empty?
81
+ size = 0
82
+ list = self
83
+ until list.empty?
84
+ list = list.tail
85
+ size += 1
86
+ end
87
+ return size
88
+ end
89
+ memoize :size
90
+ alias :length :size
91
+
92
+ # @return [::Array]
93
+ # @private
94
+ def marshal_dump
95
+ if improper?
96
+ return [to_proper_list.to_a, last(true)]
97
+ else
98
+ return [to_a, Erlang::Nil]
99
+ end
100
+ end
101
+
102
+ # @private
103
+ def marshal_load(args)
104
+ h, t = args
105
+ if h.size == 0
106
+ return t
107
+ elsif Erlang::Nil.eql?(t)
108
+ head = h[0]
109
+ tail = Erlang::List.from_enum(h[1..-1])
110
+ initialize(head, tail)
111
+ __send__(:immutable!)
112
+ return self
113
+ else
114
+ head = h[0]
115
+ tail = Erlang::List.from_enum(h[1..-1]) + t
116
+ initialize(head, tail)
117
+ __send__(:immutable!)
118
+ return self
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,160 @@
1
+ module Erlang
2
+ # Helper module for Erlang sequential collections
3
+ #
4
+ # Classes including `Erlang::Enumerable` must implement:
5
+ #
6
+ # - `#each` (just like `::Enumerable`).
7
+ # - `#select`, which takes a block, and returns an instance of the same class
8
+ # with only the items for which the block returns a true value
9
+ #
10
+ # Licensing
11
+ # =========
12
+ #
13
+ # Portions taken and modified from https://github.com/hamstergem/hamster
14
+ #
15
+ # Copyright (c) 2009-2014 Simon Harris
16
+ #
17
+ # Permission is hereby granted, free of charge, to any person obtaining
18
+ # a copy of this software and associated documentation files (the
19
+ # "Software"), to deal in the Software without restriction, including
20
+ # without limitation the rights to use, copy, modify, merge, publish,
21
+ # distribute, sublicense, and/or sell copies of the Software, and to
22
+ # permit persons to whom the Software is furnished to do so, subject to
23
+ # the following conditions:
24
+ #
25
+ # The above copyright notice and this permission notice shall be
26
+ # included in all copies or substantial portions of the Software.
27
+ #
28
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
+ #
36
+ module Enumerable
37
+ include ::Enumerable
38
+
39
+ # Return a new collection with all the elements for which the block returns false.
40
+ def reject
41
+ return enum_for(:reject) if not block_given?
42
+ return select { |item| !yield(item) }
43
+ end
44
+ alias :delete_if :reject
45
+
46
+ # Return a new collection with all `nil` elements removed.
47
+ def compact
48
+ return select { |item| !item.nil? }
49
+ end
50
+
51
+ # Search the collection for elements which are `#===` to `item`. Yield them to
52
+ # the optional code block if provided, and return them as a new collection.
53
+ def grep(pattern, &block)
54
+ result = select { |item| pattern === item }
55
+ result = result.map(&block) if block_given?
56
+ return result
57
+ end
58
+
59
+ # Search the collection for elements which are not `#===` to `item`. Yield
60
+ # them to the optional code block if provided, and return them as a new
61
+ # collection.
62
+ def grep_v(pattern, &block)
63
+ result = select { |item| !(pattern === item) }
64
+ result = result.map(&block) if block_given?
65
+ return result
66
+ end
67
+
68
+ # Yield all integers from 0 up to, but not including, the number of items in
69
+ # this collection. For collections which provide indexed access, these are all
70
+ # the valid, non-negative indices into the collection.
71
+ def each_index(&block)
72
+ return enum_for(:each_index) unless block_given?
73
+ 0.upto(size-1, &block)
74
+ return self
75
+ end
76
+
77
+ # Multiply all the items (presumably numeric) in this collection together.
78
+ def product
79
+ return reduce(1, &:*)
80
+ end
81
+
82
+ # Add up all the items (presumably numeric) in this collection.
83
+ def sum
84
+ return reduce(0, &:+)
85
+ end
86
+
87
+ # Return 2 collections, the first containing all the elements for which the block
88
+ # evaluates to true, the second containing the rest.
89
+ def partition
90
+ return enum_for(:partition) if not block_given?
91
+ a,b = super
92
+ return Erlang::Tuple[self.class.new(a), self.class.new(b)]
93
+ end
94
+
95
+ # Groups the collection into sub-collections by the result of yielding them to
96
+ # the block. Returns a {Map} where the keys are return values from the block,
97
+ # and the values are sub-collections. All the sub-collections are built up from
98
+ # `empty_group`, which should respond to `#add` by returning a new collection
99
+ # with an added element.
100
+ def group_by_with(empty_group, &block)
101
+ block ||= lambda { |item| item }
102
+ return reduce(EmptyMap) do |map, item|
103
+ key = block.call(item)
104
+ group = map.get(key) || empty_group
105
+ map.put(key, group.add(item))
106
+ end
107
+ end
108
+ protected :group_by_with
109
+
110
+ # Groups the collection into sub-collections by the result of yielding them to
111
+ # the block. Returns a {Map} where the keys are return values from the block,
112
+ # and the values are sub-collections (of the same type as this one).
113
+ def group_by(&block)
114
+ return group_by_with(self.class.empty, &block)
115
+ end
116
+
117
+ # Convert all the elements into strings and join them together, separated by
118
+ # `separator`. By default, the `separator` is `$,`, the global default string
119
+ # separator, which is normally `nil`.
120
+ def join(separator = $,)
121
+ result = ""
122
+ if separator
123
+ each_with_index { |obj, i| result << separator if i > 0; result << obj.to_s }
124
+ else
125
+ each { |obj| result << obj.to_s }
126
+ end
127
+ return Erlang.from(result)
128
+ end
129
+
130
+ # Convert this collection to a programmer-readable `String` representation.
131
+ def inspect
132
+ result = "#{self.class}["
133
+ each_with_index { |obj, i| result << ', ' if i > 0; result << obj.inspect }
134
+ return result << "]"
135
+ end
136
+
137
+ # @private
138
+ def pretty_print(pp)
139
+ return pp.group(1, "#{self.class}[", "]") do
140
+ pp.breakable ''
141
+ pp.seplist(self) { |obj| obj.pretty_print(pp) }
142
+ end
143
+ end
144
+
145
+ alias :to_ary :to_a
146
+ alias :index :find_index
147
+
148
+ ## Compatibility fixes
149
+
150
+ if RUBY_ENGINE == 'rbx'
151
+ # Rubinius implements Enumerable#sort_by using Enumerable#map
152
+ # Because we do our own, custom implementations of #map, that doesn't work well
153
+ # @private
154
+ def sort_by(&block)
155
+ result = Erlang.from(to_a)
156
+ return result.frozen? ? result.sort_by(&block) : result.sort_by!(&block)
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,4 @@
1
+ module Erlang
2
+ # @private
3
+ class Error < StandardError; end
4
+ end
@@ -1,23 +1,121 @@
1
1
  module Erlang
2
+ # An `Export` is an external function. It corresponds to the `fun M:F/A` syntax from Erlang.
3
+ #
4
+ # ### Creating Exports
5
+ #
6
+ # Erlang::Export[:erlang, :make_ref, 0]
7
+ # # => Erlang::Export[:erlang, :make_ref, 0]
8
+ #
2
9
  class Export
3
- attr_accessor :mod, :function, :arity
10
+ include Erlang::Term
11
+ include Erlang::Immutable
4
12
 
13
+ # Return the module for this `Export`
14
+ # @return [Atom]
15
+ attr_reader :mod
16
+
17
+ # Return the function for this `Export`
18
+ # @return [Atom]
19
+ attr_reader :function
20
+
21
+ # Return the arity for this `Export`
22
+ # @return [Integer]
23
+ attr_reader :arity
24
+
25
+ class << self
26
+ # Create a new `Export` populated with the given `mod`, `function`, and `arity`.
27
+ # @param mod [Atom, Symbol] The module atom
28
+ # @param function [Atom, Symbol] The function atom
29
+ # @param arity [Integer] The arity of the function
30
+ # @return [Export]
31
+ # @raise [ArgumentError] if `arity` is not an `Integer`
32
+ def [](mod, function, arity)
33
+ return new(mod, function, arity)
34
+ end
35
+
36
+ # Compares `a` and `b` and returns whether they are less than,
37
+ # equal to, or greater than each other.
38
+ #
39
+ # @param a [Export] The left argument
40
+ # @param b [Export] The right argument
41
+ # @return [-1, 0, 1]
42
+ # @raise [ArgumentError] if `a` or `b` is not an `Export`
43
+ def compare(a, b)
44
+ raise ArgumentError, "'a' must be of Erlang::Export type" unless a.kind_of?(Erlang::Export)
45
+ raise ArgumentError, "'b' must be of Erlang::Export type" unless b.kind_of?(Erlang::Export)
46
+ c = Erlang.compare(a.mod, b.mod)
47
+ return c if c != 0
48
+ c = Erlang.compare(a.function, b.function)
49
+ return c if c != 0
50
+ c = Erlang.compare(a.arity, b.arity)
51
+ return c
52
+ end
53
+ end
54
+
55
+ # @private
5
56
  def initialize(mod, function, arity)
6
- self.mod = mod
7
- self.function = function
8
- self.arity = arity
57
+ raise ArgumentError, 'arity must be a non-negative Integer' if not arity.is_a?(::Integer) or arity < 0
58
+ @mod = Erlang::Atom[mod]
59
+ @function = Erlang::Atom[function]
60
+ @arity = arity.freeze
61
+ end
62
+
63
+ # Return true if `other` has the same type and contents as this `Export`.
64
+ #
65
+ # @param other [Object] The object to compare with
66
+ # @return [Boolean]
67
+ def eql?(other)
68
+ return true if other.equal?(self)
69
+ if instance_of?(other.class)
70
+ return !!(mod == other.mod &&
71
+ function == other.function &&
72
+ arity == other.arity)
73
+ else
74
+ return !!(Erlang.compare(other, self) == 0)
75
+ end
76
+ end
77
+ alias :== :eql?
78
+
79
+ # Return the contents of this `Export` as a Erlang-readable `::String`.
80
+ #
81
+ # @example
82
+ # Erlang::Export[:erlang, :make_ref, 0].erlang_inspect
83
+ # # => "fun 'erlang':'make_ref'/0"
84
+ #
85
+ # @return [::String]
86
+ def erlang_inspect(raw = false)
87
+ result = 'fun '
88
+ result << Erlang.inspect(@mod, raw: raw)
89
+ result << ':'
90
+ result << Erlang.inspect(@function, raw: raw)
91
+ result << '/'
92
+ result << Erlang.inspect(@arity, raw: raw)
93
+ return result
9
94
  end
10
95
 
11
- # @return [String] the nicely formatted version of the message
96
+ # @return [::String] the nicely formatted version of the `Export`.
12
97
  def inspect
13
- "#<#{self.class.name} fun #{mod}:#{function}/#{arity}>"
98
+ return "Erlang::Export[#{mod.inspect}, #{function.inspect}, #{arity.inspect}]"
99
+ end
100
+
101
+ # @private
102
+ def hash
103
+ state = [@mod, @function, @arity]
104
+ return state.reduce(Erlang::Export.hash) { |acc, item| (acc << 5) - acc + item.hash }
105
+ end
106
+
107
+ # @return [::Array]
108
+ # @private
109
+ def marshal_dump
110
+ return [@mod, @function, @arity]
14
111
  end
15
112
 
16
- def ==(other)
17
- self.class === other &&
18
- mod.to_s == other.mod.to_s &&
19
- function.to_s == other.function.to_s &&
20
- arity == other.arity
113
+ # @private
114
+ def marshal_load(args)
115
+ mod, function, arity = args
116
+ initialize(mod, function, arity)
117
+ __send__(:immutable!)
118
+ return self
21
119
  end
22
120
  end
23
- end
121
+ end
@@ -0,0 +1,201 @@
1
+ require 'bigdecimal'
2
+
3
+ module Erlang
4
+ # An `Float` is a literal constant float-precision number.
5
+ #
6
+ # ### Creating Floats
7
+ #
8
+ # Erlang::Float["1.0e10"]
9
+ # # => 1.00000000000000000000e+10
10
+ # Erlang::Float[0]
11
+ # # => 0.00000000000000000000e+00
12
+ # Erlang::Float[-0.0, old: true]
13
+ # # => Erlang::Float["-0.00000000000000000000e+00", old: true]
14
+ # Erlang::Float[-1e308]
15
+ # # => -1.00000000000000000000e+308
16
+ # Erlang::Float[1e-308]
17
+ # # => 1.00000000000000000000e-308
18
+ #
19
+ class Float
20
+ include Erlang::Term
21
+ include Erlang::Immutable
22
+
23
+ # Return the data for this `Float`
24
+ # @return [::BigDecimal]
25
+ attr_reader :data
26
+
27
+ # Return the old flag for this `Float`
28
+ # @return [::Boolean]
29
+ attr_reader :old
30
+
31
+ class << self
32
+ # Create a new `Float` populated with the given `data`.
33
+ # @param data [::BigDecimal, ::Float] The content of the `Float`
34
+ # @param old [Boolean] Whether the `Float` should be considered old or not
35
+ # @return [Float]
36
+ # @raise [ArgumentError] if `data` cannot be coerced to be a `::BigDecimal`
37
+ def [](data, old: false)
38
+ if data.is_a?(::String)
39
+ data = ::BigDecimal.new(data)
40
+ elsif not data.is_a?(::BigDecimal)
41
+ data = ::BigDecimal.new(data.to_s)
42
+ end
43
+ return new(data, old)
44
+ end
45
+
46
+ # Compares `a` and `b` and returns whether they are less than,
47
+ # equal to, or greater than each other.
48
+ #
49
+ # @param a [Float] The left argument
50
+ # @param b [Float] The right argument
51
+ # @return [-1, 0, 1]
52
+ # @raise [ArgumentError] if `a` or `b` is not an `Float`
53
+ def compare(a, b)
54
+ raise ArgumentError, "'a' must be of Erlang::Float type" unless a.kind_of?(Erlang::Float)
55
+ raise ArgumentError, "'b' must be of Erlang::Float type" unless b.kind_of?(Erlang::Float)
56
+ return a.data <=> b.data
57
+ end
58
+ end
59
+
60
+ # @private
61
+ def initialize(data, old)
62
+ raise ArgumentError, 'data must be a BigDecimal' if not data.is_a?(::BigDecimal)
63
+ @data = data.freeze
64
+ @old = !!old
65
+ if @old == false and @data != @data.to_f
66
+ @data = ::BigDecimal.new(@data.to_f.to_s).freeze
67
+ end
68
+ raise ArgumentError, "data cannot be positive or negative Infinity: #{data.inspect}" if @data.to_s.include?("Infinity")
69
+ end
70
+
71
+ # @private
72
+ def hash
73
+ return @data.hash
74
+ end
75
+
76
+ # If a `numeric` is the same type as `self`, returns an array containing `numeric` and `self`.
77
+ # Otherwise, returns an array with both a numeric and num represented as `Float` objects.
78
+ #
79
+ # @param numeric [Erlang::Float, Numeric]
80
+ # @return [::Array]
81
+ def coerce(numeric)
82
+ if numeric.is_a?(Erlang::Float)
83
+ return [numeric, self]
84
+ else
85
+ return [numeric.to_f, to_f]
86
+ end
87
+ end
88
+
89
+ # Return true if `other` has the same type and contents as this `Float`.
90
+ #
91
+ # @param other [Object] The object to compare with
92
+ # @return [Boolean]
93
+ def eql?(other)
94
+ return true if other.equal?(self)
95
+ if instance_of?(other.class)
96
+ return !!(self.data == other.data)
97
+ else
98
+ return !!(Erlang.compare(other, self) == 0)
99
+ end
100
+ end
101
+ alias :== :eql?
102
+
103
+ # Return the contents of this `Float` as a Erlang-readable `::String`.
104
+ #
105
+ # @example
106
+ # Erlang::Float[-1e308].erlang_inspect
107
+ # # => "-1.00000000000000000000e+308"
108
+ #
109
+ # @return [::String]
110
+ def erlang_inspect(raw = false)
111
+ return to_float_string
112
+ end
113
+
114
+ # @return [::String] the nicely formatted version of the `Float`
115
+ def inspect
116
+ if @old
117
+ return "Erlang::Float[#{to_float_string.inspect}, old: true]"
118
+ else
119
+ float_string = to_float_string
120
+ float_object = ::Kernel::Float(float_string)
121
+ if Erlang::PositiveInfinity == float_object or Erlang::NegativeInfinity == float_object
122
+ return "Erlang::Float[#{float_string.inspect}]"
123
+ else
124
+ return float_string
125
+ end
126
+ end
127
+ end
128
+
129
+ # @return [::String] the float string format of the `Float`
130
+ def to_float_string
131
+ string = @data.to_s
132
+ sign = (string.getbyte(0) == 45) ? '-' : ''
133
+ offset = (sign.bytesize == 1) ? 1 : 0
134
+ dotpos = string.index(?.)
135
+ epos = string.index(?e)
136
+ if epos.nil?
137
+ string << "e00"
138
+ epos = string.index(?e)
139
+ end
140
+ if @data.zero?
141
+ return Erlang::Terms.binary_encoding([
142
+ sign,
143
+ '0.00000000000000000000e+00'
144
+ ].join)
145
+ end
146
+ integer = string.byteslice(offset, dotpos - offset)
147
+ fractional = string.byteslice(dotpos + 1, epos - dotpos - 1)
148
+ e = string.byteslice(epos + 1, string.bytesize - epos - 1).to_i
149
+ while fractional.bytesize > 0 and integer == ?0 and e > -323
150
+ b = fractional.getbyte(0)
151
+ fractional = fractional.byteslice(1, fractional.bytesize - 1)
152
+ e -= 1
153
+ if b != 48
154
+ integer.setbyte(0, b)
155
+ end
156
+ end
157
+ if fractional.bytesize > 20
158
+ fractional = fractional.byteslice(0, 20)
159
+ elsif fractional.bytesize < 20
160
+ fractional = fractional.ljust(20, ?0)
161
+ end
162
+ return Erlang::Terms.binary_encoding([
163
+ sign,
164
+ integer,
165
+ '.',
166
+ fractional,
167
+ (e < 0) ? 'e-' : 'e+',
168
+ e.abs.to_s.rjust(2, ?0)
169
+ ].join)
170
+ end
171
+
172
+ # @return [::Float] the float version of the `Float`
173
+ def to_f
174
+ return @data.to_f
175
+ end
176
+
177
+ # @return [::String] the string version of the `Float`
178
+ def to_s
179
+ return to_float_string
180
+ end
181
+ alias :to_str :to_s
182
+
183
+ # @return [::String]
184
+ # @private
185
+ def marshal_dump
186
+ return [to_float_string, @old]
187
+ end
188
+
189
+ # @private
190
+ def marshal_load(args)
191
+ float_string, old = args
192
+ initialize(::BigDecimal.new(float_string), old)
193
+ __send__(:immutable!)
194
+ return self
195
+ end
196
+
197
+ end
198
+
199
+ PositiveInfinity = (1.0 / 0.0).freeze
200
+ NegativeInfinity = -PositiveInfinity
201
+ end