class MemoryIO::Types::Type

The base class, all descendants of this class would be consider as a valid 'type'.

Constants

SIZE_T

The size of size_t. i.e. +sizeof(size_t)+.

Public Class Methods

find(symbol) click to toggle source

@api private

Find the subclass of {Type} by symbol.

@param [Symbol] symbol

Symbol that has been registered in {.register}.

@return [{Symbol => Object}]

The object that registered in {.register}.

@see .register

# File lib/memory_io/types/type.rb, line 90
def find(symbol)
  @map[symbol]
end
keep_pos(stream, pos: nil) { |stream| ... } click to toggle source

Yield a block and resume the position of stream.

@param [#pos, pos=] stream

Stream.

@param [Integer] pos

Move +stream+'s position to +pos+ before invoke the block.

@yieldparam [#pos, pos=] stream

Same as parameter +stream+.

@yieldreturn [Object]

The returned object will be returned by this method.

@return [Object]

Returns the object returned by block.

@example

s = StringIO.new('1234')
Type.keep_pos(s, pos: 2) { |s| s.read(2) }
#=> '34'
s.pos
#=> 0
# File lib/memory_io/types/type.rb, line 71
def keep_pos(stream, pos: nil)
  org = stream.pos
  stream.pos = pos if pos
  ret = yield stream
  stream.pos = org
  ret
end
read(_stream) click to toggle source

@abstract

# File lib/memory_io/types/type.rb, line 142
def read(_stream) raise NotImplementedError
end
read_size_t(stream) click to toggle source

Read {Type::SIZE_T} bytes and cast to a little endian unsigned integer.

@param [#read] stream

Stream to read.

@return [Integer]

Result.

@example

s = StringIO.new("\xEF\xBE\xAD\xDExV4\x00")
Type.read_size_t(s).to_s(16)
#=> '345678deadbeef'
# File lib/memory_io/types/type.rb, line 28
def read_size_t(stream)
  MemoryIO::Util.unpack(stream.read(SIZE_T))
end
register(object, option = {}) click to toggle source

Register a new type.

@param [#read, write] object

Normally, +object+ is a descendant class of {Type}.

@option [Symbol, Array<Symbol>] alias

Custom symbol name(s) that can be used in {.find}.

@option [String] doc

Doc string that will be shown in README.md.

@return [Array<Symbol>]

Array of symbols that can be used for finding the registered object.

@example

Type.register(MemoryIO::Types::Clang::CStr, alias: :meow)
#=> [:'clang/c_str', :c_str, :meow]

Type.register(ModuleOne::CStr, alias: :my_class)
#=> [:'module_one/c_str', :my_class]

Type.register(AnotherClass, alias: :my_class)
# An error will be raised because the 'alias' has been registered.

Type.register(AnotherClass, alias: [:my_class, my_class2])
#=> [:another_class, :my_class2]

@note

If all symbols in +alias+ have been registered, an ArgumentError will be raised.
However, if at least one of aliases hasn't been used, registration will success.

@see .find

# File lib/memory_io/types/type.rb, line 125
        def register(object, option = {})
          @map ||= OpenStruct.new
          aliases = Array(option[:alias])
          reg_fail = ArgumentError.new(<<-EOS.strip)
Register '#{object.inspect}' fails because another object with same name has been registered.
Specify an alias such as `register(MyClass, alias: :custom_alias_name)`.
          EOS
          raise reg_fail if aliases.any? && aliases.all? { |ali| @map[ali] }

          keys = get_keys(object).concat(aliases).uniq.reject { |k| @map[k] }
          raise reg_fail if keys.empty?

          rec = MemoryIO::Types::Record.new(object, keys, option)
          keys.each { |k| @map[k] = rec }
        end
write(_stream, _obj) click to toggle source

@abstract

# File lib/memory_io/types/type.rb, line 146
def write(_stream, _obj) raise NotImplementedError
end
write_size_t(stream, val) click to toggle source

Pack val into {Type::SIZE_T} bytes and write to stream.

@param [#write] stream

Stream to write.

@param [Integer] val

Value to be written.

@return [void]

@example

s = StringIO.new
Type.write_size_t(s, 0x123)
s.string
#=> "\x23\x01\x00\x00\x00\x00\x00\x00"
# File lib/memory_io/types/type.rb, line 46
def write_size_t(stream, val)
  stream.write(MemoryIO::Util.pack(val, SIZE_T))
end

Private Class Methods

get_keys(klass) click to toggle source

@param [Class] klass

@return [Array<Symbol>]

# File lib/memory_io/types/type.rb, line 161
def get_keys(klass)
  return [] unless klass.instance_of?(Class)

  snake = MemoryIO::Util.underscore(klass.name)
  snake.gsub!(%r[^memory_io/types/], '')
  ret = [snake]
  ret << ::File.basename(snake)
  ret.map(&:to_sym).uniq
end
inherited(klass) click to toggle source

@api private

To record descendants.

# File lib/memory_io/types/type.rb, line 154
def inherited(klass)
  register(klass, caller: caller_locations(1, 1).first)
end