erlang-terms 1.1.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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