0 branches
Tree Top files
Code
Clone with HTTPS:
56 years ago
..
README.md all: fix more tests last Apr 28 3.01 KB
stream.v all: super_batch3 fixes last Apr 13 7.88 KB

Description

encoding.binary contains utility functions for converting between an array of bytes ([]u8) and unsigned integers of various widths (u16, u32, and u64).

Also, it provide functions encode_binary[T]() and decode_binary[T]() which can converting between an array of bytes ([]u8) and generic type T.

There are two ways in which bytes can be encoded:

  1. Little endian: The least significant bytes are stored first, followed by the most significant bytes.
  2. Big endian: The most significant bytes are stored first, opposite to the little endian convention.For example, let us take the number 0x12345678. In little endian, the bytes are extracted as 0x78, 0x56, 0x34, and 0x12. In big endian, the bytes are 0x12, 0x34, 0x56, and 0x78.We follow a similar procedure when we want to go the other way around. Consider the second sequence of bytes in the previous example: 0x12, 0x34, 0x56, and 0x78. If we encode this sequence in little endian format, we get the integer 0x78563412. If we encode this sequence in big endian, we get 0x12345678.
    Note The functions in this module assume appropriately sized u8 arrays. If the sizes are not valid, the functions will panic.
    For generic T data encoding/decoding, you can use encode_binary[T]() and decode_binary[T]():
    module main
    
    import encoding.binary
    
    struct MyStruct {
     g_u8 u8
    }
    
    struct ComplexStruct {
    mut:
     f_u8      u8
     f_u32     u32 @[serialize: '-'] // this field will be skipped
     f_u64     u64
     f_string  string
     f_structs []MyStruct
     f_maps    []map[string]string
    }
    
    fn main() {
     a := ComplexStruct{
         f_u8:      u8(10)
         f_u32:     u32(1024)
         f_u64:     u64(2048)
         f_string:  'serialize me'
         f_structs: [
             MyStruct{
                 g_u8: u8(1)
             },
             MyStruct{
                 g_u8: u8(2)
             },
             MyStruct{
                 g_u8: u8(3)
             },
         ]
         f_maps:    [
             {
                 'abc': 'def'
             },
             {
                 '123': '456'
             },
             {
                 ',./': '!@#'
             },
         ]
     }
    
     b := binary.encode_binary(a)!
     mut c := binary.decode_binary[ComplexStruct](b)!
    
     // because there skipped field in `a`, a != c
     assert a != c
    
     c.f_u32 = u32(1024)
     assert a == c
    }
    
    For Go-style fixed-size stream I/O, you can use read(), write(), and size() with binary.little_endian or binary.big_endian:
    module main
    
    import encoding.binary
    import io
    
    struct Header {
     version u16
     flags   u16
     length  u32
    }
    
    struct Buffer {
    mut:
     data []u8
     pos  int
    }
    
    fn (mut b Buffer) read(mut out []u8) !int {
     if b.pos >= b.data.len {
         return io.Eof{}
     }
     n := if out.len < b.data.len - b.pos { out.len } else { b.data.len - b.pos }
     copy(mut out[..n], b.data[b.pos..b.pos + n])
     b.pos += n
     return n
    }
    
    fn (mut b Buffer) write(src []u8) !int {
     b.data << src
     return src.len
    }
    
    fn main() {
     header := Header{
         version: 1
         flags:   2
         length:  32
     }
     mut buf := Buffer{}
     binary.write(mut buf, binary.big_endian, header)!
     assert binary.size(header) == 8
    
     buf.pos = 0
     mut decoded := Header{}
     binary.read(mut buf, binary.big_endian, mut decoded)!
     assert decoded == header
    }