cbor-diag 0.1.0
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.
- checksums.yaml +7 -0
 - data/bin/cbor2diag.rb +7 -0
 - data/bin/cbor2json.rb +8 -0
 - data/bin/cbor2pretty.rb +7 -0
 - data/bin/cbor2yaml.rb +15 -0
 - data/bin/diag2cbor.rb +20 -0
 - data/bin/diag2pretty.rb +15 -0
 - data/bin/json2cbor.rb +14 -0
 - data/bin/json2pretty.rb +8 -0
 - data/cbor-diag.gemspec +22 -0
 - data/lib/cbor-diag-parser.rb +2127 -0
 - data/lib/cbor-diagnostic.rb +74 -0
 - data/lib/cbor-pretty.rb +88 -0
 - data/lib/cbor-pure.rb +260 -0
 - data/lib/half.rb +111 -0
 - metadata +108 -0
 
| 
         @@ -0,0 +1,74 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # This should work with the C-ext cbor-ruby as well as with our cbor-pure
         
     | 
| 
      
 2 
     | 
    
         
            +
            unless defined?(CBOR)
         
     | 
| 
      
 3 
     | 
    
         
            +
              require_relative 'cbor-pure'
         
     | 
| 
      
 4 
     | 
    
         
            +
            end
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            class Object
         
     | 
| 
      
 7 
     | 
    
         
            +
              def cbor_diagnostic
         
     | 
| 
      
 8 
     | 
    
         
            +
                inspect
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            class NilClass
         
     | 
| 
      
 13 
     | 
    
         
            +
              def cbor_diagnostic
         
     | 
| 
      
 14 
     | 
    
         
            +
                "null"
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            class Float
         
     | 
| 
      
 19 
     | 
    
         
            +
              def cbor_diagnostic           # do a little bit of JSON.stringify gaming (ECMA-262, 9.8.1)
         
     | 
| 
      
 20 
     | 
    
         
            +
                a = abs
         
     | 
| 
      
 21 
     | 
    
         
            +
                if a < 1 && a >= 1e-6
         
     | 
| 
      
 22 
     | 
    
         
            +
                  inspect.sub(/(\d)[.](\d+)e-(\d+)/) {"0.#{"0" * ($3.to_i - 1)}#{$1}#{$2}"}
         
     | 
| 
      
 23 
     | 
    
         
            +
                else
         
     | 
| 
      
 24 
     | 
    
         
            +
                  inspect.sub(/(e[+-])0+/) {$1}
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            raise unless 0.00006103515625.cbor_diagnostic == "0.00006103515625"
         
     | 
| 
      
 30 
     | 
    
         
            +
            raise unless 0.99.cbor_diagnostic == "0.99"
         
     | 
| 
      
 31 
     | 
    
         
            +
            raise unless 0.099.cbor_diagnostic == "0.099"
         
     | 
| 
      
 32 
     | 
    
         
            +
            raise unless 0.0000099.cbor_diagnostic == "0.0000099"
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            class String
         
     | 
| 
      
 35 
     | 
    
         
            +
              unless String.instance_methods.include?(:b)
         
     | 
| 
      
 36 
     | 
    
         
            +
                def b
         
     | 
| 
      
 37 
     | 
    
         
            +
                  dup.force_encoding(Encoding::BINARY)
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
              def hexbytes(sep = '')
         
     | 
| 
      
 41 
     | 
    
         
            +
                bytes.map{|x| "%02x" % x}.join(sep)
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
              def cbor_diagnostic
         
     | 
| 
      
 44 
     | 
    
         
            +
                if lengths = cbor_stream?
         
     | 
| 
      
 45 
     | 
    
         
            +
                  pos = 0
         
     | 
| 
      
 46 
     | 
    
         
            +
                  "(_ #{lengths.map{|l| r = self[pos, l].cbor_diagnostic; pos += l; r}.join(", ")})"
         
     | 
| 
      
 47 
     | 
    
         
            +
                else
         
     | 
| 
      
 48 
     | 
    
         
            +
                  if encoding == Encoding::BINARY
         
     | 
| 
      
 49 
     | 
    
         
            +
                    "h'#{hexbytes}'"
         
     | 
| 
      
 50 
     | 
    
         
            +
                  else
         
     | 
| 
      
 51 
     | 
    
         
            +
                    inspect.encode(Encoding::UTF_16BE).bytes.each_slice(2).map {
         
     | 
| 
      
 52 
     | 
    
         
            +
                      |c1, c2| c = (c1 << 8)+c2; c < 128 ? c.chr : '\u%04x' % c }.join
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
            end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            class Array
         
     | 
| 
      
 59 
     | 
    
         
            +
              def cbor_diagnostic
         
     | 
| 
      
 60 
     | 
    
         
            +
                "[#{"_ " if cbor_stream?}#{map(&:cbor_diagnostic).join(", ")}]"
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
            class Hash
         
     | 
| 
      
 65 
     | 
    
         
            +
              def cbor_diagnostic
         
     | 
| 
      
 66 
     | 
    
         
            +
                "{#{"_ " if cbor_stream?}#{map{ |k, v| %{#{k.cbor_diagnostic}: #{v.cbor_diagnostic}}}.join(", ")}}"
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
            end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            class CBOR::Tagged
         
     | 
| 
      
 71 
     | 
    
         
            +
              def cbor_diagnostic
         
     | 
| 
      
 72 
     | 
    
         
            +
                "#{tag}(#{data.cbor_diagnostic})"
         
     | 
| 
      
 73 
     | 
    
         
            +
              end
         
     | 
| 
      
 74 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/cbor-pretty.rb
    ADDED
    
    | 
         @@ -0,0 +1,88 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- coding: utf-8 -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # This should work with the C-ext cbor-ruby as well as with our cbor-pure
         
     | 
| 
      
 4 
     | 
    
         
            +
            unless defined?(CBOR)
         
     | 
| 
      
 5 
     | 
    
         
            +
              require_relative 'cbor-pure'
         
     | 
| 
      
 6 
     | 
    
         
            +
            end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            class String
         
     | 
| 
      
 9 
     | 
    
         
            +
              def hexbytes(sep = '')
         
     | 
| 
      
 10 
     | 
    
         
            +
                bytes.map{|x| "%02x" % x}.join(sep)
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            class CBOR
         
     | 
| 
      
 16 
     | 
    
         
            +
              def self.pretty(s, indent = 0, max_target = 40)
         
     | 
| 
      
 17 
     | 
    
         
            +
                new(s).pretty_item_final(indent, max_target)
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              def take_and_print(n, prefix = '')
         
     | 
| 
      
 21 
     | 
    
         
            +
                s = take(n)
         
     | 
| 
      
 22 
     | 
    
         
            +
                @out << prefix
         
     | 
| 
      
 23 
     | 
    
         
            +
                @out << s.hexbytes
         
     | 
| 
      
 24 
     | 
    
         
            +
                s
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
              
         
     | 
| 
      
 27 
     | 
    
         
            +
              def pretty_item_streaming(ib)
         
     | 
| 
      
 28 
     | 
    
         
            +
                res = nil
         
     | 
| 
      
 29 
     | 
    
         
            +
                @out << " # #{MT_NAMES[ib >> 5]}(*)\n"
         
     | 
| 
      
 30 
     | 
    
         
            +
                @indent += 1
         
     | 
| 
      
 31 
     | 
    
         
            +
                case ib >>= 5
         
     | 
| 
      
 32 
     | 
    
         
            +
                when 2, 3, 4, 5
         
     | 
| 
      
 33 
     | 
    
         
            +
                  while (element = pretty_item) != BREAK
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                when 7; res = BREAK
         
     | 
| 
      
 36 
     | 
    
         
            +
                else raise "unknown ib #{ib} for additional information 31"
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
                @indent -= 1
         
     | 
| 
      
 39 
     | 
    
         
            +
                res
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              MT_NAMES = ["unsigned", "negative", "bytes", "text", "array", "map", "tag", "primitive"]
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              def pretty_item
         
     | 
| 
      
 45 
     | 
    
         
            +
                ib = take_and_print(1, '   ' * @indent).ord
         
     | 
| 
      
 46 
     | 
    
         
            +
                ai = ib & 0x1F
         
     | 
| 
      
 47 
     | 
    
         
            +
                val = case ai
         
     | 
| 
      
 48 
     | 
    
         
            +
                      when 0...24; ai
         
     | 
| 
      
 49 
     | 
    
         
            +
                      when 24; take_and_print(1, ' ').ord
         
     | 
| 
      
 50 
     | 
    
         
            +
                      when 25; take_and_print(2, ' ').unpack("n").first
         
     | 
| 
      
 51 
     | 
    
         
            +
                      when 26; (s = take_and_print(4, ' ')).unpack("N").first
         
     | 
| 
      
 52 
     | 
    
         
            +
                      when 27; (s = take_and_print(8, ' ')).unpack("Q>").first
         
     | 
| 
      
 53 
     | 
    
         
            +
                      when 31; return pretty_item_streaming(ib)
         
     | 
| 
      
 54 
     | 
    
         
            +
                      else raise "unknown additional information #{ai} in ib #{ib}"
         
     | 
| 
      
 55 
     | 
    
         
            +
                      end
         
     | 
| 
      
 56 
     | 
    
         
            +
                @out << " # #{MT_NAMES[ib >> 5]}(#{val})\n"
         
     | 
| 
      
 57 
     | 
    
         
            +
                @indent += 1
         
     | 
| 
      
 58 
     | 
    
         
            +
                case ib >>= 5
         
     | 
| 
      
 59 
     | 
    
         
            +
                when 6
         
     | 
| 
      
 60 
     | 
    
         
            +
                  pretty_item
         
     | 
| 
      
 61 
     | 
    
         
            +
                when 2, 3
         
     | 
| 
      
 62 
     | 
    
         
            +
                  @out << '   ' * (@indent)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  s = take_and_print(val)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  @out << " # #{s.inspect}"
         
     | 
| 
      
 65 
     | 
    
         
            +
                  @out << "\n"
         
     | 
| 
      
 66 
     | 
    
         
            +
                when 4; val.times { pretty_item }
         
     | 
| 
      
 67 
     | 
    
         
            +
                when 5; val.times { pretty_item; pretty_item}
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
                @indent -= 1
         
     | 
| 
      
 70 
     | 
    
         
            +
                nil
         
     | 
| 
      
 71 
     | 
    
         
            +
              end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
              def pretty_item_final(indent = 0, max_target = 40)
         
     | 
| 
      
 74 
     | 
    
         
            +
                @out = ''
         
     | 
| 
      
 75 
     | 
    
         
            +
                @indent = indent
         
     | 
| 
      
 76 
     | 
    
         
            +
                pretty_item
         
     | 
| 
      
 77 
     | 
    
         
            +
                raise if @pos != @buffer.size
         
     | 
| 
      
 78 
     | 
    
         
            +
                target = [@out.each_line.map {|ln| ln =~ /#/ || 0}.max, max_target].min
         
     | 
| 
      
 79 
     | 
    
         
            +
                @out.each_line.map {|ln|
         
     | 
| 
      
 80 
     | 
    
         
            +
                  col = ln =~ /#/
         
     | 
| 
      
 81 
     | 
    
         
            +
                  if col && col < target
         
     | 
| 
      
 82 
     | 
    
         
            +
                    ln[col, 0] = ' ' * (target - col)
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
                  ln
         
     | 
| 
      
 85 
     | 
    
         
            +
                }.join
         
     | 
| 
      
 86 
     | 
    
         
            +
              end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/cbor-pure.rb
    ADDED
    
    | 
         @@ -0,0 +1,260 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- coding: utf-8 -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative "half.rb"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            class CBOR
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Streaming
         
     | 
| 
      
 8 
     | 
    
         
            +
                def cbor_stream?
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @cbor_streaming
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
                def cbor_stream!(b = true)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @cbor_streaming = b
         
     | 
| 
      
 13 
     | 
    
         
            +
                  self
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
              Array.send(:include, Streaming)
         
     | 
| 
      
 17 
     | 
    
         
            +
              Hash.send(:include, Streaming)
         
     | 
| 
      
 18 
     | 
    
         
            +
              String.send(:include, Streaming)
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              class Break
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
              BREAK = Break.new.freeze
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              Tagged = Struct.new(:tag, :data) do
         
     | 
| 
      
 25 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 26 
     | 
    
         
            +
                  "#{tag}(#{data})"
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 29 
     | 
    
         
            +
                  "#{tag}(#{data.inspect})"
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              TAG_BIGNUM_BASE = 2
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              Simple = Struct.new(:value) do
         
     | 
| 
      
 36 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 37 
     | 
    
         
            +
                  if value == 23
         
     | 
| 
      
 38 
     | 
    
         
            +
                    "undefined"
         
     | 
| 
      
 39 
     | 
    
         
            +
                  else
         
     | 
| 
      
 40 
     | 
    
         
            +
                    "simple(#{value})"
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
                alias_method :inspect, :to_s
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              def self.encode(d)
         
     | 
| 
      
 47 
     | 
    
         
            +
                new.add(d).buffer
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
              def self.decode(s)
         
     | 
| 
      
 50 
     | 
    
         
            +
                new(s).decode_item_final
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
              attr_reader :buffer
         
     | 
| 
      
 54 
     | 
    
         
            +
              def initialize(s = String.new)
         
     | 
| 
      
 55 
     | 
    
         
            +
                @buffer = s
         
     | 
| 
      
 56 
     | 
    
         
            +
                @pos = 0
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
              def head(ib, n)
         
     | 
| 
      
 60 
     | 
    
         
            +
                @buffer <<
         
     | 
| 
      
 61 
     | 
    
         
            +
                  case n
         
     | 
| 
      
 62 
     | 
    
         
            +
                  when 0...24
         
     | 
| 
      
 63 
     | 
    
         
            +
                    [ib + n].pack("C")
         
     | 
| 
      
 64 
     | 
    
         
            +
                  when 0...256
         
     | 
| 
      
 65 
     | 
    
         
            +
                    [ib + 24, n].pack("CC")
         
     | 
| 
      
 66 
     | 
    
         
            +
                  when 0...65536
         
     | 
| 
      
 67 
     | 
    
         
            +
                    [ib + 25, n].pack("Cn")
         
     | 
| 
      
 68 
     | 
    
         
            +
                  when 0...4294967296
         
     | 
| 
      
 69 
     | 
    
         
            +
                    [ib + 26, n].pack("CN")
         
     | 
| 
      
 70 
     | 
    
         
            +
                  when 0...18446744073709551616
         
     | 
| 
      
 71 
     | 
    
         
            +
                    [ib + 27, n].pack("CQ>")
         
     | 
| 
      
 72 
     | 
    
         
            +
                  else
         
     | 
| 
      
 73 
     | 
    
         
            +
                    yield                   # throw back to caller
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
              HALF_NAN_BYTES = ("\xf9".force_encoding(Encoding::BINARY) + Half::NAN_BYTES).freeze
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
              def addfloat(fv)
         
     | 
| 
      
 80 
     | 
    
         
            +
                if fv.nan?
         
     | 
| 
      
 81 
     | 
    
         
            +
                  @buffer << HALF_NAN_BYTES
         
     | 
| 
      
 82 
     | 
    
         
            +
                else
         
     | 
| 
      
 83 
     | 
    
         
            +
                  ss = [fv].pack("g")         # single-precision
         
     | 
| 
      
 84 
     | 
    
         
            +
                  if ss.unpack("g").first == fv
         
     | 
| 
      
 85 
     | 
    
         
            +
                    if hs = Half.encode_from_single(fv, ss)
         
     | 
| 
      
 86 
     | 
    
         
            +
                      @buffer << 0xf9 << hs
         
     | 
| 
      
 87 
     | 
    
         
            +
                    else
         
     | 
| 
      
 88 
     | 
    
         
            +
                      @buffer << 0xfa << ss
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
                  else
         
     | 
| 
      
 91 
     | 
    
         
            +
                    @buffer << [0xfb, fv].pack("CG") # double-precision
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
              end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
              def bignum_to_bytes(d)
         
     | 
| 
      
 97 
     | 
    
         
            +
                s = String.new
         
     | 
| 
      
 98 
     | 
    
         
            +
                while (d != 0)
         
     | 
| 
      
 99 
     | 
    
         
            +
                  s << (d & 0xFF)
         
     | 
| 
      
 100 
     | 
    
         
            +
                  d >>= 8
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
                s.reverse!
         
     | 
| 
      
 103 
     | 
    
         
            +
              end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
              def add(d)
         
     | 
| 
      
 106 
     | 
    
         
            +
                case d
         
     | 
| 
      
 107 
     | 
    
         
            +
                when Integer
         
     | 
| 
      
 108 
     | 
    
         
            +
                  ib = if d < 0
         
     | 
| 
      
 109 
     | 
    
         
            +
                         d = -1-d
         
     | 
| 
      
 110 
     | 
    
         
            +
                         0x20
         
     | 
| 
      
 111 
     | 
    
         
            +
                       else
         
     | 
| 
      
 112 
     | 
    
         
            +
                         0x00
         
     | 
| 
      
 113 
     | 
    
         
            +
                       end
         
     | 
| 
      
 114 
     | 
    
         
            +
                  head(ib, d) {             # block is called if things do not fit
         
     | 
| 
      
 115 
     | 
    
         
            +
                    s = bignum_to_bytes(d)
         
     | 
| 
      
 116 
     | 
    
         
            +
                    head(0xc0, TAG_BIGNUM_BASE + (ib >> 5))
         
     | 
| 
      
 117 
     | 
    
         
            +
                    head(0x40, s.bytesize)
         
     | 
| 
      
 118 
     | 
    
         
            +
                    s
         
     | 
| 
      
 119 
     | 
    
         
            +
                  }
         
     | 
| 
      
 120 
     | 
    
         
            +
                when Numeric; addfloat(d)
         
     | 
| 
      
 121 
     | 
    
         
            +
                when Symbol; add(d.to_s)    # hack: this should really be tagged
         
     | 
| 
      
 122 
     | 
    
         
            +
                when Simple; head(0xe0, d.value)
         
     | 
| 
      
 123 
     | 
    
         
            +
                when false; head(0xe0, 20)
         
     | 
| 
      
 124 
     | 
    
         
            +
                when true; head(0xe0, 21)
         
     | 
| 
      
 125 
     | 
    
         
            +
                when nil; head(0xe0, 22)
         
     | 
| 
      
 126 
     | 
    
         
            +
                when Tagged                 # we don't handle :simple here
         
     | 
| 
      
 127 
     | 
    
         
            +
                  head(0xc0, d.tag)
         
     | 
| 
      
 128 
     | 
    
         
            +
                  add(d.data)
         
     | 
| 
      
 129 
     | 
    
         
            +
                when String
         
     | 
| 
      
 130 
     | 
    
         
            +
                  lengths = d.cbor_stream?
         
     | 
| 
      
 131 
     | 
    
         
            +
                  e = d
         
     | 
| 
      
 132 
     | 
    
         
            +
                  ib = if d.encoding == Encoding::BINARY
         
     | 
| 
      
 133 
     | 
    
         
            +
                         0x40
         
     | 
| 
      
 134 
     | 
    
         
            +
                       else
         
     | 
| 
      
 135 
     | 
    
         
            +
                         d = d.encode(Encoding::UTF_8).force_encoding(Encoding::BINARY)
         
     | 
| 
      
 136 
     | 
    
         
            +
                         0x60
         
     | 
| 
      
 137 
     | 
    
         
            +
                       end
         
     | 
| 
      
 138 
     | 
    
         
            +
                  if lengths
         
     | 
| 
      
 139 
     | 
    
         
            +
                    @buffer << (ib + 31)
         
     | 
| 
      
 140 
     | 
    
         
            +
                    pos = 0
         
     | 
| 
      
 141 
     | 
    
         
            +
                    lengths.each do |r|
         
     | 
| 
      
 142 
     | 
    
         
            +
                      add(e[pos, r])
         
     | 
| 
      
 143 
     | 
    
         
            +
                      pos += r
         
     | 
| 
      
 144 
     | 
    
         
            +
                    end
         
     | 
| 
      
 145 
     | 
    
         
            +
                    @buffer << 0xff
         
     | 
| 
      
 146 
     | 
    
         
            +
                  else
         
     | 
| 
      
 147 
     | 
    
         
            +
                    head(ib, d.bytesize)
         
     | 
| 
      
 148 
     | 
    
         
            +
                    @buffer << d
         
     | 
| 
      
 149 
     | 
    
         
            +
                  end
         
     | 
| 
      
 150 
     | 
    
         
            +
                when Array
         
     | 
| 
      
 151 
     | 
    
         
            +
                  if d.cbor_stream?
         
     | 
| 
      
 152 
     | 
    
         
            +
                    @buffer << 0x9f
         
     | 
| 
      
 153 
     | 
    
         
            +
                    d.each {|di| add(di)}
         
     | 
| 
      
 154 
     | 
    
         
            +
                    @buffer << 0xff
         
     | 
| 
      
 155 
     | 
    
         
            +
                  else
         
     | 
| 
      
 156 
     | 
    
         
            +
                    head(0x80, d.size)
         
     | 
| 
      
 157 
     | 
    
         
            +
                    d.each {|di| add(di)}
         
     | 
| 
      
 158 
     | 
    
         
            +
                  end
         
     | 
| 
      
 159 
     | 
    
         
            +
                when Hash
         
     | 
| 
      
 160 
     | 
    
         
            +
                  if d.cbor_stream?
         
     | 
| 
      
 161 
     | 
    
         
            +
                    @buffer << 0xbf
         
     | 
| 
      
 162 
     | 
    
         
            +
                    d.each {|k, v| add(k); add(v)}
         
     | 
| 
      
 163 
     | 
    
         
            +
                    @buffer << 0xff
         
     | 
| 
      
 164 
     | 
    
         
            +
                  else
         
     | 
| 
      
 165 
     | 
    
         
            +
                    head(0xa0, d.size)
         
     | 
| 
      
 166 
     | 
    
         
            +
                    d.each {|k, v| add(k); add(v)}
         
     | 
| 
      
 167 
     | 
    
         
            +
                  end
         
     | 
| 
      
 168 
     | 
    
         
            +
                else
         
     | 
| 
      
 169 
     | 
    
         
            +
                  raise("Don't know how to encode #{d.inspect}")
         
     | 
| 
      
 170 
     | 
    
         
            +
                end
         
     | 
| 
      
 171 
     | 
    
         
            +
                self
         
     | 
| 
      
 172 
     | 
    
         
            +
              end
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
              def take(n)
         
     | 
| 
      
 175 
     | 
    
         
            +
                opos = @pos
         
     | 
| 
      
 176 
     | 
    
         
            +
                @pos += n
         
     | 
| 
      
 177 
     | 
    
         
            +
                raise "Out of bytes to decode: #{opos} + #{n} > #{@buffer.bytesize}" if @pos > @buffer.bytesize
         
     | 
| 
      
 178 
     | 
    
         
            +
                @buffer[opos, n]
         
     | 
| 
      
 179 
     | 
    
         
            +
              end
         
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
      
 181 
     | 
    
         
            +
              MT_TO_ENCODING = {2 => Encoding::BINARY, 3 => Encoding::UTF_8}
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
              def decode_item_streaming(ib, breakable)
         
     | 
| 
      
 184 
     | 
    
         
            +
                case ib >>= 5
         
     | 
| 
      
 185 
     | 
    
         
            +
                when 2, 3
         
     | 
| 
      
 186 
     | 
    
         
            +
                  want_encoding = MT_TO_ENCODING[ib]
         
     | 
| 
      
 187 
     | 
    
         
            +
                  subs = []
         
     | 
| 
      
 188 
     | 
    
         
            +
                  while (element = decode_item(true)) != BREAK
         
     | 
| 
      
 189 
     | 
    
         
            +
                    raise "non-string (#{element.inspect}) in streaming string" unless String === element
         
     | 
| 
      
 190 
     | 
    
         
            +
                    raise "bytes/text mismatch (#{element.encoding} != #{want_encoding}) in streaming string" unless element.encoding == want_encoding
         
     | 
| 
      
 191 
     | 
    
         
            +
                    subs << element
         
     | 
| 
      
 192 
     | 
    
         
            +
                  end
         
     | 
| 
      
 193 
     | 
    
         
            +
                  result = subs.join.cbor_stream!(subs.map(&:length)).force_encoding(want_encoding)
         
     | 
| 
      
 194 
     | 
    
         
            +
                when 4
         
     | 
| 
      
 195 
     | 
    
         
            +
                  result = Array.new;
         
     | 
| 
      
 196 
     | 
    
         
            +
                  while (element = decode_item(true)) != BREAK
         
     | 
| 
      
 197 
     | 
    
         
            +
                    result << element
         
     | 
| 
      
 198 
     | 
    
         
            +
                  end
         
     | 
| 
      
 199 
     | 
    
         
            +
                  result
         
     | 
| 
      
 200 
     | 
    
         
            +
                when 5
         
     | 
| 
      
 201 
     | 
    
         
            +
                  result = Hash.new
         
     | 
| 
      
 202 
     | 
    
         
            +
                  while (key = decode_item(true)) != BREAK
         
     | 
| 
      
 203 
     | 
    
         
            +
                    result[key] = decode_item
         
     | 
| 
      
 204 
     | 
    
         
            +
                  end
         
     | 
| 
      
 205 
     | 
    
         
            +
                  result
         
     | 
| 
      
 206 
     | 
    
         
            +
                when 7
         
     | 
| 
      
 207 
     | 
    
         
            +
                  raise "break stop code outside indefinite length item" unless breakable
         
     | 
| 
      
 208 
     | 
    
         
            +
                  BREAK
         
     | 
| 
      
 209 
     | 
    
         
            +
                else raise "unknown ib #{ib} for additional information 31"
         
     | 
| 
      
 210 
     | 
    
         
            +
                end
         
     | 
| 
      
 211 
     | 
    
         
            +
              end
         
     | 
| 
      
 212 
     | 
    
         
            +
              
         
     | 
| 
      
 213 
     | 
    
         
            +
              def decode_item(breakable = false)
         
     | 
| 
      
 214 
     | 
    
         
            +
                ib = take(1).ord
         
     | 
| 
      
 215 
     | 
    
         
            +
                ai = ib & 0x1F
         
     | 
| 
      
 216 
     | 
    
         
            +
                val = case ai
         
     | 
| 
      
 217 
     | 
    
         
            +
                      when 0...24; ai
         
     | 
| 
      
 218 
     | 
    
         
            +
                      when 24; take(1).ord
         
     | 
| 
      
 219 
     | 
    
         
            +
                      when 25; take(2).unpack("n").first
         
     | 
| 
      
 220 
     | 
    
         
            +
                      when 26; (s = take(4)).unpack("N").first
         
     | 
| 
      
 221 
     | 
    
         
            +
                      when 27; (s = take(8)).unpack("Q>").first
         
     | 
| 
      
 222 
     | 
    
         
            +
                      when 31; return decode_item_streaming(ib, breakable)
         
     | 
| 
      
 223 
     | 
    
         
            +
                      else raise "unknown additional information #{ai} in ib #{ib}"
         
     | 
| 
      
 224 
     | 
    
         
            +
                      end
         
     | 
| 
      
 225 
     | 
    
         
            +
                case ib >>= 5
         
     | 
| 
      
 226 
     | 
    
         
            +
                when 0; val
         
     | 
| 
      
 227 
     | 
    
         
            +
                when 1; -1-val
         
     | 
| 
      
 228 
     | 
    
         
            +
                when 7
         
     | 
| 
      
 229 
     | 
    
         
            +
                  case ai
         
     | 
| 
      
 230 
     | 
    
         
            +
                  when 20; false
         
     | 
| 
      
 231 
     | 
    
         
            +
                  when 21; true
         
     | 
| 
      
 232 
     | 
    
         
            +
                  when 22; nil
         
     | 
| 
      
 233 
     | 
    
         
            +
                  # when 27; Simple.new(27)   # Ruby does not have Undefined
         
     | 
| 
      
 234 
     | 
    
         
            +
                  when 25; Half.decode(val)
         
     | 
| 
      
 235 
     | 
    
         
            +
                  when 26; s.unpack("g").first # cannot go directly from val
         
     | 
| 
      
 236 
     | 
    
         
            +
                  when 27; s.unpack("G").first #   in Ruby
         
     | 
| 
      
 237 
     | 
    
         
            +
                  else
         
     | 
| 
      
 238 
     | 
    
         
            +
                    Simple.new(val)
         
     | 
| 
      
 239 
     | 
    
         
            +
                  end
         
     | 
| 
      
 240 
     | 
    
         
            +
                when 6
         
     | 
| 
      
 241 
     | 
    
         
            +
                  di = decode_item
         
     | 
| 
      
 242 
     | 
    
         
            +
                  if String === di && (val & ~1) == TAG_BIGNUM_BASE
         
     | 
| 
      
 243 
     | 
    
         
            +
                    (TAG_BIGNUM_BASE - val) ^ di.bytes.inject(0) {|sum, b| sum <<= 8; sum += b }
         
     | 
| 
      
 244 
     | 
    
         
            +
                  else
         
     | 
| 
      
 245 
     | 
    
         
            +
                    Tagged.new(val, di)
         
     | 
| 
      
 246 
     | 
    
         
            +
                  end
         
     | 
| 
      
 247 
     | 
    
         
            +
                when 2; take(val).force_encoding(Encoding::BINARY)
         
     | 
| 
      
 248 
     | 
    
         
            +
                when 3; take(val).force_encoding(Encoding::UTF_8)
         
     | 
| 
      
 249 
     | 
    
         
            +
                when 4; Array.new(val) { decode_item }
         
     | 
| 
      
 250 
     | 
    
         
            +
                when 5; Hash[Array.new(val) {[decode_item, decode_item]}]
         
     | 
| 
      
 251 
     | 
    
         
            +
                end
         
     | 
| 
      
 252 
     | 
    
         
            +
              end
         
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
              def decode_item_final
         
     | 
| 
      
 255 
     | 
    
         
            +
                val = decode_item
         
     | 
| 
      
 256 
     | 
    
         
            +
                raise "extra bytes follow after a deserialized object" if @pos != @buffer.size
         
     | 
| 
      
 257 
     | 
    
         
            +
                val
         
     | 
| 
      
 258 
     | 
    
         
            +
              end
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
      
 260 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/half.rb
    ADDED
    
    | 
         @@ -0,0 +1,111 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- coding: utf-8 -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # 16-bit floating point values (IEEE 754 Half Precision) are not
         
     | 
| 
      
 4 
     | 
    
         
            +
            # supported by #pack/#unpack in Ruby yet.
         
     | 
| 
      
 5 
     | 
    
         
            +
            # This is a quick hack implementing en- and decoding them.
         
     | 
| 
      
 6 
     | 
    
         
            +
            # (Since this is just a hack, the brief tests are in this file.)
         
     | 
| 
      
 7 
     | 
    
         
            +
            #
         
     | 
| 
      
 8 
     | 
    
         
            +
            # The encoder assumes that we already have a Single-Precision byte
         
     | 
| 
      
 9 
     | 
    
         
            +
            # string (e.g., from pack("g")), and this is taken apart and
         
     | 
| 
      
 10 
     | 
    
         
            +
            # reassembled.
         
     | 
| 
      
 11 
     | 
    
         
            +
            # The decoder is free-standing (trivial).
         
     | 
| 
      
 12 
     | 
    
         
            +
            #
         
     | 
| 
      
 13 
     | 
    
         
            +
            # IEEE 754 can be found at:
         
     | 
| 
      
 14 
     | 
    
         
            +
            # http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4610935
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            module Half
         
     | 
| 
      
 17 
     | 
    
         
            +
              NAN_BYTES = "\x7e\x00"
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              def self.decode_from_bytes(hs)
         
     | 
| 
      
 20 
     | 
    
         
            +
                b16, = hs.unpack("n")
         
     | 
| 
      
 21 
     | 
    
         
            +
                self.decode(b16)
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
              def self.decode(b16)
         
     | 
| 
      
 24 
     | 
    
         
            +
                exp = b16 >> 10 & 0x1f
         
     | 
| 
      
 25 
     | 
    
         
            +
                mant = b16 & 0x3ff
         
     | 
| 
      
 26 
     | 
    
         
            +
                val =
         
     | 
| 
      
 27 
     | 
    
         
            +
                  if exp == 0
         
     | 
| 
      
 28 
     | 
    
         
            +
                    Math.ldexp(mant, -24)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  elsif exp == 31
         
     | 
| 
      
 30 
     | 
    
         
            +
                    mant == 0 ? Float::INFINITY : Float::NAN
         
     | 
| 
      
 31 
     | 
    
         
            +
                  else
         
     | 
| 
      
 32 
     | 
    
         
            +
                    Math.ldexp(0x400 + mant, exp-25)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                if b16[15] != 0
         
     | 
| 
      
 35 
     | 
    
         
            +
                  -val
         
     | 
| 
      
 36 
     | 
    
         
            +
                else
         
     | 
| 
      
 37 
     | 
    
         
            +
                  val
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              def self.encode_from_single_bytes(ss)        # single-precision string
         
     | 
| 
      
 42 
     | 
    
         
            +
                b32, = ss.unpack("N")
         
     | 
| 
      
 43 
     | 
    
         
            +
                s16 = b32 >> 16 & 0x8000
         
     | 
| 
      
 44 
     | 
    
         
            +
                mant = b32 & 0x7fffff
         
     | 
| 
      
 45 
     | 
    
         
            +
                exp = b32 >> 23 & 0xff
         
     | 
| 
      
 46 
     | 
    
         
            +
                # puts "#{fv} #{s16} #{mant.to_s(16)} #{exp}"
         
     | 
| 
      
 47 
     | 
    
         
            +
                if exp == 0
         
     | 
| 
      
 48 
     | 
    
         
            +
                  s16 if mant == 0            # 0.0, -0.0
         
     | 
| 
      
 49 
     | 
    
         
            +
                elsif exp >= 103 && exp < 113 # denorm, exp16 = 0
         
     | 
| 
      
 50 
     | 
    
         
            +
                  s16 + ((mant + 0x800000) >> (126 - exp))
         
     | 
| 
      
 51 
     | 
    
         
            +
                elsif exp >= 113 && exp <= 142 # normalized
         
     | 
| 
      
 52 
     | 
    
         
            +
                  s16 + ((exp - 112) << 10) + (mant >> 13)
         
     | 
| 
      
 53 
     | 
    
         
            +
                elsif exp == 255              # Inf (handle NaN elsewhere!)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  s16 + 0x7c00 if mant == 0   # +Inf/-Inf
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              def self.encode_from_single(fv, ss)
         
     | 
| 
      
 59 
     | 
    
         
            +
                if e = self.encode_from_single_bytes(ss)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  # p e.to_s(16)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  hs = [e].pack("n")
         
     | 
| 
      
 62 
     | 
    
         
            +
                  hs if self.decode_from_bytes(hs) == fv
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
              def self.encode(fv)
         
     | 
| 
      
 67 
     | 
    
         
            +
                self.encode_from_single(fv, [fv].pack("g"))
         
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
      
 69 
     | 
    
         
            +
              
         
     | 
| 
      
 70 
     | 
    
         
            +
            end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            (-24..15).each do |i|
         
     | 
| 
      
 73 
     | 
    
         
            +
              f = Math.ldexp(1, i)
         
     | 
| 
      
 74 
     | 
    
         
            +
              s = Half.encode(f)
         
     | 
| 
      
 75 
     | 
    
         
            +
              fail i unless s
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
      
 77 
     | 
    
         
            +
            (-24..6).each do |i|
         
     | 
| 
      
 78 
     | 
    
         
            +
              f = Math.ldexp(1023, i)
         
     | 
| 
      
 79 
     | 
    
         
            +
              s = Half.encode(f)
         
     | 
| 
      
 80 
     | 
    
         
            +
              fail i unless s
         
     | 
| 
      
 81 
     | 
    
         
            +
            end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            # p Half.decode("\x7b\xff") 65504.0
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            [                               # go through Wikipedia samples
         
     | 
| 
      
 86 
     | 
    
         
            +
            0b0_01111_0000000000, 1.0,
         
     | 
| 
      
 87 
     | 
    
         
            +
            0b0_01111_0000000001, 1.0 + Math.ldexp(1, -10), # = 1 + 2−10 = 1.0009765625 (next biggest float after 1)
         
     | 
| 
      
 88 
     | 
    
         
            +
            0b1_10000_0000000000, -2.0,
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
            0b0_11110_1111111111, 65504.0, #  (max half precision)
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
            0b0_00001_0000000000, Math.ldexp(1, -14), # ≈ 6.10352 × 10−5 (minimum positive normal)
         
     | 
| 
      
 93 
     | 
    
         
            +
            0b0_00000_1111111111, Math.ldexp(1, -14) - Math.ldexp(1, -24), # ≈ 6.09756 × 10−5 (maximum subnormal)
         
     | 
| 
      
 94 
     | 
    
         
            +
            0b0_00000_0000000001, Math.ldexp(1, -24), # ≈ 5.96046 × 10−8 (minimum positive subnormal)
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
            0b0_00000_0000000000, 0.0,
         
     | 
| 
      
 97 
     | 
    
         
            +
            0b1_00000_0000000000, -0.0,
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
            0b0_11111_0000000000, 1.0/0.0,
         
     | 
| 
      
 100 
     | 
    
         
            +
            0b1_11111_0000000000, -1.0/0.0,
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
            0b0_01101_0101010101, 0.333251953125 #... ≈ 1/3 
         
     | 
| 
      
 103 
     | 
    
         
            +
            ].each_slice(2) do |hv, expected|
         
     | 
| 
      
 104 
     | 
    
         
            +
              fv = Half.decode(hv)
         
     | 
| 
      
 105 
     | 
    
         
            +
              raise [hv, fv, expected].inspect unless fv == expected
         
     | 
| 
      
 106 
     | 
    
         
            +
            end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
            # NaN cannot be compared, so this one needs to be special-cased:
         
     | 
| 
      
 109 
     | 
    
         
            +
            raise "NaN not detected" unless Half.decode(0b0_11111_1000000000).nan?
         
     | 
| 
      
 110 
     | 
    
         
            +
            raise "-NaN not detected" unless Half.decode(0b1_11111_1000000000).nan?
         
     | 
| 
      
 111 
     | 
    
         
            +
            raise "NaN not detected" unless Half.decode_from_bytes(Half::NAN_BYTES).nan?
         
     |