From 317931a3c5179e10db941157a994c8e89b7080c2 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 23 Dec 2023 19:22:33 +0100 Subject: [PATCH] encoding/cbor: deterministically store bit sets as big endian --- core/encoding/cbor/cbor.odin | 18 ----------------- core/encoding/cbor/marshal.odin | 3 ++- core/encoding/cbor/unmarshal.odin | 13 ++++++------ core/reflect/reflect.odin | 21 ++++++++++++++++++++ tests/core/encoding/cbor/test_core_cbor.odin | 2 +- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/core/encoding/cbor/cbor.odin b/core/encoding/cbor/cbor.odin index 9df4dfa51..3ab493b4b 100644 --- a/core/encoding/cbor/cbor.odin +++ b/core/encoding/cbor/cbor.odin @@ -675,21 +675,3 @@ _i128_to_uint :: proc(v: i128) -> (u: u64, m: Major, err: Encode_Data_Error) { u, err = _u128_to_u64(u128(v)) return } - -@(private) -is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool { - if ti == nil { - return false - } - t := runtime.type_info_base(ti) - #partial switch info in t.variant { - case runtime.Type_Info_Integer: - switch info.endianness { - case .Platform: return false - case .Little: return ODIN_ENDIAN != .Little - case .Big: return ODIN_ENDIAN != .Big - } - } - return false -} - diff --git a/core/encoding/cbor/marshal.odin b/core/encoding/cbor/marshal.odin index deb7ba020..b7c47f252 100644 --- a/core/encoding/cbor/marshal.odin +++ b/core/encoding/cbor/marshal.odin @@ -541,7 +541,8 @@ marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) { return marshal_into(e, any{v.data, info.base.id}) case runtime.Type_Info_Bit_Set: - do_byte_swap := is_bit_set_different_endian_to_platform(info.underlying) + // Store bit_set as big endian just like the protocol. + do_byte_swap := !reflect.bit_set_is_big_endian(v) switch ti.size * 8 { case 0: return _encode_u8(e.writer, 0) diff --git a/core/encoding/cbor/unmarshal.odin b/core/encoding/cbor/unmarshal.odin index 9ad25a38d..98ef06635 100644 --- a/core/encoding/cbor/unmarshal.odin +++ b/core/encoding/cbor/unmarshal.odin @@ -856,12 +856,11 @@ _assign_int :: proc(val: any, i: $T) -> bool { case uintptr: dst = uintptr(i) case: ti := type_info_of(v.id) - do_byte_swap := is_bit_set_different_endian_to_platform(ti) - #partial switch info in ti.variant { - case runtime.Type_Info_Bit_Set: + if _, ok := ti.variant.(runtime.Type_Info_Bit_Set); ok { + do_byte_swap := !reflect.bit_set_is_big_endian(v) switch ti.size * 8 { - case 0: - case 8: + case 0: // no-op. + case 8: x := (^u8)(v.data) x^ = u8(i) case 16: @@ -876,9 +875,9 @@ _assign_int :: proc(val: any, i: $T) -> bool { case: panic("unknown bit_size size") } - case: - return false + return true } + return false } return true } diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index de5dec2e3..de7379ecc 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -934,6 +934,27 @@ set_union_value :: proc(dst: any, value: any) -> bool { panic("expected a union to reflect.set_union_variant_typeid") } +@(require_results) +bit_set_is_big_endian :: proc(value: any, loc := #caller_location) -> bool { + if value == nil { return ODIN_ENDIAN == .Big } + + ti := runtime.type_info_base(type_info_of(value.id)) + if info, ok := ti.variant.(runtime.Type_Info_Bit_Set); ok { + if info.underlying == nil { return ODIN_ENDIAN == .Big } + + underlying_ti := runtime.type_info_base(info.underlying) + if underlying_info, uok := underlying_ti.variant.(runtime.Type_Info_Integer); uok { + switch underlying_info.endianness { + case .Platform: return ODIN_ENDIAN == .Big + case .Little: return false + case .Big: return true + } + } + + return ODIN_ENDIAN == .Big + } + panic("expected a bit_set to reflect.bit_set_is_big_endian", loc) +} @(require_results) diff --git a/tests/core/encoding/cbor/test_core_cbor.odin b/tests/core/encoding/cbor/test_core_cbor.odin index daf31c277..691a0a5ec 100644 --- a/tests/core/encoding/cbor/test_core_cbor.odin +++ b/tests/core/encoding/cbor/test_core_cbor.odin @@ -251,7 +251,7 @@ test_marshalling :: proc(t: ^testing.T) { ], "cstr": "Hellnope", "ennie": 0, - "ennieb": 2, + "ennieb": 512, "iamint": -256, "important": "!", "my_bytes": h'',