# encoding: utf-8 # Copyright 2016 Aerospike, Inc. # # Portions may be licensed to Aerospike, Inc. under one or more contributor # license agreements. # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at http:#www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. require 'msgpack' require 'aerospike/utils/pool' module Aerospike private class Unpacker @@pool = Pool.new @@pool.create_block = Proc.new { Unpacker.new } def self.use unpacker = @@pool.poll unpacker.reset yield unpacker ensure @@pool.offer(unpacker) end MsgPackExt = Struct.new(:type, :data) MsgPackExt::TYPES = [ # Map Create Flags: 0x00, # UNORDERED 0x01, # K_ORDERED 0x03, # KV_ORDERED 0x08, # PRESERVE_ORDER ] def initialize @unpacker = MessagePack::Unpacker.new MsgPackExt::TYPES.each do |type| @unpacker.register_type(type) { |data| MsgPackExt.new(type, data) } end end def unpack(bytes) obj = @unpacker.feed(bytes).read case obj when Array then unpack_list(obj) when Hash then unpack_map(obj) else obj end end def reset @unpacker.reset end private def unpack_list(array) normalize_strings_in_array(array) end def unpack_map(hash) hash = normalize_strings_in_map(hash) if hash.any? (key, _) = hash.first hash.shift if MsgPackExt === key end hash end def normalize_elem(elem) case elem when String elem[1..-1].encode(Aerospike.encoding) when Array normalize_strings_in_array(elem) when Hash normalize_strings_in_map(elem) else elem end end def normalize_strings_in_array(arr) arr.map! { |elem| normalize_elem(elem) } end def normalize_strings_in_map(hash) hash.inject({}) do |h, (k,v)| h.update({ normalize_elem(k) => normalize_elem(v) }) end end end end