mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
encoding/cbor: make temp allocations more explicit
This commit is contained in:
@@ -26,9 +26,6 @@ Encoder_Flag :: enum {
|
|||||||
// NOTE: In order to do this, all keys of a map have to be pre-computed, sorted, and
|
// NOTE: In order to do this, all keys of a map have to be pre-computed, sorted, and
|
||||||
// then written, this involves temporary allocations for the keys and a copy of the map itself.
|
// then written, this involves temporary allocations for the keys and a copy of the map itself.
|
||||||
Deterministic_Map_Sorting,
|
Deterministic_Map_Sorting,
|
||||||
|
|
||||||
// Internal flag to do initialization.
|
|
||||||
_In_Progress,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Encoder_Flags :: bit_set[Encoder_Flag]
|
Encoder_Flags :: bit_set[Encoder_Flag]
|
||||||
@@ -40,8 +37,9 @@ ENCODE_FULLY_DETERMINISTIC :: Encoder_Flags{.Deterministic_Int_Size, .Determinis
|
|||||||
ENCODE_SMALL :: Encoder_Flags{.Deterministic_Int_Size, .Deterministic_Float_Size}
|
ENCODE_SMALL :: Encoder_Flags{.Deterministic_Int_Size, .Deterministic_Float_Size}
|
||||||
|
|
||||||
Encoder :: struct {
|
Encoder :: struct {
|
||||||
flags: Encoder_Flags,
|
flags: Encoder_Flags,
|
||||||
writer: io.Writer,
|
writer: io.Writer,
|
||||||
|
temp_allocator: runtime.Allocator,
|
||||||
}
|
}
|
||||||
|
|
||||||
Decoder_Flag :: enum {
|
Decoder_Flag :: enum {
|
||||||
@@ -56,9 +54,6 @@ Decoder_Flag :: enum {
|
|||||||
|
|
||||||
// Makes the decoder shrink of excess capacity from allocated buffers/containers before returning.
|
// Makes the decoder shrink of excess capacity from allocated buffers/containers before returning.
|
||||||
Shrink_Excess,
|
Shrink_Excess,
|
||||||
|
|
||||||
// Internal flag to do initialization.
|
|
||||||
_In_Progress,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Decoder_Flags :: bit_set[Decoder_Flag]
|
Decoder_Flags :: bit_set[Decoder_Flag]
|
||||||
@@ -122,7 +117,9 @@ decode_from_decoder :: proc(d: Decoder, allocator := context.allocator) -> (v: V
|
|||||||
|
|
||||||
d := d
|
d := d
|
||||||
|
|
||||||
_DECODE_PROGRESS_GUARD(&d)
|
if d.max_pre_alloc <= 0 {
|
||||||
|
d.max_pre_alloc = DEFAULT_MAX_PRE_ALLOC
|
||||||
|
}
|
||||||
|
|
||||||
v, err = _decode_from_decoder(d)
|
v, err = _decode_from_decoder(d)
|
||||||
// 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.
|
||||||
@@ -191,7 +188,7 @@ have to be precomputed, sorted and only then written to the output.
|
|||||||
|
|
||||||
Empty flags will do nothing extra to the value.
|
Empty flags will do nothing extra to the value.
|
||||||
|
|
||||||
The allocations for the `.Deterministic_Map_Sorting` flag are done using the `context.temp_allocator`
|
The allocations for the `.Deterministic_Map_Sorting` flag are done using the given temp_allocator.
|
||||||
but are followed by the necessary `delete` and `free` calls if the allocator supports them.
|
but are followed by the necessary `delete` and `free` calls if the allocator supports them.
|
||||||
This is helpful when the CBOR size is so big that you don't want to collect all the temporary
|
This is helpful when the CBOR size is so big that you don't want to collect all the temporary
|
||||||
allocations until the end.
|
allocations until the end.
|
||||||
@@ -206,22 +203,22 @@ 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) -> (data: []byte, err: Encode_Error) {
|
encode_into_bytes :: proc(v: Value, flags := ENCODE_SMALL, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (data: []byte, err: Encode_Error) {
|
||||||
b := strings.builder_make(allocator) or_return
|
b := strings.builder_make(allocator) or_return
|
||||||
encode_into_builder(&b, v, flags) 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) -> Encode_Error {
|
encode_into_builder :: proc(b: ^strings.Builder, v: Value, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Encode_Error {
|
||||||
return encode_into_writer(strings.to_stream(b), v, flags)
|
return encode_into_writer(strings.to_stream(b), v, flags, temp_allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) -> Encode_Error {
|
encode_into_writer :: proc(w: io.Writer, v: Value, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Encode_Error {
|
||||||
return encode_into_encoder(Encoder{flags, w}, v)
|
return encode_into_encoder(Encoder{flags, w, temp_allocator}, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encodes the CBOR value into binary CBOR written to the given encoder.
|
// Encodes the CBOR value into binary CBOR written to the given encoder.
|
||||||
@@ -229,8 +226,15 @@ encode_into_writer :: proc(w: io.Writer, v: Value, flags := ENCODE_SMALL) -> Enc
|
|||||||
encode_into_encoder :: proc(e: Encoder, v: Value) -> Encode_Error {
|
encode_into_encoder :: proc(e: Encoder, v: Value) -> Encode_Error {
|
||||||
e := e
|
e := e
|
||||||
|
|
||||||
_ENCODE_PROGRESS_GUARD(&e) or_return
|
if e.temp_allocator.procedure == nil {
|
||||||
|
e.temp_allocator = context.temp_allocator
|
||||||
|
}
|
||||||
|
|
||||||
|
if .Self_Described_CBOR in e.flags {
|
||||||
|
_encode_u64(e, TAG_SELF_DESCRIBED_CBOR, .Tag) or_return
|
||||||
|
e.flags &~= { .Self_Described_CBOR }
|
||||||
|
}
|
||||||
|
|
||||||
switch v_spec in v {
|
switch v_spec in v {
|
||||||
case u8: return _encode_u8(e.writer, v_spec, .Unsigned)
|
case u8: return _encode_u8(e.writer, v_spec, .Unsigned)
|
||||||
case u16: return _encode_u16(e, v_spec, .Unsigned)
|
case u16: return _encode_u16(e, v_spec, .Unsigned)
|
||||||
@@ -256,66 +260,6 @@ encode_into_encoder :: proc(e: Encoder, v: Value) -> Encode_Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@(deferred_in_out=_decode_progress_end)
|
|
||||||
_DECODE_PROGRESS_GUARD :: proc(d: ^Decoder) -> (is_begin: bool, tmp: runtime.Arena_Temp) {
|
|
||||||
if ._In_Progress in d.flags {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
is_begin = true
|
|
||||||
|
|
||||||
d.flags |= { ._In_Progress }
|
|
||||||
|
|
||||||
if context.allocator != context.temp_allocator {
|
|
||||||
tmp = runtime.default_temp_allocator_temp_begin()
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.max_pre_alloc <= 0 {
|
|
||||||
d.max_pre_alloc = DEFAULT_MAX_PRE_ALLOC
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_decode_progress_end :: proc(d: ^Decoder, is_begin: bool, tmp: runtime.Arena_Temp) {
|
|
||||||
if !is_begin {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
d.flags &~= { ._In_Progress }
|
|
||||||
|
|
||||||
runtime.default_temp_allocator_temp_end(tmp)
|
|
||||||
}
|
|
||||||
|
|
||||||
@(deferred_in_out=_encode_progress_end)
|
|
||||||
_ENCODE_PROGRESS_GUARD :: proc(e: ^Encoder) -> (is_begin: bool, tmp: runtime.Arena_Temp, err: Encode_Error) {
|
|
||||||
if ._In_Progress in e.flags {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
is_begin = true
|
|
||||||
|
|
||||||
e.flags |= { ._In_Progress }
|
|
||||||
|
|
||||||
if context.allocator != context.temp_allocator {
|
|
||||||
tmp = runtime.default_temp_allocator_temp_begin()
|
|
||||||
}
|
|
||||||
|
|
||||||
if .Self_Described_CBOR in e.flags {
|
|
||||||
_encode_u64(e^, TAG_SELF_DESCRIBED_CBOR, .Tag) or_return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_encode_progress_end :: proc(e: ^Encoder, is_begin: bool, tmp: runtime.Arena_Temp, err: Encode_Error) {
|
|
||||||
if !is_begin || err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
e.flags &~= { ._In_Progress }
|
|
||||||
|
|
||||||
runtime.default_temp_allocator_temp_end(tmp)
|
|
||||||
}
|
|
||||||
|
|
||||||
_decode_header :: proc(r: io.Reader) -> (hdr: Header, err: io.Error) {
|
_decode_header :: proc(r: io.Reader) -> (hdr: Header, err: io.Error) {
|
||||||
hdr = Header(_decode_u8(r) or_return)
|
hdr = Header(_decode_u8(r) or_return)
|
||||||
return
|
return
|
||||||
@@ -602,13 +546,13 @@ _encode_map :: proc(e: Encoder, m: Map) -> (err: Encode_Error) {
|
|||||||
entry: Map_Entry,
|
entry: Map_Entry,
|
||||||
}
|
}
|
||||||
|
|
||||||
entries := make([]Map_Entry_With_Key, len(m), context.temp_allocator) or_return
|
entries := make([]Map_Entry_With_Key, len(m), e.temp_allocator) or_return
|
||||||
defer delete(entries, context.temp_allocator)
|
defer delete(entries, e.temp_allocator)
|
||||||
|
|
||||||
for &entry, i in entries {
|
for &entry, i in entries {
|
||||||
entry.entry = m[i]
|
entry.entry = m[i]
|
||||||
|
|
||||||
buf := strings.builder_make(context.temp_allocator) or_return
|
buf := strings.builder_make(e.temp_allocator) or_return
|
||||||
|
|
||||||
ke := e
|
ke := e
|
||||||
ke.writer = strings.to_stream(&buf)
|
ke.writer = strings.to_stream(&buf)
|
||||||
@@ -624,7 +568,7 @@ _encode_map :: proc(e: Encoder, m: Map) -> (err: Encode_Error) {
|
|||||||
|
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
io.write_full(e.writer, entry.encoded_key) or_return
|
io.write_full(e.writer, entry.encoded_key) or_return
|
||||||
delete(entry.encoded_key, context.temp_allocator)
|
delete(entry.encoded_key, e.temp_allocator)
|
||||||
|
|
||||||
encode(e, entry.entry.value) or_return
|
encode(e, entry.entry.value) or_return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,21 @@ Also provided are conversion to and from JSON and the CBOR diagnostic format.
|
|||||||
|
|
||||||
**Allocations:**
|
**Allocations:**
|
||||||
|
|
||||||
In general, when in the following table it says allocations are done on the `context.temp_allocator`, these allocations
|
In general, when in the following table it says allocations are done on the `temp_allocator`, these allocations
|
||||||
are still attempted to be deallocated.
|
are still attempted to be deallocated.
|
||||||
This allows you to use an allocator with freeing implemented as the `context.temp_allocator` which is handy with big CBOR.
|
This allows you to use an allocator with freeing implemented as the `temp_allocator` which is handy with big CBOR.
|
||||||
|
|
||||||
If you use the default `context.temp_allocator` it will be returned back to its state when the process (en/decoding, (un)marshal) started.
|
- *Encoding*: If the `.Deterministic_Map_Sorting` flag is set on the encoder, this allocates on the given `temp_allocator`
|
||||||
|
|
||||||
- *Encoding*: If the `.Deterministic_Map_Sorting` flag is set on the encoder, this allocates on `context.temp_allocator`
|
|
||||||
some space for the keys of maps in order to sort them and then write them.
|
some space for the keys of maps in order to sort them and then write them.
|
||||||
Other than that there are no allocations (only for the final bytes if you use `cbor.encode_into_bytes`.
|
Other than that there are no allocations (only for the final bytes if you use `cbor.encode_into_bytes`.
|
||||||
|
|
||||||
- *Decoding*: Allocates everything on the given allocator and input given can be deleted after decoding.
|
- *Decoding*: Allocates everything on the given allocator and input given can be deleted after decoding.
|
||||||
*No* allocations are done on the `context.temp_allocator`.
|
*No* temporary allocations are done.
|
||||||
|
|
||||||
- *Marshal*: Same allocation strategy as encoding.
|
- *Marshal*: Same allocation strategy as encoding.
|
||||||
|
|
||||||
- *Unmarshal*: Allocates everything on the given allocator and input given can be deleted after unmarshalling.
|
- *Unmarshal*: Allocates everything on the given allocator and input given can be deleted after unmarshalling.
|
||||||
Some temporary allocations are done on the `context.temp_allocator`.
|
Some temporary allocations are done on the given `temp_allocator`.
|
||||||
|
|
||||||
**Determinism:**
|
**Determinism:**
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ have to be precomputed, sorted and only then written to the output.
|
|||||||
|
|
||||||
Empty flags will do nothing extra to the value.
|
Empty flags will do nothing extra to the value.
|
||||||
|
|
||||||
The allocations for the `.Deterministic_Map_Sorting` flag are done using the `context.temp_allocator`
|
The allocations for the `.Deterministic_Map_Sorting` flag are done using the given `temp_allocator`.
|
||||||
but are followed by the necessary `delete` and `free` calls if the allocator supports them.
|
but are followed by the necessary `delete` and `free` calls if the allocator supports them.
|
||||||
This is helpful when the CBOR size is so big that you don't want to collect all the temporary
|
This is helpful when the CBOR size is so big that you don't want to collect all the temporary
|
||||||
allocations until the end.
|
allocations until the end.
|
||||||
@@ -45,7 +45,7 @@ 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) -> (bytes: []byte, err: Marshal_Error) {
|
marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (bytes: []byte, err: Marshal_Error) {
|
||||||
b, alloc_err := strings.builder_make(allocator)
|
b, alloc_err := strings.builder_make(allocator)
|
||||||
// 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 {
|
||||||
@@ -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); err != nil {
|
if err = marshal_into_builder(&b, v, flags, temp_allocator); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,14 +63,14 @@ 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) -> Marshal_Error {
|
marshal_into_builder :: proc(b: ^strings.Builder, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Marshal_Error {
|
||||||
return marshal_into_writer(strings.to_writer(b), v, flags)
|
return marshal_into_writer(strings.to_writer(b), v, flags, temp_allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) -> Marshal_Error {
|
marshal_into_writer :: proc(w: io.Writer, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Marshal_Error {
|
||||||
encoder := Encoder{flags, w}
|
encoder := Encoder{flags, w, temp_allocator}
|
||||||
return marshal_into_encoder(encoder, v)
|
return marshal_into_encoder(encoder, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +79,14 @@ marshal_into_writer :: proc(w: io.Writer, v: any, flags := ENCODE_SMALL) -> Mars
|
|||||||
marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) {
|
marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) {
|
||||||
e := e
|
e := e
|
||||||
|
|
||||||
err_conv(_ENCODE_PROGRESS_GUARD(&e)) or_return
|
if e.temp_allocator.procedure == nil {
|
||||||
|
e.temp_allocator = context.temp_allocator
|
||||||
|
}
|
||||||
|
|
||||||
|
if .Self_Described_CBOR in e.flags {
|
||||||
|
err_conv(_encode_u64(e, TAG_SELF_DESCRIBED_CBOR, .Tag)) or_return
|
||||||
|
e.flags &~= { .Self_Described_CBOR }
|
||||||
|
}
|
||||||
|
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return _encode_nil(e.writer)
|
return _encode_nil(e.writer)
|
||||||
@@ -321,7 +328,7 @@ marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) {
|
|||||||
|
|
||||||
switch info.key.id {
|
switch info.key.id {
|
||||||
case string:
|
case string:
|
||||||
entries := make([dynamic]Encoded_Entry_Fast(^[]byte), 0, map_cap, context.temp_allocator) or_return
|
entries := make([dynamic]Encoded_Entry_Fast(^[]byte), 0, map_cap, e.temp_allocator) or_return
|
||||||
defer delete(entries)
|
defer delete(entries)
|
||||||
|
|
||||||
for bucket_index in 0..<map_cap {
|
for bucket_index in 0..<map_cap {
|
||||||
@@ -355,7 +362,7 @@ marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) {
|
|||||||
return
|
return
|
||||||
|
|
||||||
case cstring:
|
case cstring:
|
||||||
entries := make([dynamic]Encoded_Entry_Fast(^cstring), 0, map_cap, context.temp_allocator) or_return
|
entries := make([dynamic]Encoded_Entry_Fast(^cstring), 0, map_cap, e.temp_allocator) or_return
|
||||||
defer delete(entries)
|
defer delete(entries)
|
||||||
|
|
||||||
for bucket_index in 0..<map_cap {
|
for bucket_index in 0..<map_cap {
|
||||||
@@ -391,15 +398,15 @@ marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) {
|
|||||||
return
|
return
|
||||||
|
|
||||||
case:
|
case:
|
||||||
entries := make([dynamic]Encoded_Entry, 0, map_cap, context.temp_allocator) or_return
|
entries := make([dynamic]Encoded_Entry, 0, map_cap, e.temp_allocator) or_return
|
||||||
defer delete(entries)
|
defer delete(entries)
|
||||||
|
|
||||||
for bucket_index in 0..<map_cap {
|
for bucket_index in 0..<map_cap {
|
||||||
runtime.map_hash_is_valid(hs[bucket_index]) or_continue
|
runtime.map_hash_is_valid(hs[bucket_index]) or_continue
|
||||||
|
|
||||||
key := rawptr(runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index))
|
key := rawptr(runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index))
|
||||||
key_builder := strings.builder_make(0, 8, context.temp_allocator) or_return
|
key_builder := strings.builder_make(0, 8, e.temp_allocator) or_return
|
||||||
marshal_into(Encoder{e.flags, strings.to_stream(&key_builder)}, any{ key, info.key.id }) or_return
|
marshal_into(Encoder{e.flags, strings.to_stream(&key_builder), e.temp_allocator}, any{ key, info.key.id }) or_return
|
||||||
append(&entries, Encoded_Entry{ &key_builder.buf, bucket_index }) or_return
|
append(&entries, Encoded_Entry{ &key_builder.buf, bucket_index }) or_return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,7 +477,7 @@ marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) {
|
|||||||
name: string,
|
name: string,
|
||||||
field: int,
|
field: int,
|
||||||
}
|
}
|
||||||
entries := make([dynamic]Name, 0, n, context.temp_allocator) or_return
|
entries := make([dynamic]Name, 0, n, e.temp_allocator) or_return
|
||||||
defer delete(entries)
|
defer delete(entries)
|
||||||
|
|
||||||
for name, i in info.names {
|
for name, i in info.names {
|
||||||
@@ -530,7 +537,7 @@ marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) {
|
|||||||
case reflect.Type_Info_Named:
|
case reflect.Type_Info_Named:
|
||||||
err_conv(_encode_text(e, vt.name)) or_return
|
err_conv(_encode_text(e, vt.name)) or_return
|
||||||
case:
|
case:
|
||||||
builder := strings.builder_make(context.temp_allocator) or_return
|
builder := strings.builder_make(e.temp_allocator) or_return
|
||||||
defer strings.builder_destroy(&builder)
|
defer strings.builder_destroy(&builder)
|
||||||
reflect.write_type(&builder, vti)
|
reflect.write_type(&builder, vti)
|
||||||
err_conv(_encode_text(e, strings.to_string(builder))) or_return
|
err_conv(_encode_text(e, strings.to_string(builder))) or_return
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import "core:unicode/utf8"
|
|||||||
Unmarshals the given CBOR into the given pointer using reflection.
|
Unmarshals the given CBOR into the given pointer using reflection.
|
||||||
Types that require allocation are allocated using the given allocator.
|
Types that require allocation are allocated using the given allocator.
|
||||||
|
|
||||||
Some temporary allocations are done on the `context.temp_allocator`, but, if you want to,
|
Some temporary allocations are done on the given `temp_allocator`, but, if you want to,
|
||||||
this can be set to a "normal" allocator, because the necessary `delete` and `free` calls are still made.
|
this can be set to a "normal" allocator, because the necessary `delete` and `free` calls are still made.
|
||||||
This is helpful when the CBOR size is so big that you don't want to collect all the temporary allocations until the end.
|
This is helpful when the CBOR size is so big that you don't want to collect all the temporary allocations until the end.
|
||||||
|
|
||||||
@@ -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) -> (err: Unmarshal_Error) {
|
unmarshal_from_reader :: proc(r: io.Reader, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (err: Unmarshal_Error) {
|
||||||
err = unmarshal_from_decoder(Decoder{ DEFAULT_MAX_PRE_ALLOC, flags, r }, ptr, allocator=allocator)
|
err = unmarshal_from_decoder(Decoder{ DEFAULT_MAX_PRE_ALLOC, flags, r }, ptr, allocator, temp_allocator)
|
||||||
|
|
||||||
// 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,23 +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) -> (err: Unmarshal_Error) {
|
unmarshal_from_string :: proc(s: string, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (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)
|
err = unmarshal_from_reader(r, ptr, flags, allocator, temp_allocator)
|
||||||
|
|
||||||
// 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) -> (err: Unmarshal_Error) {
|
unmarshal_from_decoder :: proc(d: Decoder, ptr: ^$T, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (err: Unmarshal_Error) {
|
||||||
d := d
|
d := d
|
||||||
|
|
||||||
_DECODE_PROGRESS_GUARD(&d)
|
err = _unmarshal_any_ptr(d, ptr, nil, allocator, temp_allocator)
|
||||||
|
|
||||||
err = _unmarshal_any_ptr(d, ptr, allocator=allocator)
|
|
||||||
|
|
||||||
// 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 }
|
||||||
@@ -64,8 +62,9 @@ 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) -> Unmarshal_Error {
|
_unmarshal_any_ptr :: proc(d: Decoder, v: any, hdr: Maybe(Header) = nil, allocator := context.allocator, temp_allocator := context.temp_allocator) -> Unmarshal_Error {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
context.temp_allocator = temp_allocator
|
||||||
v := v
|
v := v
|
||||||
|
|
||||||
if v == nil || v.id == nil {
|
if v == nil || v.id == nil {
|
||||||
|
|||||||
@@ -855,7 +855,7 @@ expect_float :: proc(t: ^testing.T, encoded: string, expected: $T, loc := #calle
|
|||||||
|
|
||||||
buf: bytes.Buffer
|
buf: bytes.Buffer
|
||||||
stream := bytes.buffer_to_stream(&buf)
|
stream := bytes.buffer_to_stream(&buf)
|
||||||
encoder := cbor.Encoder{cbor.ENCODE_FULLY_DETERMINISTIC, stream}
|
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)
|
bytes.buffer_reset(&buf)
|
||||||
|
|||||||
Reference in New Issue
Block a user