diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 34ac71fca..d25758275 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -1,6 +1,7 @@ package json import "core:mem" +import "core:bits" import "core:runtime" import "core:strconv" import "core:strings" @@ -20,7 +21,10 @@ marshal :: proc(v: any, allocator := context.allocator) -> ([]byte, Marshal_Erro strings.destroy_builder(&b); return nil, err; } - + if len(b.buf) == 0 { + strings.destroy_builder(&b); + return nil, err; + } return b.buf[:], err; } @@ -242,7 +246,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error { } case Type_Info_Enum: - return Marshal_Error.Unsupported_Type; + return marshal_arg(b, any{v.data, info.base.id}); case Type_Info_Bit_Field: data: u64 = 0; @@ -273,6 +277,50 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error { write_byte(b, '}'); case Type_Info_Bit_Set: + is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool { + if ti == nil { + return false; + } + ti = runtime.type_info_base(ti); + switch info in ti.variant { + case runtime.Type_Info_Integer: + using runtime.Type_Info_Endianness; + switch info.endianness { + case Platform: return false; + case Little: return ODIN_ENDIAN != "little"; + case Big: return ODIN_ENDIAN != "big"; + } + } + return false; + } + + bit_data: u64; + bit_size := u64(8*ti.size); + + do_byte_swap := is_bit_set_different_endian_to_platform(info.underlying); + + switch bit_size { + case 0: bit_data = 0; + case 8: + x := (^u8)(v.data)^; + bit_data = u64(x); + case 16: + x := (^u16)(v.data)^; + if do_byte_swap do x = bits.byte_swap(x); + bit_data = u64(x); + case 32: + x := (^u32)(v.data)^; + if do_byte_swap do x = bits.byte_swap(x); + bit_data = u64(x); + case 64: + x := (^u64)(v.data)^; + if do_byte_swap do x = bits.byte_swap(x); + bit_data = u64(x); + case: panic("unknown bit_size size"); + } + write_u64(b, bit_data); + + return Marshal_Error.Unsupported_Type; case Type_Info_Opaque: diff --git a/core/encoding/json/parser.odin b/core/encoding/json/parser.odin index aa041ba5e..374f8589f 100644 --- a/core/encoding/json/parser.odin +++ b/core/encoding/json/parser.odin @@ -11,7 +11,7 @@ Parser :: struct { allocator: mem.Allocator, } -make_parser :: proc(data: string, spec := Specification.JSON, allocator := context.allocator) -> Parser { +make_parser :: proc(data: []byte, spec := Specification.JSON, allocator := context.allocator) -> Parser { p: Parser; p.tok = make_tokenizer(data, spec); p.spec = spec; @@ -21,7 +21,7 @@ make_parser :: proc(data: string, spec := Specification.JSON, allocator := conte return p; } -parse :: proc(data: string, spec := Specification.JSON, allocator := context.allocator) -> (Value, Error) { +parse :: proc(data: []byte, spec := Specification.JSON, allocator := context.allocator) -> (Value, Error) { context.allocator = allocator; p := make_parser(data, spec, allocator); diff --git a/core/encoding/json/tokenizer.odin b/core/encoding/json/tokenizer.odin index 3cada4b45..dd1704ba7 100644 --- a/core/encoding/json/tokenizer.odin +++ b/core/encoding/json/tokenizer.odin @@ -35,17 +35,17 @@ Kind :: enum { } Tokenizer :: struct { - using pos: Pos, - data: string, - r: rune, // current rune - w: int, // current rune width in bytes + using pos: Pos, + data: []byte, + r: rune, // current rune + w: int, // current rune width in bytes curr_line_offset: int, - spec: Specification, + spec: Specification, } -make_tokenizer :: proc(data: string, spec := Specification.JSON) -> Tokenizer { +make_tokenizer :: proc(data: []byte, spec := Specification.JSON) -> Tokenizer { t := Tokenizer{pos = {line=1}, data = data, spec = spec}; next_rune(&t); if t.r == utf8.RUNE_BOM { @@ -59,7 +59,7 @@ next_rune :: proc(t: ^Tokenizer) -> rune #no_bounds_check { return utf8.RUNE_EOF; } t.offset += t.w; - t.r, t.w = utf8.decode_rune_in_string(t.data[t.offset:]); + t.r, t.w = utf8.decode_rune(t.data[t.offset:]); t.pos.column = t.offset - t.curr_line_offset; return t.r; } @@ -174,7 +174,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) { skip_alphanum(t); - switch str := t.data[token.offset:t.offset]; str { + switch str := string(t.data[token.offset:t.offset]); str { case "null": token.kind = Kind.Null; case "false": token.kind = Kind.False; case "true": token.kind = Kind.True; @@ -204,7 +204,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) { if t.r == 'I' || t.r == 'N' { skip_alphanum(t); } - switch t.data[token.offset:t.offset] { + switch string(t.data[token.offset:t.offset]) { case "-Infinity": token.kind = Kind.Infinity; case "-NaN": token.kind = Kind.NaN; } @@ -224,7 +224,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) { } skip_digits(t); } - str := t.data[token.offset:t.offset]; + str := string(t.data[token.offset:t.offset]); if !is_valid_number(str, t.spec) { err = Error.Invalid_Number; } @@ -254,7 +254,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) { skip_digits(t); } - str := t.data[token.offset:t.offset]; + str := string(t.data[token.offset:t.offset]); if !is_valid_number(str, t.spec) { err = Error.Invalid_Number; } @@ -284,7 +284,8 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) { } } - if !is_valid_string_literal(t.data[token.offset : t.offset], t.spec) { + str := string(t.data[token.offset : t.offset]); + if !is_valid_string_literal(str, t.spec) { err = Error.Invalid_String; } @@ -323,7 +324,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) { case: err = Error.Illegal_Character; } - token.text = t.data[token.offset : t.offset]; + token.text = string(t.data[token.offset : t.offset]); return; } diff --git a/core/encoding/json/validator.odin b/core/encoding/json/validator.odin index 332716e24..17073f102 100644 --- a/core/encoding/json/validator.odin +++ b/core/encoding/json/validator.odin @@ -3,7 +3,7 @@ package json import "core:mem" // NOTE(bill): is_valid will not check for duplicate keys -is_valid :: proc(data: string, spec := Specification.JSON) -> bool { +is_valid :: proc(data: []byte, spec := Specification.JSON) -> bool { p := make_parser(data, spec, mem.nil_allocator()); if p.spec == Specification.JSON5 { return validate_value(&p); diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 10d4eb2be..c4a535d77 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -739,7 +739,7 @@ enum_value_to_u64 :: proc(ev: runtime.Type_Info_Enum_Value) -> u64 { } fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { - is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info, ) -> bool { + is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool { if ti == nil { return false; }