Update tests\core\encoding\cbor to use new test runner.

It was leaky and required a substantial number of `loc := #caller_location` additions to parts of the core library to make it easier to track down how and where it leaked.

The tests now run fine multi-threaded.
This commit is contained in:
Jeroen van Rijn
2024-06-02 14:47:07 -04:00
committed by Feoramund
parent 6a1649d8aa
commit a27b167218
11 changed files with 323 additions and 420 deletions
+2 -2
View File
@@ -29,12 +29,12 @@ MIN_READ_BUFFER_SIZE :: 16
@(private) @(private)
DEFAULT_MAX_CONSECUTIVE_EMPTY_READS :: 128 DEFAULT_MAX_CONSECUTIVE_EMPTY_READS :: 128
reader_init :: proc(b: ^Reader, rd: io.Reader, size: int = DEFAULT_BUF_SIZE, allocator := context.allocator) { reader_init :: proc(b: ^Reader, rd: io.Reader, size: int = DEFAULT_BUF_SIZE, allocator := context.allocator, loc := #caller_location) {
size := size size := size
size = max(size, MIN_READ_BUFFER_SIZE) size = max(size, MIN_READ_BUFFER_SIZE)
reader_reset(b, rd) reader_reset(b, rd)
b.buf_allocator = allocator b.buf_allocator = allocator
b.buf = make([]byte, size, allocator) b.buf = make([]byte, size, allocator, loc)
} }
reader_init_with_buf :: proc(b: ^Reader, rd: io.Reader, buf: []byte) { reader_init_with_buf :: proc(b: ^Reader, rd: io.Reader, buf: []byte) {
+35 -35
View File
@@ -27,19 +27,19 @@ Read_Op :: enum i8 {
} }
buffer_init :: proc(b: ^Buffer, buf: []byte) { buffer_init :: proc(b: ^Buffer, buf: []byte, loc := #caller_location) {
resize(&b.buf, len(buf)) resize(&b.buf, len(buf), loc=loc)
copy(b.buf[:], buf) copy(b.buf[:], buf)
} }
buffer_init_string :: proc(b: ^Buffer, s: string) { buffer_init_string :: proc(b: ^Buffer, s: string, loc := #caller_location) {
resize(&b.buf, len(s)) resize(&b.buf, len(s), loc=loc)
copy(b.buf[:], s) copy(b.buf[:], s)
} }
buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) { buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator, loc := #caller_location) {
if b.buf == nil { if b.buf == nil {
b.buf = make([dynamic]byte, len, cap, allocator) b.buf = make([dynamic]byte, len, cap, allocator, loc)
return return
} }
@@ -96,28 +96,28 @@ buffer_truncate :: proc(b: ^Buffer, n: int) {
} }
@(private) @(private)
_buffer_try_grow :: proc(b: ^Buffer, n: int) -> (int, bool) { _buffer_try_grow :: proc(b: ^Buffer, n: int, loc := #caller_location) -> (int, bool) {
if l := len(b.buf); n <= cap(b.buf)-l { if l := len(b.buf); n <= cap(b.buf)-l {
resize(&b.buf, l+n) resize(&b.buf, l+n, loc=loc)
return l, true return l, true
} }
return 0, false return 0, false
} }
@(private) @(private)
_buffer_grow :: proc(b: ^Buffer, n: int) -> int { _buffer_grow :: proc(b: ^Buffer, n: int, loc := #caller_location) -> int {
m := buffer_length(b) m := buffer_length(b)
if m == 0 && b.off != 0 { if m == 0 && b.off != 0 {
buffer_reset(b) buffer_reset(b)
} }
if i, ok := _buffer_try_grow(b, n); ok { if i, ok := _buffer_try_grow(b, n, loc=loc); ok {
return i return i
} }
if b.buf == nil && n <= SMALL_BUFFER_SIZE { if b.buf == nil && n <= SMALL_BUFFER_SIZE {
// Fixes #2756 by preserving allocator if already set on Buffer via init_buffer_allocator // Fixes #2756 by preserving allocator if already set on Buffer via init_buffer_allocator
reserve(&b.buf, SMALL_BUFFER_SIZE) reserve(&b.buf, SMALL_BUFFER_SIZE, loc=loc)
resize(&b.buf, n) resize(&b.buf, n, loc=loc)
return 0 return 0
} }
@@ -127,31 +127,31 @@ _buffer_grow :: proc(b: ^Buffer, n: int) -> int {
} else if c > max(int) - c - n { } else if c > max(int) - c - n {
panic("bytes.Buffer: too large") panic("bytes.Buffer: too large")
} else { } else {
resize(&b.buf, 2*c + n) resize(&b.buf, 2*c + n, loc=loc)
copy(b.buf[:], b.buf[b.off:]) copy(b.buf[:], b.buf[b.off:])
} }
b.off = 0 b.off = 0
resize(&b.buf, m+n) resize(&b.buf, m+n, loc=loc)
return m return m
} }
buffer_grow :: proc(b: ^Buffer, n: int) { buffer_grow :: proc(b: ^Buffer, n: int, loc := #caller_location) {
if n < 0 { if n < 0 {
panic("bytes.buffer_grow: negative count") panic("bytes.buffer_grow: negative count")
} }
m := _buffer_grow(b, n) m := _buffer_grow(b, n, loc=loc)
resize(&b.buf, m) resize(&b.buf, m, loc=loc)
} }
buffer_write_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) { buffer_write_at :: proc(b: ^Buffer, p: []byte, offset: int, loc := #caller_location) -> (n: int, err: io.Error) {
b.last_read = .Invalid b.last_read = .Invalid
if offset < 0 { if offset < 0 {
err = .Invalid_Offset err = .Invalid_Offset
return return
} }
_, ok := _buffer_try_grow(b, offset+len(p)) _, ok := _buffer_try_grow(b, offset+len(p), loc=loc)
if !ok { if !ok {
_ = _buffer_grow(b, offset+len(p)) _ = _buffer_grow(b, offset+len(p), loc=loc)
} }
if len(b.buf) <= offset { if len(b.buf) <= offset {
return 0, .Short_Write return 0, .Short_Write
@@ -160,47 +160,47 @@ buffer_write_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.
} }
buffer_write :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) { buffer_write :: proc(b: ^Buffer, p: []byte, loc := #caller_location) -> (n: int, err: io.Error) {
b.last_read = .Invalid b.last_read = .Invalid
m, ok := _buffer_try_grow(b, len(p)) m, ok := _buffer_try_grow(b, len(p), loc=loc)
if !ok { if !ok {
m = _buffer_grow(b, len(p)) m = _buffer_grow(b, len(p), loc=loc)
} }
return copy(b.buf[m:], p), nil return copy(b.buf[m:], p), nil
} }
buffer_write_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) { buffer_write_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int, loc := #caller_location) -> (n: int, err: io.Error) {
return buffer_write(b, ([^]byte)(ptr)[:size]) return buffer_write(b, ([^]byte)(ptr)[:size], loc=loc)
} }
buffer_write_string :: proc(b: ^Buffer, s: string) -> (n: int, err: io.Error) { buffer_write_string :: proc(b: ^Buffer, s: string, loc := #caller_location) -> (n: int, err: io.Error) {
b.last_read = .Invalid b.last_read = .Invalid
m, ok := _buffer_try_grow(b, len(s)) m, ok := _buffer_try_grow(b, len(s), loc=loc)
if !ok { if !ok {
m = _buffer_grow(b, len(s)) m = _buffer_grow(b, len(s), loc=loc)
} }
return copy(b.buf[m:], s), nil return copy(b.buf[m:], s), nil
} }
buffer_write_byte :: proc(b: ^Buffer, c: byte) -> io.Error { buffer_write_byte :: proc(b: ^Buffer, c: byte, loc := #caller_location) -> io.Error {
b.last_read = .Invalid b.last_read = .Invalid
m, ok := _buffer_try_grow(b, 1) m, ok := _buffer_try_grow(b, 1, loc=loc)
if !ok { if !ok {
m = _buffer_grow(b, 1) m = _buffer_grow(b, 1, loc=loc)
} }
b.buf[m] = c b.buf[m] = c
return nil return nil
} }
buffer_write_rune :: proc(b: ^Buffer, r: rune) -> (n: int, err: io.Error) { buffer_write_rune :: proc(b: ^Buffer, r: rune, loc := #caller_location) -> (n: int, err: io.Error) {
if r < utf8.RUNE_SELF { if r < utf8.RUNE_SELF {
buffer_write_byte(b, byte(r)) buffer_write_byte(b, byte(r), loc=loc)
return 1, nil return 1, nil
} }
b.last_read = .Invalid b.last_read = .Invalid
m, ok := _buffer_try_grow(b, utf8.UTF_MAX) m, ok := _buffer_try_grow(b, utf8.UTF_MAX, loc=loc)
if !ok { if !ok {
m = _buffer_grow(b, utf8.UTF_MAX) m = _buffer_grow(b, utf8.UTF_MAX, loc=loc)
} }
res: [4]byte res: [4]byte
res, n = utf8.encode_rune(r) res, n = utf8.encode_rune(r)
+2 -2
View File
@@ -320,8 +320,8 @@ to_diagnostic_format :: proc {
// Turns the given CBOR value into a human-readable string. // Turns the given CBOR value into a human-readable string.
// See docs on the proc group `diagnose` for more info. // See docs on the proc group `diagnose` for more info.
to_diagnostic_format_string :: proc(val: Value, padding := 0, allocator := context.allocator) -> (string, mem.Allocator_Error) #optional_allocator_error { to_diagnostic_format_string :: proc(val: Value, padding := 0, allocator := context.allocator, loc := #caller_location) -> (string, mem.Allocator_Error) #optional_allocator_error {
b := strings.builder_make(allocator) b := strings.builder_make(allocator, loc)
w := strings.to_stream(&b) w := strings.to_stream(&b)
err := to_diagnostic_format_writer(w, val, padding) err := to_diagnostic_format_writer(w, val, padding)
if err == .EOF { if err == .EOF {
+53 -52
View File
@@ -95,24 +95,25 @@ decode :: decode_from
// Decodes the given string as CBOR. // Decodes the given string as CBOR.
// See docs on the proc group `decode` for more information. // See docs on the proc group `decode` for more information.
decode_from_string :: proc(s: string, flags: Decoder_Flags = {}, allocator := context.allocator) -> (v: Value, err: Decode_Error) { decode_from_string :: proc(s: string, flags: Decoder_Flags = {}, allocator := context.allocator, loc := #caller_location) -> (v: Value, err: Decode_Error) {
r: strings.Reader r: strings.Reader
strings.reader_init(&r, s) strings.reader_init(&r, s)
return decode_from_reader(strings.reader_to_stream(&r), flags, allocator) return decode_from_reader(strings.reader_to_stream(&r), flags, allocator, loc)
} }
// Reads a CBOR value from the given reader. // Reads a CBOR value from the given reader.
// See docs on the proc group `decode` for more information. // See docs on the proc group `decode` for more information.
decode_from_reader :: proc(r: io.Reader, flags: Decoder_Flags = {}, allocator := context.allocator) -> (v: Value, err: Decode_Error) { decode_from_reader :: proc(r: io.Reader, flags: Decoder_Flags = {}, allocator := context.allocator, loc := #caller_location) -> (v: Value, err: Decode_Error) {
return decode_from_decoder( return decode_from_decoder(
Decoder{ DEFAULT_MAX_PRE_ALLOC, flags, r }, Decoder{ DEFAULT_MAX_PRE_ALLOC, flags, r },
allocator=allocator, allocator=allocator,
loc = loc,
) )
} }
// Reads a CBOR value from the given decoder. // Reads a CBOR value from the given decoder.
// See docs on the proc group `decode` for more information. // See docs on the proc group `decode` for more information.
decode_from_decoder :: proc(d: Decoder, allocator := context.allocator) -> (v: Value, err: Decode_Error) { decode_from_decoder :: proc(d: Decoder, allocator := context.allocator, loc := #caller_location) -> (v: Value, err: Decode_Error) {
context.allocator = allocator context.allocator = allocator
d := d d := d
@@ -121,13 +122,13 @@ decode_from_decoder :: proc(d: Decoder, allocator := context.allocator) -> (v: V
d.max_pre_alloc = DEFAULT_MAX_PRE_ALLOC d.max_pre_alloc = DEFAULT_MAX_PRE_ALLOC
} }
v, err = _decode_from_decoder(d) v, err = _decode_from_decoder(d, {}, allocator, loc)
// Normal EOF does not exist here, we try to read the exact amount that is said to be provided. // Normal EOF does not exist here, we try to read the exact amount that is said to be provided.
if err == .EOF { err = .Unexpected_EOF } if err == .EOF { err = .Unexpected_EOF }
return return
} }
_decode_from_decoder :: proc(d: Decoder, hdr: Header = Header(0)) -> (v: Value, err: Decode_Error) { _decode_from_decoder :: proc(d: Decoder, hdr: Header = Header(0), allocator := context.allocator, loc := #caller_location) -> (v: Value, err: Decode_Error) {
hdr := hdr hdr := hdr
r := d.reader r := d.reader
if hdr == Header(0) { hdr = _decode_header(r) or_return } if hdr == Header(0) { hdr = _decode_header(r) or_return }
@@ -161,11 +162,11 @@ _decode_from_decoder :: proc(d: Decoder, hdr: Header = Header(0)) -> (v: Value,
switch maj { switch maj {
case .Unsigned: return _decode_tiny_u8(add) case .Unsigned: return _decode_tiny_u8(add)
case .Negative: return Negative_U8(_decode_tiny_u8(add) or_return), nil case .Negative: return Negative_U8(_decode_tiny_u8(add) or_return), nil
case .Bytes: return _decode_bytes_ptr(d, add) case .Bytes: return _decode_bytes_ptr(d, add, .Bytes, allocator, loc)
case .Text: return _decode_text_ptr(d, add) case .Text: return _decode_text_ptr(d, add, allocator, loc)
case .Array: return _decode_array_ptr(d, add) case .Array: return _decode_array_ptr(d, add, allocator, loc)
case .Map: return _decode_map_ptr(d, add) case .Map: return _decode_map_ptr(d, add, allocator, loc)
case .Tag: return _decode_tag_ptr(d, add) case .Tag: return _decode_tag_ptr(d, add, allocator, loc)
case .Other: return _decode_tiny_simple(add) case .Other: return _decode_tiny_simple(add)
case: return nil, .Bad_Major case: return nil, .Bad_Major
} }
@@ -203,27 +204,27 @@ encode :: encode_into
// Encodes the CBOR value into binary CBOR allocated on the given allocator. // Encodes the CBOR value into binary CBOR allocated on the given allocator.
// See the docs on the proc group `encode_into` for more info. // See the docs on the proc group `encode_into` for more info.
encode_into_bytes :: proc(v: Value, flags := ENCODE_SMALL, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (data: []byte, err: Encode_Error) { encode_into_bytes :: proc(v: Value, flags := ENCODE_SMALL, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (data: []byte, err: Encode_Error) {
b := strings.builder_make(allocator) or_return b := strings.builder_make(allocator, loc) or_return
encode_into_builder(&b, v, flags, temp_allocator) or_return encode_into_builder(&b, v, flags, temp_allocator) or_return
return b.buf[:], nil return b.buf[:], nil
} }
// Encodes the CBOR value into binary CBOR written to the given builder. // Encodes the CBOR value into binary CBOR written to the given builder.
// See the docs on the proc group `encode_into` for more info. // See the docs on the proc group `encode_into` for more info.
encode_into_builder :: proc(b: ^strings.Builder, v: Value, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Encode_Error { encode_into_builder :: proc(b: ^strings.Builder, v: Value, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Encode_Error {
return encode_into_writer(strings.to_stream(b), v, flags, temp_allocator) return encode_into_writer(strings.to_stream(b), v, flags, temp_allocator, loc=loc)
} }
// Encodes the CBOR value into binary CBOR written to the given writer. // Encodes the CBOR value into binary CBOR written to the given writer.
// See the docs on the proc group `encode_into` for more info. // See the docs on the proc group `encode_into` for more info.
encode_into_writer :: proc(w: io.Writer, v: Value, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Encode_Error { encode_into_writer :: proc(w: io.Writer, v: Value, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Encode_Error {
return encode_into_encoder(Encoder{flags, w, temp_allocator}, v) return encode_into_encoder(Encoder{flags, w, temp_allocator}, v, loc=loc)
} }
// Encodes the CBOR value into binary CBOR written to the given encoder. // Encodes the CBOR value into binary CBOR written to the given encoder.
// See the docs on the proc group `encode_into` for more info. // See the docs on the proc group `encode_into` for more info.
encode_into_encoder :: proc(e: Encoder, v: Value) -> Encode_Error { encode_into_encoder :: proc(e: Encoder, v: Value, loc := #caller_location) -> Encode_Error {
e := e e := e
if e.temp_allocator.procedure == nil { if e.temp_allocator.procedure == nil {
@@ -366,21 +367,21 @@ _encode_u64_exact :: proc(w: io.Writer, v: u64, major: Major = .Unsigned) -> (er
return return
} }
_decode_bytes_ptr :: proc(d: Decoder, add: Add, type: Major = .Bytes) -> (v: ^Bytes, err: Decode_Error) { _decode_bytes_ptr :: proc(d: Decoder, add: Add, type: Major = .Bytes, allocator := context.allocator, loc := #caller_location) -> (v: ^Bytes, err: Decode_Error) {
v = new(Bytes) or_return v = new(Bytes, allocator, loc) or_return
defer if err != nil { free(v) } defer if err != nil { free(v, allocator, loc) }
v^ = _decode_bytes(d, add, type) or_return v^ = _decode_bytes(d, add, type, allocator, loc) or_return
return return
} }
_decode_bytes :: proc(d: Decoder, add: Add, type: Major = .Bytes, allocator := context.allocator) -> (v: Bytes, err: Decode_Error) { _decode_bytes :: proc(d: Decoder, add: Add, type: Major = .Bytes, allocator := context.allocator, loc := #caller_location) -> (v: Bytes, err: Decode_Error) {
context.allocator = allocator context.allocator = allocator
add := add add := add
n, scap := _decode_len_str(d, add) or_return n, scap := _decode_len_str(d, add) or_return
buf := strings.builder_make(0, scap) or_return buf := strings.builder_make(0, scap, allocator, loc) or_return
defer if err != nil { strings.builder_destroy(&buf) } defer if err != nil { strings.builder_destroy(&buf) }
buf_stream := strings.to_stream(&buf) buf_stream := strings.to_stream(&buf)
@@ -426,40 +427,40 @@ _encode_bytes :: proc(e: Encoder, val: Bytes, major: Major = .Bytes) -> (err: En
return return
} }
_decode_text_ptr :: proc(d: Decoder, add: Add) -> (v: ^Text, err: Decode_Error) { _decode_text_ptr :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: ^Text, err: Decode_Error) {
v = new(Text) or_return v = new(Text, allocator, loc) or_return
defer if err != nil { free(v) } defer if err != nil { free(v) }
v^ = _decode_text(d, add) or_return v^ = _decode_text(d, add, allocator, loc) or_return
return return
} }
_decode_text :: proc(d: Decoder, add: Add, allocator := context.allocator) -> (v: Text, err: Decode_Error) { _decode_text :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: Text, err: Decode_Error) {
return (Text)(_decode_bytes(d, add, .Text, allocator) or_return), nil return (Text)(_decode_bytes(d, add, .Text, allocator, loc) or_return), nil
} }
_encode_text :: proc(e: Encoder, val: Text) -> Encode_Error { _encode_text :: proc(e: Encoder, val: Text) -> Encode_Error {
return _encode_bytes(e, transmute([]byte)val, .Text) return _encode_bytes(e, transmute([]byte)val, .Text)
} }
_decode_array_ptr :: proc(d: Decoder, add: Add) -> (v: ^Array, err: Decode_Error) { _decode_array_ptr :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: ^Array, err: Decode_Error) {
v = new(Array) or_return v = new(Array, allocator, loc) or_return
defer if err != nil { free(v) } defer if err != nil { free(v) }
v^ = _decode_array(d, add) or_return v^ = _decode_array(d, add, allocator, loc) or_return
return return
} }
_decode_array :: proc(d: Decoder, add: Add) -> (v: Array, err: Decode_Error) { _decode_array :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: Array, err: Decode_Error) {
n, scap := _decode_len_container(d, add) or_return n, scap := _decode_len_container(d, add) or_return
array := make([dynamic]Value, 0, scap) or_return array := make([dynamic]Value, 0, scap, allocator, loc) or_return
defer if err != nil { defer if err != nil {
for entry in array { destroy(entry) } for entry in array { destroy(entry, allocator) }
delete(array) delete(array, loc)
} }
for i := 0; n == -1 || i < n; i += 1 { for i := 0; n == -1 || i < n; i += 1 {
val, verr := _decode_from_decoder(d) val, verr := _decode_from_decoder(d, {}, allocator, loc)
if n == -1 && verr == .Break { if n == -1 && verr == .Break {
break break
} else if verr != nil { } else if verr != nil {
@@ -485,39 +486,39 @@ _encode_array :: proc(e: Encoder, arr: Array) -> Encode_Error {
return nil return nil
} }
_decode_map_ptr :: proc(d: Decoder, add: Add) -> (v: ^Map, err: Decode_Error) { _decode_map_ptr :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: ^Map, err: Decode_Error) {
v = new(Map) or_return v = new(Map, allocator, loc) or_return
defer if err != nil { free(v) } defer if err != nil { free(v) }
v^ = _decode_map(d, add) or_return v^ = _decode_map(d, add, allocator, loc) or_return
return return
} }
_decode_map :: proc(d: Decoder, add: Add) -> (v: Map, err: Decode_Error) { _decode_map :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: Map, err: Decode_Error) {
n, scap := _decode_len_container(d, add) or_return n, scap := _decode_len_container(d, add) or_return
items := make([dynamic]Map_Entry, 0, scap) or_return items := make([dynamic]Map_Entry, 0, scap, allocator, loc) or_return
defer if err != nil { defer if err != nil {
for entry in items { for entry in items {
destroy(entry.key) destroy(entry.key)
destroy(entry.value) destroy(entry.value)
} }
delete(items) delete(items, loc)
} }
for i := 0; n == -1 || i < n; i += 1 { for i := 0; n == -1 || i < n; i += 1 {
key, kerr := _decode_from_decoder(d) key, kerr := _decode_from_decoder(d, {}, allocator, loc)
if n == -1 && kerr == .Break { if n == -1 && kerr == .Break {
break break
} else if kerr != nil { } else if kerr != nil {
return nil, kerr return nil, kerr
} }
value := _decode_from_decoder(d) or_return value := _decode_from_decoder(d, {}, allocator, loc) or_return
append(&items, Map_Entry{ append(&items, Map_Entry{
key = key, key = key,
value = value, value = value,
}) or_return }, loc) or_return
} }
if .Shrink_Excess in d.flags { shrink(&items) } if .Shrink_Excess in d.flags { shrink(&items) }
@@ -578,20 +579,20 @@ _encode_map :: proc(e: Encoder, m: Map) -> (err: Encode_Error) {
return nil return nil
} }
_decode_tag_ptr :: proc(d: Decoder, add: Add) -> (v: Value, err: Decode_Error) { _decode_tag_ptr :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: Value, err: Decode_Error) {
tag := _decode_tag(d, add) or_return tag := _decode_tag(d, add, allocator, loc) or_return
if t, ok := tag.?; ok { if t, ok := tag.?; ok {
defer if err != nil { destroy(t.value) } defer if err != nil { destroy(t.value) }
tp := new(Tag) or_return tp := new(Tag, allocator, loc) or_return
tp^ = t tp^ = t
return tp, nil return tp, nil
} }
// no error, no tag, this was the self described CBOR tag, skip it. // no error, no tag, this was the self described CBOR tag, skip it.
return _decode_from_decoder(d) return _decode_from_decoder(d, {}, allocator, loc)
} }
_decode_tag :: proc(d: Decoder, add: Add) -> (v: Maybe(Tag), err: Decode_Error) { _decode_tag :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: Maybe(Tag), err: Decode_Error) {
num := _decode_uint_as_u64(d.reader, add) or_return num := _decode_uint_as_u64(d.reader, add) or_return
// CBOR can be wrapped in a tag that decoders can use to see/check if the binary data is CBOR. // CBOR can be wrapped in a tag that decoders can use to see/check if the binary data is CBOR.
@@ -602,7 +603,7 @@ _decode_tag :: proc(d: Decoder, add: Add) -> (v: Maybe(Tag), err: Decode_Error)
t := Tag{ t := Tag{
number = num, number = num,
value = _decode_from_decoder(d) or_return, value = _decode_from_decoder(d, {}, allocator, loc) or_return,
} }
if nested, ok := t.value.(^Tag); ok { if nested, ok := t.value.(^Tag); ok {
+8 -8
View File
@@ -45,8 +45,8 @@ marshal :: marshal_into
// Marshals the given value into a CBOR byte stream (allocated using the given allocator). // Marshals the given value into a CBOR byte stream (allocated using the given allocator).
// See docs on the `marshal_into` proc group for more info. // See docs on the `marshal_into` proc group for more info.
marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (bytes: []byte, err: Marshal_Error) { marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (bytes: []byte, err: Marshal_Error) {
b, alloc_err := strings.builder_make(allocator) b, alloc_err := strings.builder_make(allocator, loc=loc)
// The builder as a stream also returns .EOF if it ran out of memory so this is consistent. // The builder as a stream also returns .EOF if it ran out of memory so this is consistent.
if alloc_err != nil { if alloc_err != nil {
return nil, .EOF return nil, .EOF
@@ -54,7 +54,7 @@ marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.a
defer if err != nil { strings.builder_destroy(&b) } defer if err != nil { strings.builder_destroy(&b) }
if err = marshal_into_builder(&b, v, flags, temp_allocator); err != nil { if err = marshal_into_builder(&b, v, flags, temp_allocator, loc=loc); err != nil {
return return
} }
@@ -63,20 +63,20 @@ marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.a
// Marshals the given value into a CBOR byte stream written to the given builder. // Marshals the given value into a CBOR byte stream written to the given builder.
// See docs on the `marshal_into` proc group for more info. // See docs on the `marshal_into` proc group for more info.
marshal_into_builder :: proc(b: ^strings.Builder, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Marshal_Error { marshal_into_builder :: proc(b: ^strings.Builder, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Marshal_Error {
return marshal_into_writer(strings.to_writer(b), v, flags, temp_allocator) return marshal_into_writer(strings.to_writer(b), v, flags, temp_allocator, loc=loc)
} }
// Marshals the given value into a CBOR byte stream written to the given writer. // Marshals the given value into a CBOR byte stream written to the given writer.
// See docs on the `marshal_into` proc group for more info. // See docs on the `marshal_into` proc group for more info.
marshal_into_writer :: proc(w: io.Writer, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Marshal_Error { marshal_into_writer :: proc(w: io.Writer, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Marshal_Error {
encoder := Encoder{flags, w, temp_allocator} encoder := Encoder{flags, w, temp_allocator}
return marshal_into_encoder(encoder, v) return marshal_into_encoder(encoder, v, loc=loc)
} }
// Marshals the given value into a CBOR byte stream written to the given encoder. // Marshals the given value into a CBOR byte stream written to the given encoder.
// See docs on the `marshal_into` proc group for more info. // See docs on the `marshal_into` proc group for more info.
marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) { marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (err: Marshal_Error) {
e := e e := e
if e.temp_allocator.procedure == nil { if e.temp_allocator.procedure == nil {
+52 -50
View File
@@ -31,8 +31,8 @@ unmarshal :: proc {
unmarshal_from_string, unmarshal_from_string,
} }
unmarshal_from_reader :: proc(r: io.Reader, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (err: Unmarshal_Error) { unmarshal_from_reader :: proc(r: io.Reader, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
err = unmarshal_from_decoder(Decoder{ DEFAULT_MAX_PRE_ALLOC, flags, r }, ptr, allocator, temp_allocator) err = unmarshal_from_decoder(Decoder{ DEFAULT_MAX_PRE_ALLOC, flags, r }, ptr, allocator, temp_allocator, loc)
// Normal EOF does not exist here, we try to read the exact amount that is said to be provided. // Normal EOF does not exist here, we try to read the exact amount that is said to be provided.
if err == .EOF { err = .Unexpected_EOF } if err == .EOF { err = .Unexpected_EOF }
@@ -40,21 +40,21 @@ unmarshal_from_reader :: proc(r: io.Reader, ptr: ^$T, flags := Decoder_Flags{},
} }
// Unmarshals from a string, see docs on the proc group `Unmarshal` for more info. // Unmarshals from a string, see docs on the proc group `Unmarshal` for more info.
unmarshal_from_string :: proc(s: string, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (err: Unmarshal_Error) { unmarshal_from_string :: proc(s: string, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
sr: strings.Reader sr: strings.Reader
r := strings.to_reader(&sr, s) r := strings.to_reader(&sr, s)
err = unmarshal_from_reader(r, ptr, flags, allocator, temp_allocator) err = unmarshal_from_reader(r, ptr, flags, allocator, temp_allocator, loc)
// Normal EOF does not exist here, we try to read the exact amount that is said to be provided. // Normal EOF does not exist here, we try to read the exact amount that is said to be provided.
if err == .EOF { err = .Unexpected_EOF } if err == .EOF { err = .Unexpected_EOF }
return return
} }
unmarshal_from_decoder :: proc(d: Decoder, ptr: ^$T, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (err: Unmarshal_Error) { unmarshal_from_decoder :: proc(d: Decoder, ptr: ^$T, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
d := d d := d
err = _unmarshal_any_ptr(d, ptr, nil, allocator, temp_allocator) err = _unmarshal_any_ptr(d, ptr, nil, allocator, temp_allocator, loc)
// Normal EOF does not exist here, we try to read the exact amount that is said to be provided. // Normal EOF does not exist here, we try to read the exact amount that is said to be provided.
if err == .EOF { err = .Unexpected_EOF } if err == .EOF { err = .Unexpected_EOF }
@@ -62,7 +62,7 @@ unmarshal_from_decoder :: proc(d: Decoder, ptr: ^$T, allocator := context.alloca
} }
_unmarshal_any_ptr :: proc(d: Decoder, v: any, hdr: Maybe(Header) = nil, allocator := context.allocator, temp_allocator := context.temp_allocator) -> Unmarshal_Error { _unmarshal_any_ptr :: proc(d: Decoder, v: any, hdr: Maybe(Header) = nil, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> Unmarshal_Error {
context.allocator = allocator context.allocator = allocator
context.temp_allocator = temp_allocator context.temp_allocator = temp_allocator
v := v v := v
@@ -78,10 +78,10 @@ _unmarshal_any_ptr :: proc(d: Decoder, v: any, hdr: Maybe(Header) = nil, allocat
} }
data := any{(^rawptr)(v.data)^, ti.variant.(reflect.Type_Info_Pointer).elem.id} data := any{(^rawptr)(v.data)^, ti.variant.(reflect.Type_Info_Pointer).elem.id}
return _unmarshal_value(d, data, hdr.? or_else (_decode_header(d.reader) or_return)) return _unmarshal_value(d, data, hdr.? or_else (_decode_header(d.reader) or_return), allocator, temp_allocator, loc)
} }
_unmarshal_value :: proc(d: Decoder, v: any, hdr: Header) -> (err: Unmarshal_Error) { _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
v := v v := v
ti := reflect.type_info_base(type_info_of(v.id)) ti := reflect.type_info_base(type_info_of(v.id))
r := d.reader r := d.reader
@@ -104,7 +104,7 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header) -> (err: Unmarshal_Err
// Allow generic unmarshal by doing it into a `Value`. // Allow generic unmarshal by doing it into a `Value`.
switch &dst in v { switch &dst in v {
case Value: case Value:
dst = err_conv(_decode_from_decoder(d, hdr)) or_return dst = err_conv(_decode_from_decoder(d, hdr, allocator, loc)) or_return
return return
} }
@@ -308,7 +308,7 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header) -> (err: Unmarshal_Err
if impl, ok := _tag_implementations_nr[nr]; ok { if impl, ok := _tag_implementations_nr[nr]; ok {
return impl->unmarshal(d, nr, v) return impl->unmarshal(d, nr, v)
} else if nr == TAG_OBJECT_TYPE { } else if nr == TAG_OBJECT_TYPE {
return _unmarshal_union(d, v, ti, hdr) return _unmarshal_union(d, v, ti, hdr, loc=loc)
} else { } else {
// Discard the tag info and unmarshal as its value. // Discard the tag info and unmarshal as its value.
return _unmarshal_value(d, v, _decode_header(r) or_return) return _unmarshal_value(d, v, _decode_header(r) or_return)
@@ -316,19 +316,19 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header) -> (err: Unmarshal_Err
return _unsupported(v, hdr, add) return _unsupported(v, hdr, add)
case .Bytes: return _unmarshal_bytes(d, v, ti, hdr, add) case .Bytes: return _unmarshal_bytes(d, v, ti, hdr, add, allocator=allocator, loc=loc)
case .Text: return _unmarshal_string(d, v, ti, hdr, add) case .Text: return _unmarshal_string(d, v, ti, hdr, add, allocator=allocator, loc=loc)
case .Array: return _unmarshal_array(d, v, ti, hdr, add) case .Array: return _unmarshal_array(d, v, ti, hdr, add, allocator=allocator, loc=loc)
case .Map: return _unmarshal_map(d, v, ti, hdr, add) case .Map: return _unmarshal_map(d, v, ti, hdr, add, allocator=allocator, loc=loc)
case: return .Bad_Major case: return .Bad_Major
} }
} }
_unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add) -> (err: Unmarshal_Error) { _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
#partial switch t in ti.variant { #partial switch t in ti.variant {
case reflect.Type_Info_String: case reflect.Type_Info_String:
bytes := err_conv(_decode_bytes(d, add)) or_return bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return
if t.is_cstring { if t.is_cstring {
raw := (^cstring)(v.data) raw := (^cstring)(v.data)
@@ -347,7 +347,7 @@ _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
if elem_base.id != byte { return _unsupported(v, hdr) } if elem_base.id != byte { return _unsupported(v, hdr) }
bytes := err_conv(_decode_bytes(d, add)) or_return bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return
raw := (^mem.Raw_Slice)(v.data) raw := (^mem.Raw_Slice)(v.data)
raw^ = transmute(mem.Raw_Slice)bytes raw^ = transmute(mem.Raw_Slice)bytes
return return
@@ -357,12 +357,12 @@ _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
if elem_base.id != byte { return _unsupported(v, hdr) } if elem_base.id != byte { return _unsupported(v, hdr) }
bytes := err_conv(_decode_bytes(d, add)) or_return bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return
raw := (^mem.Raw_Dynamic_Array)(v.data) raw := (^mem.Raw_Dynamic_Array)(v.data)
raw.data = raw_data(bytes) raw.data = raw_data(bytes)
raw.len = len(bytes) raw.len = len(bytes)
raw.cap = len(bytes) raw.cap = len(bytes)
raw.allocator = context.allocator raw.allocator = allocator
return return
case reflect.Type_Info_Array: case reflect.Type_Info_Array:
@@ -385,10 +385,10 @@ _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
return _unsupported(v, hdr) return _unsupported(v, hdr)
} }
_unmarshal_string :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add) -> (err: Unmarshal_Error) { _unmarshal_string :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
#partial switch t in ti.variant { #partial switch t in ti.variant {
case reflect.Type_Info_String: case reflect.Type_Info_String:
text := err_conv(_decode_text(d, add)) or_return text := err_conv(_decode_text(d, add, allocator, loc)) or_return
if t.is_cstring { if t.is_cstring {
raw := (^cstring)(v.data) raw := (^cstring)(v.data)
@@ -403,8 +403,8 @@ _unmarshal_string :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Heade
// Enum by its variant name. // Enum by its variant name.
case reflect.Type_Info_Enum: case reflect.Type_Info_Enum:
text := err_conv(_decode_text(d, add, allocator=context.temp_allocator)) or_return text := err_conv(_decode_text(d, add, allocator=temp_allocator, loc=loc)) or_return
defer delete(text, context.temp_allocator) defer delete(text, temp_allocator, loc)
for name, i in t.names { for name, i in t.names {
if name == text { if name == text {
@@ -414,8 +414,8 @@ _unmarshal_string :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Heade
} }
case reflect.Type_Info_Rune: case reflect.Type_Info_Rune:
text := err_conv(_decode_text(d, add, allocator=context.temp_allocator)) or_return text := err_conv(_decode_text(d, add, allocator=temp_allocator, loc=loc)) or_return
defer delete(text, context.temp_allocator) defer delete(text, temp_allocator, loc)
r := (^rune)(v.data) r := (^rune)(v.data)
dr, n := utf8.decode_rune(text) dr, n := utf8.decode_rune(text)
@@ -430,13 +430,15 @@ _unmarshal_string :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Heade
return _unsupported(v, hdr) return _unsupported(v, hdr)
} }
_unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add) -> (err: Unmarshal_Error) { _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
assign_array :: proc( assign_array :: proc(
d: Decoder, d: Decoder,
da: ^mem.Raw_Dynamic_Array, da: ^mem.Raw_Dynamic_Array,
elemt: ^reflect.Type_Info, elemt: ^reflect.Type_Info,
length: int, length: int,
growable := true, growable := true,
allocator := context.allocator,
loc := #caller_location,
) -> (out_of_space: bool, err: Unmarshal_Error) { ) -> (out_of_space: bool, err: Unmarshal_Error) {
for idx: uintptr = 0; length == -1 || idx < uintptr(length); idx += 1 { for idx: uintptr = 0; length == -1 || idx < uintptr(length); idx += 1 {
elem_ptr := rawptr(uintptr(da.data) + idx*uintptr(elemt.size)) elem_ptr := rawptr(uintptr(da.data) + idx*uintptr(elemt.size))
@@ -450,13 +452,13 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
if !growable { return true, .Out_Of_Memory } if !growable { return true, .Out_Of_Memory }
cap := 2 * da.cap cap := 2 * da.cap
ok := runtime.__dynamic_array_reserve(da, elemt.size, elemt.align, cap) ok := runtime.__dynamic_array_reserve(da, elemt.size, elemt.align, cap, loc)
// NOTE: Might be lying here, but it is at least an allocator error. // NOTE: Might be lying here, but it is at least an allocator error.
if !ok { return false, .Out_Of_Memory } if !ok { return false, .Out_Of_Memory }
} }
err = _unmarshal_value(d, elem, hdr) err = _unmarshal_value(d, elem, hdr, allocator=allocator, loc=loc)
if length == -1 && err == .Break { break } if length == -1 && err == .Break { break }
if err != nil { return } if err != nil { return }
@@ -469,10 +471,10 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
// Allow generically storing the values array. // Allow generically storing the values array.
switch &dst in v { switch &dst in v {
case ^Array: case ^Array:
dst = err_conv(_decode_array_ptr(d, add)) or_return dst = err_conv(_decode_array_ptr(d, add, allocator=allocator, loc=loc)) or_return
return return
case Array: case Array:
dst = err_conv(_decode_array(d, add)) or_return dst = err_conv(_decode_array(d, add, allocator=allocator, loc=loc)) or_return
return return
} }
@@ -480,8 +482,8 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
case reflect.Type_Info_Slice: case reflect.Type_Info_Slice:
length, scap := err_conv(_decode_len_container(d, add)) or_return length, scap := err_conv(_decode_len_container(d, add)) or_return
data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align) or_return data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align, allocator=allocator, loc=loc) or_return
defer if err != nil { mem.free_bytes(data) } defer if err != nil { mem.free_bytes(data, allocator=allocator, loc=loc) }
da := mem.Raw_Dynamic_Array{raw_data(data), 0, length, context.allocator } da := mem.Raw_Dynamic_Array{raw_data(data), 0, length, context.allocator }
@@ -489,7 +491,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
if .Shrink_Excess in d.flags { if .Shrink_Excess in d.flags {
// Ignoring an error here, but this is not critical to succeed. // Ignoring an error here, but this is not critical to succeed.
_ = runtime.__dynamic_array_shrink(&da, t.elem.size, t.elem.align, da.len) _ = runtime.__dynamic_array_shrink(&da, t.elem.size, t.elem.align, da.len, loc=loc)
} }
raw := (^mem.Raw_Slice)(v.data) raw := (^mem.Raw_Slice)(v.data)
@@ -500,8 +502,8 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
case reflect.Type_Info_Dynamic_Array: case reflect.Type_Info_Dynamic_Array:
length, scap := err_conv(_decode_len_container(d, add)) or_return length, scap := err_conv(_decode_len_container(d, add)) or_return
data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align) or_return data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align, loc=loc) or_return
defer if err != nil { mem.free_bytes(data) } defer if err != nil { mem.free_bytes(data, allocator=allocator, loc=loc) }
raw := (^mem.Raw_Dynamic_Array)(v.data) raw := (^mem.Raw_Dynamic_Array)(v.data)
raw.data = raw_data(data) raw.data = raw_data(data)
@@ -513,7 +515,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
if .Shrink_Excess in d.flags { if .Shrink_Excess in d.flags {
// Ignoring an error here, but this is not critical to succeed. // Ignoring an error here, but this is not critical to succeed.
_ = runtime.__dynamic_array_shrink(raw, t.elem.size, t.elem.align, raw.len) _ = runtime.__dynamic_array_shrink(raw, t.elem.size, t.elem.align, raw.len, loc=loc)
} }
return return
@@ -525,7 +527,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
return _unsupported(v, hdr) return _unsupported(v, hdr)
} }
da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, context.allocator } da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator }
out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return
if out_of_space { return _unsupported(v, hdr) } if out_of_space { return _unsupported(v, hdr) }
@@ -539,7 +541,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
return _unsupported(v, hdr) return _unsupported(v, hdr)
} }
da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, context.allocator } da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator }
out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return
if out_of_space { return _unsupported(v, hdr) } if out_of_space { return _unsupported(v, hdr) }
@@ -553,7 +555,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
return _unsupported(v, hdr) return _unsupported(v, hdr)
} }
da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, 2, context.allocator } da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, 2, allocator }
info: ^runtime.Type_Info info: ^runtime.Type_Info
switch ti.id { switch ti.id {
@@ -575,7 +577,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
return _unsupported(v, hdr) return _unsupported(v, hdr)
} }
da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, 4, context.allocator } da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, 4, allocator }
info: ^runtime.Type_Info info: ^runtime.Type_Info
switch ti.id { switch ti.id {
@@ -593,17 +595,17 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
} }
} }
_unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add) -> (err: Unmarshal_Error) { _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
r := d.reader r := d.reader
decode_key :: proc(d: Decoder, v: any, allocator := context.allocator) -> (k: string, err: Unmarshal_Error) { decode_key :: proc(d: Decoder, v: any, allocator := context.allocator, loc := #caller_location) -> (k: string, err: Unmarshal_Error) {
entry_hdr := _decode_header(d.reader) or_return entry_hdr := _decode_header(d.reader) or_return
entry_maj, entry_add := _header_split(entry_hdr) entry_maj, entry_add := _header_split(entry_hdr)
#partial switch entry_maj { #partial switch entry_maj {
case .Text: case .Text:
k = err_conv(_decode_text(d, entry_add, allocator)) or_return k = err_conv(_decode_text(d, entry_add, allocator=allocator, loc=loc)) or_return
return return
case .Bytes: case .Bytes:
bytes := err_conv(_decode_bytes(d, entry_add, allocator=allocator)) or_return bytes := err_conv(_decode_bytes(d, entry_add, allocator=allocator, loc=loc)) or_return
k = string(bytes) k = string(bytes)
return return
case: case:
@@ -615,10 +617,10 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header,
// Allow generically storing the map array. // Allow generically storing the map array.
switch &dst in v { switch &dst in v {
case ^Map: case ^Map:
dst = err_conv(_decode_map_ptr(d, add)) or_return dst = err_conv(_decode_map_ptr(d, add, allocator=allocator, loc=loc)) or_return
return return
case Map: case Map:
dst = err_conv(_decode_map(d, add)) or_return dst = err_conv(_decode_map(d, add, allocator=allocator, loc=loc)) or_return
return return
} }
@@ -754,7 +756,7 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header,
// Unmarshal into a union, based on the `TAG_OBJECT_TYPE` tag of the spec, it denotes a tag which // Unmarshal into a union, based on the `TAG_OBJECT_TYPE` tag of the spec, it denotes a tag which
// contains an array of exactly two elements, the first is a textual representation of the following // contains an array of exactly two elements, the first is a textual representation of the following
// CBOR value's type. // CBOR value's type.
_unmarshal_union :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header) -> (err: Unmarshal_Error) { _unmarshal_union :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, loc := #caller_location) -> (err: Unmarshal_Error) {
r := d.reader r := d.reader
#partial switch t in ti.variant { #partial switch t in ti.variant {
case reflect.Type_Info_Union: case reflect.Type_Info_Union:
@@ -792,7 +794,7 @@ _unmarshal_union :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
case reflect.Type_Info_Named: case reflect.Type_Info_Named:
if vti.name == target_name { if vti.name == target_name {
reflect.set_union_variant_raw_tag(v, tag) reflect.set_union_variant_raw_tag(v, tag)
return _unmarshal_value(d, any{v.data, variant.id}, _decode_header(r) or_return) return _unmarshal_value(d, any{v.data, variant.id}, _decode_header(r) or_return, loc=loc)
} }
case: case:
@@ -804,7 +806,7 @@ _unmarshal_union :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
if variant_name == target_name { if variant_name == target_name {
reflect.set_union_variant_raw_tag(v, tag) reflect.set_union_variant_raw_tag(v, tag)
return _unmarshal_value(d, any{v.data, variant.id}, _decode_header(r) or_return) return _unmarshal_value(d, any{v.data, variant.id}, _decode_header(r) or_return, loc=loc)
} }
} }
} }
+4 -4
View File
@@ -350,9 +350,9 @@ Output:
ab ab
*/ */
write_byte :: proc(b: ^Builder, x: byte) -> (n: int) { write_byte :: proc(b: ^Builder, x: byte, loc := #caller_location) -> (n: int) {
n0 := len(b.buf) n0 := len(b.buf)
append(&b.buf, x) append(&b.buf, x, loc)
n1 := len(b.buf) n1 := len(b.buf)
return n1-n0 return n1-n0
} }
@@ -380,9 +380,9 @@ NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n`
Returns: Returns:
- n: The number of bytes appended - n: The number of bytes appended
*/ */
write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) { write_bytes :: proc(b: ^Builder, x: []byte, loc := #caller_location) -> (n: int) {
n0 := len(b.buf) n0 := len(b.buf)
append(&b.buf, ..x) append(&b.buf, ..x, loc=loc)
n1 := len(b.buf) n1 := len(b.buf)
return n1-n0 return n1-n0
} }
+7 -7
View File
@@ -45,13 +45,13 @@ crypto_test:
$(ODIN) test crypto $(COMMON) -o:speed -out:test_crypto $(ODIN) test crypto $(COMMON) -o:speed -out:test_crypto
encoding_test: encoding_test:
$(ODIN) run encoding/hxa $(COMMON) $(COLLECTION) -out:test_hxa $(ODIN) test encoding/base64 $(COMMON) -out:test_base64
$(ODIN) run encoding/json $(COMMON) -out:test_json $(ODIN) test encoding/cbor $(COMMON) -out:test_cbor
$(ODIN) run encoding/varint $(COMMON) -out:test_varint $(ODIN) run encoding/hex $(COMMON) -out:test_hex
$(ODIN) run encoding/xml $(COMMON) -out:test_xml $(ODIN) run encoding/hxa $(COMMON) $(COLLECTION) -out:test_hxa
$(ODIN) run encoding/cbor $(COMMON) -out:test_cbor $(ODIN) run encoding/json $(COMMON) -out:test_json
$(ODIN) run encoding/hex $(COMMON) -out:test_hex $(ODIN) run encoding/varint $(COMMON) -out:test_varint
$(ODIN) run encoding/base64 $(COMMON) -out:test_base64 $(ODIN) run encoding/xml $(COMMON) -out:test_xml
filepath_test: filepath_test:
$(ODIN) run path/filepath $(COMMON) $(COLLECTION) -out:test_core_filepath $(ODIN) run path/filepath $(COMMON) $(COLLECTION) -out:test_core_filepath
+6 -6
View File
@@ -21,13 +21,13 @@ echo ---
echo --- echo ---
echo Running core:encoding tests echo Running core:encoding tests
echo --- echo ---
%PATH_TO_ODIN% test encoding/base64 %COMMON% -out:test_base64.exe || exit /b
%PATH_TO_ODIN% test encoding/cbor %COMMON% -out:test_cbor.exe || exit /b
%PATH_TO_ODIN% test encoding/hex %COMMON% -out:test_hex.exe || exit /b
rem %PATH_TO_ODIN% run encoding/hxa %COMMON% %COLLECTION% -out:test_hxa.exe || exit /b rem %PATH_TO_ODIN% run encoding/hxa %COMMON% %COLLECTION% -out:test_hxa.exe || exit /b
%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe || exit /b %PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe || exit /b
%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b %PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b
%PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b %PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b
%PATH_TO_ODIN% test encoding/cbor %COMMON% -out:test_cbor.exe -define:ODIN_TEST_THREADS=1 -define:ODIN_TEST_FANCY=false || exit /b
%PATH_TO_ODIN% run encoding/hex %COMMON% -out:test_hex.exe || exit /b
%PATH_TO_ODIN% run encoding/base64 %COMMON% -out:test_base64.exe || exit /b
echo --- echo ---
echo Running core:fmt tests echo Running core:fmt tests
+21 -44
View File
@@ -1,61 +1,38 @@
package test_encoding_base64 package test_encoding_base64
import "base:intrinsics" import "base:intrinsics"
import "core:encoding/base64" import "core:encoding/base64"
import "core:fmt"
import "core:os"
import "core:reflect"
import "core:testing" import "core:testing"
TEST_count := 0 Test :: struct {
TEST_fail := 0 vector: string,
base64: string,
when ODIN_TEST {
expect_value :: testing.expect_value
} else {
expect_value :: proc(t: ^testing.T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) {
TEST_count += 1
ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected)
if !ok {
TEST_fail += 1
fmt.printf("[%v] expected %v, got %v\n", loc, expected, value)
}
return ok
}
} }
main :: proc() { tests :: []Test{
t := testing.T{} {"", ""},
{"f", "Zg=="},
test_encoding(&t) {"fo", "Zm8="},
test_decoding(&t) {"foo", "Zm9v"},
{"foob", "Zm9vYg=="},
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) {"fooba", "Zm9vYmE="},
if TEST_fail > 0 { {"foobar", "Zm9vYmFy"},
os.exit(1)
}
} }
@(test) @(test)
test_encoding :: proc(t: ^testing.T) { test_encoding :: proc(t: ^testing.T) {
expect_value(t, base64.encode(transmute([]byte)string("")), "") for test in tests {
expect_value(t, base64.encode(transmute([]byte)string("f")), "Zg==") v := base64.encode(transmute([]byte)test.vector)
expect_value(t, base64.encode(transmute([]byte)string("fo")), "Zm8=") defer delete(v)
expect_value(t, base64.encode(transmute([]byte)string("foo")), "Zm9v") testing.expect_value(t, v, test.base64)
expect_value(t, base64.encode(transmute([]byte)string("foob")), "Zm9vYg==") }
expect_value(t, base64.encode(transmute([]byte)string("fooba")), "Zm9vYmE=")
expect_value(t, base64.encode(transmute([]byte)string("foobar")), "Zm9vYmFy")
} }
@(test) @(test)
test_decoding :: proc(t: ^testing.T) { test_decoding :: proc(t: ^testing.T) {
expect_value(t, string(base64.decode("")), "") for test in tests {
expect_value(t, string(base64.decode("Zg==")), "f") v := string(base64.decode(test.base64))
expect_value(t, string(base64.decode("Zm8=")), "fo") defer delete(v)
expect_value(t, string(base64.decode("Zm9v")), "foo") testing.expect_value(t, v, test.vector)
expect_value(t, string(base64.decode("Zm9vYg==")), "foob") }
expect_value(t, string(base64.decode("Zm9vYmE=")), "fooba")
expect_value(t, string(base64.decode("Zm9vYmFy")), "foobar")
} }
+132 -209
View File
@@ -1,105 +1,15 @@
package test_encoding_cbor package test_encoding_cbor
import "base:intrinsics" import "base:intrinsics"
import "core:bytes" import "core:bytes"
import "core:encoding/cbor" import "core:encoding/cbor"
import "core:fmt" import "core:fmt"
import "core:io" import "core:io"
import "core:math/big" import "core:math/big"
import "core:mem"
import "core:os"
import "core:reflect" import "core:reflect"
import "core:testing" import "core:testing"
import "core:time" import "core:time"
TEST_count := 0
TEST_fail := 0
when ODIN_TEST {
expect :: testing.expect
expect_value :: testing.expect_value
errorf :: testing.errorf
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.printf("[%v] %v\n", loc, message)
return
}
}
expect_value :: proc(t: ^testing.T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) {
TEST_count += 1
ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected)
if !ok {
TEST_fail += 1
fmt.printf("[%v] expected %v, got %v\n", loc, expected, value)
}
return ok
}
errorf :: proc(t: ^testing.T, fmts: string, args: ..any, loc := #caller_location) {
TEST_fail += 1
fmt.printf("[%v] ERROR: ", loc)
fmt.printf(fmts, ..args)
fmt.println()
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
}
main :: proc() {
t := testing.T{}
test_marshalling(&t)
test_marshalling_maybe(&t)
test_marshalling_nil_maybe(&t)
test_marshalling_union(&t)
test_lying_length_array(&t)
test_decode_unsigned(&t)
test_encode_unsigned(&t)
test_decode_negative(&t)
test_encode_negative(&t)
test_decode_simples(&t)
test_encode_simples(&t)
test_decode_floats(&t)
test_encode_floats(&t)
test_decode_bytes(&t)
test_encode_bytes(&t)
test_decode_strings(&t)
test_encode_strings(&t)
test_decode_lists(&t)
test_encode_lists(&t)
test_decode_maps(&t)
test_encode_maps(&t)
test_decode_tags(&t)
test_encode_tags(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
Foo :: struct { Foo :: struct {
str: string, str: string,
cstr: cstring, cstr: cstring,
@@ -143,14 +53,6 @@ FooBars :: bit_set[FooBar; u16]
@(test) @(test)
test_marshalling :: proc(t: ^testing.T) { test_marshalling :: proc(t: ^testing.T) {
tracker: mem.Tracking_Allocator
mem.tracking_allocator_init(&tracker, context.allocator)
context.allocator = mem.tracking_allocator(&tracker)
context.temp_allocator = context.allocator
defer mem.tracking_allocator_destroy(&tracker)
ev :: expect_value
{ {
nice := "16 is a nice number" nice := "16 is a nice number"
now := time.Time{_nsec = 1701117968 * 1e9} now := time.Time{_nsec = 1701117968 * 1e9}
@@ -205,18 +107,18 @@ test_marshalling :: proc(t: ^testing.T) {
} }
data, err := cbor.marshal(f, cbor.ENCODE_FULLY_DETERMINISTIC) data, err := cbor.marshal(f, cbor.ENCODE_FULLY_DETERMINISTIC)
ev(t, err, nil) testing.expect_value(t, err, nil)
defer delete(data) defer delete(data)
decoded, derr := cbor.decode(string(data)) decoded, derr := cbor.decode(string(data))
ev(t, derr, nil) testing.expect_value(t, derr, nil)
defer cbor.destroy(decoded) defer cbor.destroy(decoded)
diagnosis, eerr := cbor.to_diagnostic_format(decoded) diagnosis, eerr := cbor.to_diagnostic_format(decoded)
ev(t, eerr, nil) testing.expect_value(t, eerr, nil)
defer delete(diagnosis) defer delete(diagnosis)
ev(t, diagnosis, `{ testing.expect_value(t, diagnosis, `{
"base64": 34("MTYgaXMgYSBuaWNlIG51bWJlcg=="), "base64": 34("MTYgaXMgYSBuaWNlIG51bWJlcg=="),
"biggest": 2(h'f951a9fd3c158afdff08ab8e0'), "biggest": 2(h'f951a9fd3c158afdff08ab8e0'),
"biggie": 18446744073709551615, "biggie": 18446744073709551615,
@@ -285,7 +187,7 @@ test_marshalling :: proc(t: ^testing.T) {
backf: Foo backf: Foo
uerr := cbor.unmarshal(string(data), &backf) uerr := cbor.unmarshal(string(data), &backf)
ev(t, uerr, nil) testing.expect_value(t, uerr, nil)
defer { defer {
delete(backf.str) delete(backf.str)
delete(backf.cstr) delete(backf.cstr)
@@ -304,104 +206,102 @@ test_marshalling :: proc(t: ^testing.T) {
big.destroy(&backf.smallest) big.destroy(&backf.smallest)
} }
ev(t, backf.str, f.str) testing.expect_value(t, backf.str, f.str)
ev(t, backf.cstr, f.cstr) testing.expect_value(t, backf.cstr, f.cstr)
#partial switch v in backf.value { #partial switch v in backf.value {
case ^cbor.Map: case ^cbor.Map:
for entry, i in v { for entry, i in v {
fm := f.value.(^cbor.Map) fm := f.value.(^cbor.Map)
ev(t, entry.key, fm[i].key) testing.expect_value(t, entry.key, fm[i].key)
if str, is_str := entry.value.(^cbor.Text); is_str { if str, is_str := entry.value.(^cbor.Text); is_str {
ev(t, str^, fm[i].value.(^cbor.Text)^) testing.expect_value(t, str^, fm[i].value.(^cbor.Text)^)
} else { } else {
ev(t, entry.value, fm[i].value) testing.expect_value(t, entry.value, fm[i].value)
} }
} }
case: errorf(t, "wrong type %v", v) case: testing.expectf(t, false, "wrong type %v", v)
} }
ev(t, backf.neg, f.neg) testing.expect_value(t, backf.neg, f.neg)
ev(t, backf.iamint, f.iamint) testing.expect_value(t, backf.iamint, f.iamint)
ev(t, backf.base64, f.base64) testing.expect_value(t, backf.base64, f.base64)
ev(t, backf.renamed, f.renamed) testing.expect_value(t, backf.renamed, f.renamed)
ev(t, backf.now, f.now) testing.expect_value(t, backf.now, f.now)
ev(t, backf.nowie, f.nowie) testing.expect_value(t, backf.nowie, f.nowie)
for e, i in f.child.dyn { ev(t, backf.child.dyn[i], e) } for e, i in f.child.dyn { testing.expect_value(t, backf.child.dyn[i], e) }
for key, value in f.child.mappy { ev(t, backf.child.mappy[key], value) } for key, value in f.child.mappy { testing.expect_value(t, backf.child.mappy[key], value) }
ev(t, backf.child.my_integers, f.child.my_integers) testing.expect_value(t, backf.child.my_integers, f.child.my_integers)
ev(t, len(backf.my_bytes), 0) testing.expect_value(t, len(backf.my_bytes), 0)
ev(t, len(backf.my_bytes), len(f.my_bytes)) testing.expect_value(t, len(backf.my_bytes), len(f.my_bytes))
ev(t, backf.ennie, f.ennie) testing.expect_value(t, backf.ennie, f.ennie)
ev(t, backf.ennieb, f.ennieb) testing.expect_value(t, backf.ennieb, f.ennieb)
ev(t, backf.quat, f.quat) testing.expect_value(t, backf.quat, f.quat)
ev(t, backf.comp, f.comp) testing.expect_value(t, backf.comp, f.comp)
ev(t, backf.important, f.important) testing.expect_value(t, backf.important, f.important)
ev(t, backf.no, nil) testing.expect_value(t, backf.no, nil)
ev(t, backf.nos, nil) testing.expect_value(t, backf.nos, nil)
ev(t, backf.yes, f.yes) testing.expect_value(t, backf.yes, f.yes)
ev(t, backf.biggie, f.biggie) testing.expect_value(t, backf.biggie, f.biggie)
ev(t, backf.smallie, f.smallie) testing.expect_value(t, backf.smallie, f.smallie)
ev(t, backf.onetwenty, f.onetwenty) testing.expect_value(t, backf.onetwenty, f.onetwenty)
ev(t, backf.small_onetwenty, f.small_onetwenty) testing.expect_value(t, backf.small_onetwenty, f.small_onetwenty)
ev(t, backf.ignore_this, nil) testing.expect_value(t, backf.ignore_this, nil)
s_equals, s_err := big.equals(&backf.smallest, &f.smallest) s_equals, s_err := big.equals(&backf.smallest, &f.smallest)
ev(t, s_err, nil) testing.expect_value(t, s_err, nil)
if !s_equals { if !s_equals {
errorf(t, "smallest: %v does not equal %v", big.itoa(&backf.smallest), big.itoa(&f.smallest)) testing.expectf(t, false, "smallest: %v does not equal %v", big.itoa(&backf.smallest), big.itoa(&f.smallest))
} }
b_equals, b_err := big.equals(&backf.biggest, &f.biggest) b_equals, b_err := big.equals(&backf.biggest, &f.biggest)
ev(t, b_err, nil) testing.expect_value(t, b_err, nil)
if !b_equals { if !b_equals {
errorf(t, "biggest: %v does not equal %v", big.itoa(&backf.biggest), big.itoa(&f.biggest)) testing.expectf(t, false, "biggest: %v does not equal %v", big.itoa(&backf.biggest), big.itoa(&f.biggest))
} }
} }
for _, leak in tracker.allocation_map {
errorf(t, "%v leaked %m\n", leak.location, leak.size)
}
for bad_free in tracker.bad_free_array {
errorf(t, "%v allocation %p was freed badly\n", bad_free.location, bad_free.memory)
}
} }
@(test) @(test)
test_marshalling_maybe :: proc(t: ^testing.T) { test_marshalling_maybe :: proc(t: ^testing.T) {
maybe_test: Maybe(int) = 1 maybe_test: Maybe(int) = 1
data, err := cbor.marshal(maybe_test) data, err := cbor.marshal(maybe_test)
expect_value(t, err, nil) defer delete(data)
testing.expect_value(t, err, nil)
val, derr := cbor.decode(string(data)) val, derr := cbor.decode(string(data))
expect_value(t, derr, nil) testing.expect_value(t, derr, nil)
expect_value(t, cbor.to_diagnostic_format(val), "1") diag := cbor.to_diagnostic_format(val)
testing.expect_value(t, diag, "1")
delete(diag)
maybe_dest: Maybe(int) maybe_dest: Maybe(int)
uerr := cbor.unmarshal(string(data), &maybe_dest) uerr := cbor.unmarshal(string(data), &maybe_dest)
expect_value(t, uerr, nil) testing.expect_value(t, uerr, nil)
expect_value(t, maybe_dest, 1) testing.expect_value(t, maybe_dest, 1)
} }
@(test) @(test)
test_marshalling_nil_maybe :: proc(t: ^testing.T) { test_marshalling_nil_maybe :: proc(t: ^testing.T) {
maybe_test: Maybe(int) maybe_test: Maybe(int)
data, err := cbor.marshal(maybe_test) data, err := cbor.marshal(maybe_test)
expect_value(t, err, nil) defer delete(data)
testing.expect_value(t, err, nil)
val, derr := cbor.decode(string(data)) val, derr := cbor.decode(string(data))
expect_value(t, derr, nil) testing.expect_value(t, derr, nil)
expect_value(t, cbor.to_diagnostic_format(val), "nil") diag := cbor.to_diagnostic_format(val)
testing.expect_value(t, diag, "nil")
delete(diag)
maybe_dest: Maybe(int) maybe_dest: Maybe(int)
uerr := cbor.unmarshal(string(data), &maybe_dest) uerr := cbor.unmarshal(string(data), &maybe_dest)
expect_value(t, uerr, nil) testing.expect_value(t, uerr, nil)
expect_value(t, maybe_dest, nil) testing.expect_value(t, maybe_dest, nil)
} }
@(test) @(test)
@@ -427,17 +327,24 @@ test_marshalling_union :: proc(t: ^testing.T) {
{ {
test: My_Union = My_Distinct("Hello, World!") test: My_Union = My_Distinct("Hello, World!")
data, err := cbor.marshal(test) data, err := cbor.marshal(test)
expect_value(t, err, nil) defer delete(data)
testing.expect_value(t, err, nil)
val, derr := cbor.decode(string(data)) val, derr := cbor.decode(string(data))
expect_value(t, derr, nil) defer cbor.destroy(val)
testing.expect_value(t, derr, nil)
expect_value(t, cbor.to_diagnostic_format(val, -1), `1010(["My_Distinct", "Hello, World!"])`) diag := cbor.to_diagnostic_format(val, -1)
defer delete(diag)
testing.expect_value(t, diag, `1010(["My_Distinct", "Hello, World!"])`)
dest: My_Union dest: My_Union
uerr := cbor.unmarshal(string(data), &dest) uerr := cbor.unmarshal(string(data), &dest)
expect_value(t, uerr, nil) testing.expect_value(t, uerr, nil)
expect_value(t, dest, My_Distinct("Hello, World!")) testing.expect_value(t, dest, My_Distinct("Hello, World!"))
if str, ok := dest.(My_Distinct); ok {
delete(string(str))
}
} }
My_Union_No_Nil :: union #no_nil { My_Union_No_Nil :: union #no_nil {
@@ -450,17 +357,21 @@ test_marshalling_union :: proc(t: ^testing.T) {
{ {
test: My_Union_No_Nil = My_Struct{.Two} test: My_Union_No_Nil = My_Struct{.Two}
data, err := cbor.marshal(test) data, err := cbor.marshal(test)
expect_value(t, err, nil) defer delete(data)
testing.expect_value(t, err, nil)
val, derr := cbor.decode(string(data)) val, derr := cbor.decode(string(data))
expect_value(t, derr, nil) defer cbor.destroy(val)
testing.expect_value(t, derr, nil)
expect_value(t, cbor.to_diagnostic_format(val, -1), `1010(["My_Struct", {"my_enum": 1}])`) diag := cbor.to_diagnostic_format(val, -1)
defer delete(diag)
testing.expect_value(t, diag, `1010(["My_Struct", {"my_enum": 1}])`)
dest: My_Union_No_Nil dest: My_Union_No_Nil
uerr := cbor.unmarshal(string(data), &dest) uerr := cbor.unmarshal(string(data), &dest)
expect_value(t, uerr, nil) testing.expect_value(t, uerr, nil)
expect_value(t, dest, My_Struct{.Two}) testing.expect_value(t, dest, My_Struct{.Two})
} }
} }
@@ -469,7 +380,7 @@ test_lying_length_array :: proc(t: ^testing.T) {
// Input says this is an array of length max(u64), this should not allocate that amount. // Input says this is an array of length max(u64), this should not allocate that amount.
input := []byte{0x9B, 0x00, 0x00, 0x42, 0xFA, 0x42, 0xFA, 0x42, 0xFA, 0x42} input := []byte{0x9B, 0x00, 0x00, 0x42, 0xFA, 0x42, 0xFA, 0x42, 0xFA, 0x42}
_, err := cbor.decode(string(input)) _, err := cbor.decode(string(input))
expect_value(t, err, io.Error.Unexpected_EOF) // .Out_Of_Memory would be bad. testing.expect_value(t, err, io.Error.Unexpected_EOF) // .Out_Of_Memory would be bad.
} }
@(test) @(test)
@@ -691,65 +602,73 @@ test_encode_lists :: proc(t: ^testing.T) {
expect_streamed_encoding(t, "\x9f\xff", &cbor.Array{}) expect_streamed_encoding(t, "\x9f\xff", &cbor.Array{})
{ {
bytes.buffer_reset(&buf) buf: bytes.Buffer
bytes.buffer_init_allocator(&buf, 0, 0)
defer bytes.buffer_destroy(&buf)
stream := bytes.buffer_to_stream(&buf)
encoder := cbor.Encoder{cbor.ENCODE_FULLY_DETERMINISTIC, stream, {}}
err: cbor.Encode_Error err: cbor.Encode_Error
err = cbor.encode_stream_begin(stream, .Array) err = cbor.encode_stream_begin(stream, .Array)
expect_value(t, err, nil) testing.expect_value(t, err, nil)
{ {
err = cbor.encode_stream_array_item(encoder, u8(1)) err = cbor.encode_stream_array_item(encoder, u8(1))
expect_value(t, err, nil) testing.expect_value(t, err, nil)
err = cbor.encode_stream_array_item(encoder, &cbor.Array{u8(2), u8(3)}) err = cbor.encode_stream_array_item(encoder, &cbor.Array{u8(2), u8(3)})
expect_value(t, err, nil) testing.expect_value(t, err, nil)
err = cbor.encode_stream_begin(stream, .Array) err = cbor.encode_stream_begin(stream, .Array)
expect_value(t, err, nil) testing.expect_value(t, err, nil)
{ {
err = cbor.encode_stream_array_item(encoder, u8(4)) err = cbor.encode_stream_array_item(encoder, u8(4))
expect_value(t, err, nil) testing.expect_value(t, err, nil)
err = cbor.encode_stream_array_item(encoder, u8(5)) err = cbor.encode_stream_array_item(encoder, u8(5))
expect_value(t, err, nil) testing.expect_value(t, err, nil)
} }
err = cbor.encode_stream_end(stream) err = cbor.encode_stream_end(stream)
expect_value(t, err, nil) testing.expect_value(t, err, nil)
} }
err = cbor.encode_stream_end(stream) err = cbor.encode_stream_end(stream)
expect_value(t, err, nil) testing.expect_value(t, err, nil)
expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)string("\x9f\x01\x82\x02\x03\x9f\x04\x05\xff\xff"))) testing.expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)string("\x9f\x01\x82\x02\x03\x9f\x04\x05\xff\xff")))
} }
{ {
bytes.buffer_reset(&buf) buf: bytes.Buffer
bytes.buffer_init_allocator(&buf, 0, 0)
defer bytes.buffer_destroy(&buf)
stream := bytes.buffer_to_stream(&buf)
encoder := cbor.Encoder{cbor.ENCODE_FULLY_DETERMINISTIC, stream, {}}
err: cbor.Encode_Error err: cbor.Encode_Error
err = cbor._encode_u8(stream, 2, .Array) err = cbor._encode_u8(stream, 2, .Array)
expect_value(t, err, nil) testing.expect_value(t, err, nil)
a := "a" a := "a"
err = cbor.encode(encoder, &a) err = cbor.encode(encoder, &a)
expect_value(t, err, nil) testing.expect_value(t, err, nil)
{ {
err = cbor.encode_stream_begin(stream, .Map) err = cbor.encode_stream_begin(stream, .Map)
expect_value(t, err, nil) testing.expect_value(t, err, nil)
b := "b" b := "b"
c := "c" c := "c"
err = cbor.encode_stream_map_entry(encoder, &b, &c) err = cbor.encode_stream_map_entry(encoder, &b, &c)
expect_value(t, err, nil) testing.expect_value(t, err, nil)
err = cbor.encode_stream_end(stream) err = cbor.encode_stream_end(stream)
expect_value(t, err, nil) testing.expect_value(t, err, nil)
} }
expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)string("\x82\x61\x61\xbf\x61\x62\x61\x63\xff"))) testing.expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)string("\x82\x61\x61\xbf\x61\x62\x61\x63\xff")))
} }
} }
@@ -807,30 +726,30 @@ expect_decoding :: proc(t: ^testing.T, encoded: string, decoded: string, type: t
res, err := cbor.decode(encoded) res, err := cbor.decode(encoded)
defer cbor.destroy(res) defer cbor.destroy(res)
expect_value(t, reflect.union_variant_typeid(res), type, loc) testing.expect_value(t, reflect.union_variant_typeid(res), type, loc)
expect_value(t, err, nil, loc) testing.expect_value(t, err, nil, loc)
str := cbor.to_diagnostic_format(res, padding=-1) str := cbor.to_diagnostic_format(res, padding=-1)
defer delete(str) defer delete(str)
expect_value(t, str, decoded, loc) testing.expect_value(t, str, decoded, loc)
} }
expect_tag :: proc(t: ^testing.T, encoded: string, nr: cbor.Tag_Number, value_decoded: string, loc := #caller_location) { expect_tag :: proc(t: ^testing.T, encoded: string, nr: cbor.Tag_Number, value_decoded: string, loc := #caller_location) {
res, err := cbor.decode(encoded) res, err := cbor.decode(encoded)
defer cbor.destroy(res) defer cbor.destroy(res)
expect_value(t, err, nil, loc) testing.expect_value(t, err, nil, loc)
if tag, is_tag := res.(^cbor.Tag); is_tag { if tag, is_tag := res.(^cbor.Tag); is_tag {
expect_value(t, tag.number, nr, loc) testing.expect_value(t, tag.number, nr, loc)
str := cbor.to_diagnostic_format(tag, padding=-1) str := cbor.to_diagnostic_format(tag, padding=-1)
defer delete(str) defer delete(str)
expect_value(t, str, value_decoded, loc) testing.expect_value(t, str, value_decoded, loc)
} else { } else {
errorf(t, "Value %#v is not a tag", res, loc) testing.expectf(t, false, "Value %#v is not a tag", res, loc)
} }
} }
@@ -838,35 +757,39 @@ expect_float :: proc(t: ^testing.T, encoded: string, expected: $T, loc := #calle
res, err := cbor.decode(encoded) res, err := cbor.decode(encoded)
defer cbor.destroy(res) defer cbor.destroy(res)
expect_value(t, reflect.union_variant_typeid(res), typeid_of(T), loc) testing.expect_value(t, reflect.union_variant_typeid(res), typeid_of(T), loc)
expect_value(t, err, nil, loc) testing.expect_value(t, err, nil, loc)
#partial switch r in res { #partial switch r in res {
case f16: case f16:
when T == f16 { expect_value(t, res, expected, loc) } else { unreachable() } when T == f16 { testing.expect_value(t, res, expected, loc) } else { unreachable() }
case f32: case f32:
when T == f32 { expect_value(t, res, expected, loc) } else { unreachable() } when T == f32 { testing.expect_value(t, res, expected, loc) } else { unreachable() }
case f64: case f64:
when T == f64 { expect_value(t, res, expected, loc) } else { unreachable() } when T == f64 { testing.expect_value(t, res, expected, loc) } else { unreachable() }
case: case:
unreachable() unreachable()
} }
} }
buf: bytes.Buffer
stream := bytes.buffer_to_stream(&buf)
encoder := cbor.Encoder{cbor.ENCODE_FULLY_DETERMINISTIC, stream, {}}
expect_encoding :: proc(t: ^testing.T, val: cbor.Value, encoded: string, loc := #caller_location) { expect_encoding :: proc(t: ^testing.T, val: cbor.Value, encoded: string, loc := #caller_location) {
bytes.buffer_reset(&buf) buf: bytes.Buffer
bytes.buffer_init_allocator(&buf, 0, 0)
defer bytes.buffer_destroy(&buf)
stream := bytes.buffer_to_stream(&buf)
encoder := cbor.Encoder{cbor.ENCODE_FULLY_DETERMINISTIC, stream, {}}
err := cbor.encode(encoder, val) err := cbor.encode(encoder, val, loc)
expect_value(t, err, nil, loc) testing.expect_value(t, err, nil, loc)
expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)encoded), loc) testing.expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)encoded), loc)
} }
expect_streamed_encoding :: proc(t: ^testing.T, encoded: string, values: ..cbor.Value, loc := #caller_location) { expect_streamed_encoding :: proc(t: ^testing.T, encoded: string, values: ..cbor.Value, loc := #caller_location) {
bytes.buffer_reset(&buf) buf: bytes.Buffer
bytes.buffer_init_allocator(&buf, 0, 0)
defer bytes.buffer_destroy(&buf)
stream := bytes.buffer_to_stream(&buf)
encoder := cbor.Encoder{cbor.ENCODE_FULLY_DETERMINISTIC, stream, {}}
for value, i in values { for value, i in values {
err: cbor.Encode_Error err: cbor.Encode_Error
@@ -891,15 +814,15 @@ expect_streamed_encoding :: proc(t: ^testing.T, encoded: string, values: ..cbor.
if err2 != nil { break } if err2 != nil { break }
} }
case: case:
errorf(t, "%v does not support streamed encoding", reflect.union_variant_typeid(value)) testing.expectf(t, false, "%v does not support streamed encoding", reflect.union_variant_typeid(value))
} }
expect_value(t, err, nil, loc) testing.expect_value(t, err, nil, loc)
expect_value(t, err2, nil, loc) testing.expect_value(t, err2, nil, loc)
} }
err := cbor.encode_stream_end(stream) err := cbor.encode_stream_end(stream)
expect_value(t, err, nil, loc) testing.expect_value(t, err, nil, loc)
expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)encoded), loc) testing.expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)encoded), loc)
} }