Module: Rencoder::Encoder

Included in:
Coder
Defined in:
lib/rencoder/encoder.rb

Defined Under Namespace

Classes: EncodingError

Instance Method Summary collapse

Instance Method Details

#encode(object) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/rencoder/encoder.rb', line 5

def encode(object)
  case object
  when String, Symbol then encode_string(object)
  when Fixnum then encode_integer(object)
  when Float then encode_float(object)
  when TrueClass, FalseClass then encode_boolean(object)
  when NilClass then encode_nil(object)
  when Array then encode_array(object)
  when Hash then encode_hash(object)
  else
    raise EncodingError, "Unable to serialize '#{object.class}'"
  end
end

#encode_array(object) ⇒ Object



72
73
74
75
76
77
78
79
80
# File 'lib/rencoder/encoder.rb', line 72

def encode_array(object)
  array_data = object.map { |item| encode(item) }.join

  if object.size < LIST_FIXED_COUNT
    (LIST_FIXED_START + object.size).chr + array_data
  else
    CHR_LIST.chr + array_data + CHR_TERM.chr
  end
end

#encode_boolean(object) ⇒ Object



68
69
70
# File 'lib/rencoder/encoder.rb', line 68

def encode_boolean(object)
  [object ? CHR_TRUE : CHR_FALSE].pack('C')
end

#encode_float(object) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rencoder/encoder.rb', line 44

def encode_float(object)
  # Always serialize floats as 64-bit, since single-precision serialization is a poo
  # If you don't believe me try this:
  #
  # [1.1].pack('F').unpack('F').first
  # => 1.100000023841858
  #
  if options[:float32] # not recommended
    [CHR_FLOAT32, object].pack('Cg')
  else
    [CHR_FLOAT64, object].pack('CG')
  end
end

#encode_hash(object) ⇒ Object



82
83
84
85
86
87
88
89
90
# File 'lib/rencoder/encoder.rb', line 82

def encode_hash(object)
  hash_data = object.map { |key, value| encode(key) + encode(value) }.join

  if object.size < DICT_FIXED_COUNT
    (DICT_FIXED_START + object.size).chr + hash_data
  else
    CHR_DICT.chr + hash_data + CHR_TERM.chr
  end
end

#encode_integer(object) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/rencoder/encoder.rb', line 19

def encode_integer(object)
  case object
  when (0...INT_POS_FIXED_COUNT) # predefined positive intger
    [INT_POS_FIXED_START + object].pack('C')
  when (-INT_NEG_FIXED_COUNT...0) # predefined negative integer
    [INT_NEG_FIXED_START-1-object].pack('C')
  when (-128...128)
    [CHR_INT1, object].pack('Cc') # 8-bit signed
  when (-32768...32768)
    [CHR_INT2, object].pack('Cs>') # 16-bit signed
  when (-2147483648...2147483648)
    [CHR_INT4, object].pack('Cl>') # 32-bit signed
  when (-9223372036854775808...9223372036854775808)
    [CHR_INT8, object].pack('Cq>') # 64-bit signed
  else # encode as ASCII
    bytes = object.to_s.bytes

    if bytes.size >= MAX_INT_LENGTH
      raise EncodingError, "Unable to serialize Fixnum #{object} due to overflow"
    end

    [CHR_INT, *bytes, CHR_TERM].pack('C*')
  end
end

#encode_nil(object) ⇒ Object



92
93
94
# File 'lib/rencoder/encoder.rb', line 92

def encode_nil(object)
  [CHR_NONE].pack('C')
end

#encode_string(object) ⇒ Object



58
59
60
61
62
63
64
65
66
# File 'lib/rencoder/encoder.rb', line 58

def encode_string(object)
  bytes = object.to_s

  if bytes.size < STR_FIXED_COUNT
    (STR_FIXED_START + bytes.size).chr + bytes
  else
    "#{bytes.bytesize.to_s}:#{bytes}"
  end
end