package lbp import "base:intrinsics" import "core:io" import "core:mem" import "core:strings" Error :: union #shared_nil { io.Error, mem.Allocator_Error, } Coder :: struct { stream: io.Stream, version: i32, allocator: mem.Allocator, write: bool, } init_read :: proc(reader: io.Reader, allocator: mem.Allocator) -> (coder: Coder, err: Error) { _, ok := io.to_reader(reader) assert(ok, "init_read expected a reader") coder = Coder { stream = reader, allocator = allocator, write = false, } err = serialize_number(&coder, &coder.version) return coder, err } init_write :: proc(writer: io.Writer, version: i32) -> (coder: Coder, err: Error) { _, ok := io.to_writer(writer) assert(ok, "init_write expected a writer") coder = Coder { stream = writer, allocator = mem.panic_allocator(), write = true, version = version, } return coder, nil } serialize_bytes :: proc(e: ^Coder, val: []byte) -> io.Error { if e.write { _, err := io.write(e.stream, val) return err } else { _, err := io.read(e.stream, val) return err } } serialize_number :: proc( c: ^Coder, val: ^$T, ) -> Error where intrinsics.type_is_integer(T) || intrinsics.type_is_float(T) { num_bytes := size_of(val) return serialize_bytes(c, mem.byte_slice(rawptr(val), size_of(T))) } serialize_vector :: proc( c: ^Coder, val: $T/^[$C]$V, ) -> Error where intrinsics.type_is_integer(V) || intrinsics.type_is_float(T) { for i in 0 ..< len(val) { serialize_number(c, &val[i]) } } serialize_string :: proc(c: ^Coder, val: ^string) -> Error { if c.write { bytes := transmute([]byte)(val^) length := i32(len(bytes)) serialize_number(c, &length) or_return serialize_bytes(c, bytes) or_return } else { length: i32 serialize_number(c, &length) or_return bytes := make([]byte, length, c.allocator) or_return serialize_bytes(c, bytes) or_return val^ = string(bytes) } return nil }