class Aws::Cbor::Encoder

Pure ruby implementation of CBOR encoder.

Constants

DOUBLE_BYTES
FLOAT_BYTES
MAJOR_TYPE_ARRAY
MAJOR_TYPE_BYTE_STR
MAJOR_TYPE_MAP
MAJOR_TYPE_NEGATIVE_INT
MAJOR_TYPE_SIMPLE
MAJOR_TYPE_STR
MAJOR_TYPE_TAG
MAJOR_TYPE_UNSIGNED_INT
MAX_INTEGER
TAG_BIGNUM_BASE
TAG_TYPE_BIGDEC
TAG_TYPE_EPOCH

www.rfc-editor.org/rfc/rfc8949.html#tags

Public Class Methods

new() click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 9
def initialize
  @buffer = String.new
end

Public Instance Methods

add(value) click to toggle source

generic method for adding generic Ruby data based on its type

# File lib/aws-sdk-core/cbor/encoder.rb, line 19
def add(value)
  case value
  when BigDecimal then add_big_decimal(value)
  when Integer then add_auto_integer(value)
  when Numeric then add_auto_float(value)
  when Symbol then add_string(value.to_s)
  when true, false then add_boolean(value)
  when nil then add_nil
  when Tagged
    add_tag(value.tag)
    add(value.value)
  when String
    if value.encoding == Encoding::BINARY
      add_byte_string(value)
    else
      add_string(value)
    end
  when Array
    start_array(value.size)
    value.each { |di| add(di) }
  when Hash
    start_map(value.size)
    value.each do |k, v|
      add(k)
      add(v)
    end
  when Time
    add_time(value)
  else
    raise UnknownTypeError, value
  end
  self
end
bytes() click to toggle source

@return the encoded bytes in CBOR format for all added data

# File lib/aws-sdk-core/cbor/encoder.rb, line 14
def bytes
  @buffer
end

Private Instance Methods

add_auto_float(value) click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 167
def add_auto_float(value)
  if value.nan?
    @buffer << FLOAT_BYTES << [value].pack('g')
  else
    ss = [value].pack('g') # single-precision
    if ss.unpack1('g') == value
      @buffer << FLOAT_BYTES << ss
    else
      @buffer << [DOUBLE_BYTES, value].pack('CG') # double-precision
    end
  end
end
add_auto_integer(value) click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 140
def add_auto_integer(value)
  major_type =
    if value.negative?
      value = -1 - value
      MAJOR_TYPE_NEGATIVE_INT
    else
      MAJOR_TYPE_UNSIGNED_INT
    end

  if value >= MAX_INTEGER
    s = bignum_to_bytes(value)
    head(MAJOR_TYPE_TAG, TAG_BIGNUM_BASE + (major_type >> 5))
    head(MAJOR_TYPE_BYTE_STR, s.bytesize)
    @buffer << s
  else
    head(major_type, value)
  end
end
add_big_decimal(value) click to toggle source

A decimal fraction or a bigfloat is represented as a tagged array that contains exactly two integer numbers: an exponent e and a mantissa m decimal fractions are always represented with a base of 10 See: www.rfc-editor.org/rfc/rfc8949.html#name-decimal-fractions-and-bigfl

# File lib/aws-sdk-core/cbor/encoder.rb, line 123
def add_big_decimal(value)
  if value.infinite? == 1
    return add_float(value.infinite? * Float::INFINITY)
  elsif value.nan?
    return add_float(Float::NAN)
  end

  head(MAJOR_TYPE_TAG, TAG_TYPE_BIGDEC)
  sign, digits, base, exp = value.split
  # Ruby BigDecimal digits of XXX are used as 0.XXX, convert
  exp = exp - digits.size
  digits = sign * digits.to_i
  start_array(2)
  add_auto_integer(exp)
  add_auto_integer(digits)
end
add_bignum(value) click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 104
def add_bignum(value)
  major_type =
    if value.negative?
      value = -1 - value
      MAJOR_TYPE_NEGATIVE_INT
    else
      MAJOR_TYPE_UNSIGNED_INT
    end
  s = bignum_to_bytes(value)
  head(MAJOR_TYPE_TAG, TAG_BIGNUM_BASE + (major_type >> 5))
  head(MAJOR_TYPE_BYTE_STR, s.bytesize)
  @buffer << s
end
add_boolean(value) click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 184
def add_boolean(value)
  value ? head(MAJOR_TYPE_SIMPLE, 21) : head(MAJOR_TYPE_SIMPLE, 20)
end
add_byte_string(value) click to toggle source

Encoding MUST already be Encoding::BINARY

# File lib/aws-sdk-core/cbor/encoder.rb, line 189
def add_byte_string(value)
  head(MAJOR_TYPE_BYTE_STR, value.bytesize)
  @buffer << value
end
add_double(value) click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 163
def add_double(value)
  @buffer << [DOUBLE_BYTES, value].pack('CG') # double-precision
end
add_float(value) click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 159
def add_float(value)
  @buffer << [FLOAT_BYTES, value].pack('Cg') # single-precision
end
add_integer(value) click to toggle source

streaming style, lower level interface

# File lib/aws-sdk-core/cbor/encoder.rb, line 93
def add_integer(value)
  major_type =
    if value.negative?
      value = -1 - value
      MAJOR_TYPE_NEGATIVE_INT
    else
      MAJOR_TYPE_UNSIGNED_INT
    end
  head(major_type, value)
end
add_nil() click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 180
def add_nil
  head(MAJOR_TYPE_SIMPLE, 22)
end
add_string(value) click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 194
def add_string(value)
  value = value.encode(Encoding::UTF_8).force_encoding(Encoding::BINARY)
  head(MAJOR_TYPE_STR, value.bytesize)
  @buffer << value
end
add_tag(tag) click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 223
def add_tag(tag)
  head(MAJOR_TYPE_TAG, tag)
end
add_time(value) click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 227
def add_time(value)
  head(MAJOR_TYPE_TAG, TAG_TYPE_EPOCH)
  epoch_ms = (value.to_f * 1000).to_i
  add_integer(epoch_ms)
end
bignum_to_bytes(value) click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 233
def bignum_to_bytes(value)
  s = String.new
  while value != 0
    s << (value & 0xFF)
    value >>= 8
  end
  s.reverse!
end
end_indefinite_collection() click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 218
def end_indefinite_collection
  # write the stop sequence
  head(MAJOR_TYPE_SIMPLE + 31, 0)
end
head(major_type, value) click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 74
def head(major_type, value)
  @buffer <<
    case value
    when 0...24
      [major_type + value].pack('C') # 8-bit unsigned
    when 0...256
      [major_type + 24, value].pack('CC')
    when 0...65_536
      [major_type + 25, value].pack('Cn')
    when 0...4_294_967_296
      [major_type + 26, value].pack('CN')
    when 0...MAX_INTEGER
      [major_type + 27, value].pack('CQ>')
    else
      raise Error, "Value is too large to encode: #{value}"
    end
end
start_array(length) click to toggle source

caller is responsible for adding length values

# File lib/aws-sdk-core/cbor/encoder.rb, line 201
def start_array(length)
  head(MAJOR_TYPE_ARRAY, length)
end
start_indefinite_array() click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 205
def start_indefinite_array
  head(MAJOR_TYPE_ARRAY + 31, 0)
end
start_indefinite_map() click to toggle source
# File lib/aws-sdk-core/cbor/encoder.rb, line 214
def start_indefinite_map
  head(MAJOR_TYPE_MAP + 31, 0)
end
start_map(length) click to toggle source

caller is responsible for adding length key/value pairs

# File lib/aws-sdk-core/cbor/encoder.rb, line 210
def start_map(length)
  head(MAJOR_TYPE_MAP, length)
end