module FDB::Tuple
def self.encode(v, nested=false)
def self.encode(v, nested=false) if v.nil? if nested "\x00\xFF" else @@NULL_CODE.chr end elsif v.kind_of? String if v.encoding == Encoding::BINARY || v.encoding == Encoding::ASCII @@BYTES_CODE.chr + v.gsub("\x00", "\x00\xFF") + 0.chr elsif v.encoding == Encoding::UTF_8 @@STRING_CODE.chr + v.dup.force_encoding("BINARY").gsub("\x00", "\x00\xFF") + 0.chr else raise ArgumentError, "unsupported encoding #{v.encoding.name}" end elsif v.kind_of? Integer raise RangeError, "Integer magnitude is too large (more than 255 bytes)" if v < -2**2040+1 || v > 2**2040-1 if v == 0 @@INT_ZERO_CODE.chr elsif v > 0 if v > @@size_limits[-1] length = (v.bit_length + 7) / 8 result = @@POS_INT_END.chr + length.chr length.times do |i| result << ((v >> (8 * (length-i-1))) & 0xff) end result else n = bisect_left( @@size_limits, v ) (@@INT_ZERO_CODE+n).chr + [v].pack("Q>").slice(8-n, n) end else if -v > @@size_limits[-1] length = ((-v).bit_length + 7) / 8 v += (1 << (length * 8)) - 1 result = @@NEG_INT_START.chr + (length ^ 0xff).chr length.times do |i| result << ((v >> (8 * (length-i-1))) & 0xff) end result else n = bisect_left( @@size_limits, -v ) (@@INT_ZERO_CODE-n).chr + [@@size_limits[n]+v].pack("Q>").slice(8-n, n) end end elsif v.kind_of? TrueClass @@TRUE_CODE.chr elsif v.kind_of? FalseClass @@FALSE_CODE.chr elsif v.kind_of? SingleFloat @@FLOAT_CODE.chr + float_adjust([v.value].pack("g"), 0, 4, true) elsif v.kind_of? Float @@DOUBLE_CODE.chr + float_adjust([v].pack("G"), 0, 8, true) elsif v.kind_of? UUID @@UUID_CODE.chr + v.data elsif v.kind_of? Array @@NESTED_CODE.chr + (v.map { |el| encode(el, true).force_encoding("BINARY") }).join + 0.chr else raise ArgumentError, "unsupported type #{v.class}" end end