class MessagePack::Factory

def dump(v, *rest)

def dump(v, *rest)
  packer = packer(*rest)
  packer.write(v)
  packer.full_pack
end

def load(src, param = nil)

def load(src, param = nil)
  unpacker = nil
  if src.is_a? String
    unpacker = unpacker(param)
    unpacker.feed(src)
  else
    unpacker = unpacker(src, param)
  end
  unpacker.full_unpack
end

def pool(size = 1, **options)

def pool(size = 1, **options)
  Pool.new(
    frozen? ? self : dup.freeze,
    size,
    options.empty? ? nil : options,
  )
end

def register_type(type, klass, options = { packer: :to_msgpack_ext, unpacker: :from_msgpack_ext })

def register_type(type, klass, options = { packer: :to_msgpack_ext, unpacker: :from_msgpack_ext })
  raise FrozenError, "can't modify frozen MessagePack::Factory" if frozen?
  if options
    options = options.dup
    case packer = options[:packer]
    when nil, Proc
      # all good
    when String, Symbol
      options[:packer] = packer.to_sym.to_proc
    when Method
      options[:packer] = packer.to_proc
    when packer.respond_to?(:call)
      options[:packer] = packer.method(:call).to_proc
    else
      raise ::TypeError, "expected :packer argument to be a callable object, got: #{packer.inspect}"
    end
    case unpacker = options[:unpacker]
    when nil, Proc
      # all good
    when String, Symbol
      options[:unpacker] = klass.method(unpacker).to_proc
    when Method
      options[:unpacker] = unpacker.to_proc
    when packer.respond_to?(:call)
      options[:unpacker] = unpacker.method(:call).to_proc
    else
      raise ::TypeError, "expected :unpacker argument to be a callable object, got: #{unpacker.inspect}"
    end
  end
  register_type_internal(type, klass, options)
end

def registered_types(selector=:both)

[ {type: id, class: Class(or nil), packer: arg, unpacker: arg}, ... ]
def registered_types(selector=:both)
  packer, unpacker = registered_types_internal
  # packer: Class -> [tid, proc, _flags]
  # unpacker: tid -> [klass, proc, _flags]
  list = []
  case selector
  when :both
    packer.each_pair do |klass, ary|
      type = ary[0]
      packer_proc = ary[1]
      unpacker_proc = nil
      if unpacker.has_key?(type)
        unpacker_proc = unpacker.delete(type)[1]
      end
      list << {type: type, class: klass, packer: packer_proc, unpacker: unpacker_proc}
    end
    # unpacker definition only
    unpacker.each_pair do |type, ary|
      list << {type: type, class: ary[0], packer: nil, unpacker: ary[1]}
    end
  when :packer
    packer.each_pair do |klass, ary|
      if ary[1]
        list << {type: ary[0], class: klass, packer: ary[1]}
      end
    end
  when :unpacker
    unpacker.each_pair do |type, ary|
      if ary[1]
        list << {type: type, class: ary[0], unpacker: ary[1]}
      end
    end
  else
    raise ArgumentError, "invalid selector #{selector}"
  end
  list.sort{|a, b| a[:type] <=> b[:type] }
end

def type_registered?(klass_or_type, selector=:both)

def type_registered?(klass_or_type, selector=:both)
  case klass_or_type
  when Class
    klass = klass_or_type
    registered_types(selector).any?{|entry| klass <= entry[:class] }
  when Integer
    type = klass_or_type
    registered_types(selector).any?{|entry| type == entry[:type] }
  else
    raise ArgumentError, "class or type id"
  end
end