class Mingle::BinCodec::MingleBinCodec

Constants

BYTE_ORDER

Public Class Methods

new() click to toggle source
# File lib/mingle/bincodec.rb, line 37
def initialize
    @conv = Io::BinaryConverter.new( :order => BYTE_ORDER )
end

Public Instance Methods

as_buffer( obj ) click to toggle source
# File lib/mingle/bincodec.rb, line 201
def as_buffer( obj )
    
    not_nil( obj, :obj )
    obj.is_a?( MingleStruct ) or codec_raise( "Not a struct: #{obj}" )

    buf = RubyVersions.when_19x( StringIO.new ) do |io|
        io.set_encoding( "binary" )
    end

    wr = Io::BinaryWriter.new( :order => BYTE_ORDER, :io => buf )

    append_struct( wr, obj )

    buf.string
end
from_buffer( buf ) click to toggle source
# File lib/mingle/bincodec.rb, line 427
def from_buffer( buf )
 
    validate_from_buffer_args( buf )

    scanner = Io::BinaryReader.new( 
        :order => BYTE_ORDER, :io => StringIO.new( buf ) )

    if ( res = read_value( scanner ) ).is_a?( MingleStruct )
        res
    else
        raise "Decode res wasn't a struct; got #{res.class}" 
    end
end

Private Instance Methods

append_boolean( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 62
def append_boolean( wr, val )

    append_type_code( wr, TYPE_CODE_BOOLEAN )
    wr.write_bool( val.to_bool )
end
append_buffer( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 113
def append_buffer( wr, val )
    
    append_type_code( wr, TYPE_CODE_BUFFER )
    append_sized_buffer( wr, val.buf )
end
append_enum( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 120
def append_enum( wr, val )

    append_type_code( wr, TYPE_CODE_ENUM )
    append_type_reference( wr, val.type )
    append_identifier( wr, val.value )
end
append_fields( wr, flds ) click to toggle source
# File lib/mingle/bincodec.rb, line 177
def append_fields( wr, flds )
    
    flds.each_pair do |fld, val|
        
        unless val.is_a?( MingleNull )
            append_type_code( wr, TYPE_CODE_FIELD )
            append_identifier( wr, fld )
            append_value( wr, val )
        end
    end

    append_type_code( wr, TYPE_CODE_END )
end
append_float32( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 108
def append_float32( wr, val )
    append_num( wr, val, TYPE_CODE_FLOAT32, :write_float32 )
end
append_float64( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 103
def append_float64( wr, val )
    append_num( wr, val, TYPE_CODE_FLOAT64, :write_float64 )
end
append_identifier( wr, id ) click to toggle source
# File lib/mingle/bincodec.rb, line 57
def append_identifier( wr, id )
    BinWriter.as_bin_writer( wr ).write_identifier( id )
end
append_int32( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 88
def append_int32( wr, val )
    append_num( wr, val, TYPE_CODE_INT32, :write_int32 )
end
append_int64( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 83
def append_int64( wr, val )
    append_num( wr, val, TYPE_CODE_INT64, :write_int64 )
end
append_list( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 143
def append_list( wr, val )
    
    append_type_code( wr, TYPE_CODE_LIST )
    wr.write_int32( -1 )
    val.each { |elt| append_value( wr, elt ) }
    append_type_code( wr, TYPE_CODE_END )
end
append_num( wr, mg_num, type_code, enc_meth ) click to toggle source
# File lib/mingle/bincodec.rb, line 76
def append_num( wr, mg_num, type_code, enc_meth )
 
    append_type_code( wr, type_code )
    wr.send( enc_meth, mg_num.num )
end
append_sized_buffer( wr, buf ) click to toggle source
# File lib/mingle/bincodec.rb, line 47
def append_sized_buffer( wr, buf )
    wr.write_buffer32( buf )
end
append_string( wr, str ) click to toggle source
# File lib/mingle/bincodec.rb, line 69
def append_string( wr, str )
    
    append_type_code( wr, TYPE_CODE_STRING )
    wr.write_utf8( str.to_s )
end
append_struct( wr, ms ) click to toggle source
# File lib/mingle/bincodec.rb, line 192
def append_struct( wr, ms )
    
    append_type_code( wr, TYPE_CODE_STRUCT )
    wr.write_int32( -1 )
    append_type_reference( wr, ms.type )
    append_fields( wr, ms.fields )
end
append_symbol_map( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 136
def append_symbol_map( wr, val )
    
    append_type_code( wr, TYPE_CODE_SYMBOL_MAP )
    append_fields( wr, val )
end
append_timestamp( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 128
def append_timestamp( wr, val )
    
    append_type_code( wr, TYPE_CODE_TIMESTAMP )
    wr.write_int64( val.time.to_i )
    wr.write_int32( val.time.nsec )
end
append_type_code( wr, code ) click to toggle source
# File lib/mingle/bincodec.rb, line 42
def append_type_code( wr, code )
    wr.write_int8( code )
end
append_type_reference( wr, typ ) click to toggle source
# File lib/mingle/bincodec.rb, line 52
def append_type_reference( wr, typ )
    BinWriter.as_bin_writer( wr ).write_type_reference( typ )
end
append_uint32( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 93
def append_uint32( wr, val )
    append_num( wr, val, TYPE_CODE_UINT32, :write_uint32 )
end
append_uint64( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 98
def append_uint64( wr, val )
    append_num( wr, val, TYPE_CODE_UINT64, :write_uint64 )
end
append_value( wr, val ) click to toggle source
# File lib/mingle/bincodec.rb, line 152
def append_value( wr, val )
    
    case val

        when MingleBoolean then append_boolean( wr, val )
        when MingleString then append_string( wr, val )
        when MingleInt32 then append_int32( wr, val )
        when MingleInt64 then append_int64( wr, val )
        when MingleUint32 then append_uint32( wr, val )
        when MingleUint64 then append_uint64( wr, val )
        when MingleFloat32 then append_float32( wr, val )
        when MingleFloat64 then append_float64( wr, val )
        when MingleBuffer then append_buffer( wr, val )
        when MingleEnum then append_enum( wr, val )
        when MingleTimestamp then append_timestamp( wr, val )
        when MingleStruct then append_struct( wr, val )
        when MingleSymbolMap then append_symbol_map( wr, val )
        when MingleList then append_list( wr, val )
        when MingleNull then append_type_code( wr, TYPE_CODE_NULL )

        else raise "Unhandled value type: #{val.class}"
    end
end
cur_pos( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 230
def cur_pos( scanner )
    scanner.pos
end
decode_raise( pos_obj, msg ) click to toggle source
# File lib/mingle/bincodec.rb, line 235
def decode_raise( pos_obj, msg )
    
    off = case pos_obj
        when Fixnum then pos_obj
        when Io::BinaryReader then last_pos( pos_obj )
        else raise "Unexpected pos_obj of type #{pos_obj.class}"
    end

    codec_raise( "[offset #{off}]: #{msg}" )
end
expect_type_code( scanner, code_sym ) click to toggle source
# File lib/mingle/bincodec.rb, line 257
def expect_type_code( scanner, code_sym )

    code_val = Mingle::BinCodec.const_get( code_sym )
    
    if ( b = scanner.read_int8 ) == code_val
        code_val
    else
        type_code_expect_raise( code_sym, b, last_pos( scanner ) )
    end
end
expect_type_code_end( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 269
def expect_type_code_end( scanner )
    expect_type_code( scanner, :TYPE_CODE_END )
end
last_pos( scanner ) click to toggle source

Useful when reporting errors; returns the index just before pos, which was presumably related to the error

# File lib/mingle/bincodec.rb, line 225
def last_pos( scanner )
    scanner.pos - 1
end
raise_unrecognized_value_code( tc, pos ) click to toggle source
# File lib/mingle/bincodec.rb, line 247
def raise_unrecognized_value_code( tc, pos )
    decode_raise( pos, sprintf( "Unrecognized value code: 0x%02x", tc ) )
end
read_field( scanner, flds ) click to toggle source
# File lib/mingle/bincodec.rb, line 284
def read_field( scanner, flds )
 
    id = read_identifier( scanner )
    fld = read_value( scanner )

    flds[ id ] = fld
end
read_fields( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 293
def read_fields( scanner )

    flds = {}

    while ( tc = scanner.read_int8 ) != TYPE_CODE_END
        if tc == TYPE_CODE_FIELD
            read_field( scanner, flds )
        else
            type_code_expect_raise( 
                :TYPE_CODE_FIELD, tc, cur_pos( scanner ) )
        end
    end

    MingleSymbolMap.create( flds )
end
read_identifier( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 279
def read_identifier( scanner )
    return BinReader.as_bin_reader( scanner ).read_identifier
end
read_mg_boolean( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 310
def read_mg_boolean( scanner )
    
    case b = scanner.read_int8
        when 0x00 then MingleBoolean::FALSE
        when 0x01 then MingleBoolean::TRUE
        else raise "Unexpected bool val: #{to_hex_byte( b )}"
    end
end
read_mg_buffer( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 352
def read_mg_buffer( scanner )
    MingleBuffer.new( scanner.read_buffer32 )
end
read_mg_enum( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 357
def read_mg_enum( scanner )
    
    typ = read_type_reference( scanner )
    value = read_identifier( scanner )

    MingleEnum.new( :type => typ, :value => value )
end
read_mg_list( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 375
def read_mg_list( scanner )
    
    res = []
    len = scanner.read_int32 # ignored for now

    while ( tc = scanner.read_int8 ) != TYPE_CODE_END
        res << read_value( scanner, tc )
    end

    MingleList.new( res )
end
read_mg_string( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 320
def read_mg_string( scanner )
    MingleString.new( scanner.read_utf8 )
end
read_mg_struct( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 325
def read_mg_struct( scanner )
 
    sz = scanner.read_int32
    typ = read_type_reference( scanner )
    flds = read_fields( scanner )

    MingleStruct.new( :type => typ, :fields => flds )
end
read_mg_timestamp( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 366
def read_mg_timestamp( scanner )
    
    secs, nsec = scanner.read_int64, scanner.read_int32
    t = Time.at( secs, nsec.to_f / 1000.0 )

    MingleTimestamp.new( t, false )
end
read_type_reference( scanner ) click to toggle source
# File lib/mingle/bincodec.rb, line 274
def read_type_reference( scanner )
    return BinReader.as_bin_reader( scanner ).read_type_reference
end
read_value( scanner, typ = scanner.read_int8 ) click to toggle source
# File lib/mingle/bincodec.rb, line 388
def read_value( scanner, typ = scanner.read_int8 )
    
    case typ 

        when TYPE_CODE_BOOLEAN then read_mg_boolean( scanner )
        when TYPE_CODE_INT64 then read_mg_int64( scanner )
        when TYPE_CODE_INT32 then read_mg_int32( scanner )
        when TYPE_CODE_UINT32 then read_mg_uint32( scanner )
        when TYPE_CODE_UINT64 then read_mg_uint64( scanner )
        when TYPE_CODE_FLOAT64 then read_mg_float64( scanner )
        when TYPE_CODE_FLOAT32 then read_mg_float32( scanner )
        when TYPE_CODE_STRING then read_mg_string( scanner )
        when TYPE_CODE_BUFFER then read_mg_buffer( scanner )
        when TYPE_CODE_ENUM then read_mg_enum( scanner )
        when TYPE_CODE_TIMESTAMP then read_mg_timestamp( scanner )
        when TYPE_CODE_STRUCT then read_mg_struct( scanner )
        when TYPE_CODE_SYMBOL_MAP then read_fields( scanner )
        when TYPE_CODE_LIST then read_mg_list( scanner )
        when TYPE_CODE_NULL then MingleNull::INSTANCE
        else raise_unrecognized_value_code( typ, scanner )
    end
end
to_hex_byte( i ) click to toggle source
# File lib/mingle/bincodec.rb, line 218
def to_hex_byte( i )
    sprintf( "0x%02x", i % 256 )
end
type_code_expect_raise( code_sym, code_act, pos ) click to toggle source
# File lib/mingle/bincodec.rb, line 252
def type_code_expect_raise( code_sym, code_act, pos )
    raise_unrecognized_value_code( code_act, pos )
end
validate_from_buffer_args( buf ) click to toggle source
# File lib/mingle/bincodec.rb, line 412
def validate_from_buffer_args( buf )

    not_nil( buf, :buf )

    RubyVersions.when_19x do 
        buf.encoding == Encoding::BINARY or 
            codec_raise( "Buffer encoding is not binary" )
    end

    unless ( tc = @conv.read_int8( buf[ 0, 1 ] ) ) == TYPE_CODE_STRUCT 
        raise_unrecognized_value_code( tc, 0 )
    end
end