| ... | @@ -1002,6 +1002,8 @@ pub const ValueTree = struct { | ... | @@ -1002,6 +1002,8 @@ pub const ValueTree = struct { |
| 1002 | pub const ObjectMap = StringHashMap(Value); | 1002 | pub const ObjectMap = StringHashMap(Value); |
| 1003 | pub const Array = ArrayList(Value); | 1003 | pub const Array = ArrayList(Value); |
| 1004 | | 1004 | |
| | 1005 | /// Represents a JSON value |
| | 1006 | /// Currently only supports numbers that fit into i64 or f64. |
| 1005 | pub const Value = union(enum) { | 1007 | pub const Value = union(enum) { |
| 1006 | Null, | 1008 | Null, |
| 1007 | Bool: bool, | 1009 | Bool: bool, |
| ... | @@ -1270,10 +1272,11 @@ pub const Parser = struct { | ... | @@ -1270,10 +1272,11 @@ pub const Parser = struct { |
| 1270 | } | 1272 | } |
| 1271 | }; | 1273 | }; |
| 1272 | | 1274 | |
| 1273 | /// Unescape a JSON string | 1275 | // Unescape a JSON string |
| 1274 | /// Optimized for arena allocators, uses Allocator.shrink | 1276 | // Only to be used on strings already validated by the parser |
| 1275 | pub fn unescapeStringAlloc(alloc: *Allocator, input: []const u8) ![]u8 { | 1277 | // Optimized for arena allocators, uses Allocator.shrink |
| 1276 | var output = try alloc.alloc(u8, input.len); | 1278 | fn unescapeStringAlloc(alloc: *Allocator, input: []const u8) ![]u8 { |
| | 1279 | const output = try alloc.alloc(u8, input.len); |
| 1277 | errdefer alloc.free(output); | 1280 | errdefer alloc.free(output); |
| 1278 | | 1281 | |
| 1279 | var inIndex: usize = 0; | 1282 | var inIndex: usize = 0; |
| ... | @@ -1281,8 +1284,8 @@ pub fn unescapeStringAlloc(alloc: *Allocator, input: []const u8) ![]u8 { | ... | @@ -1281,8 +1284,8 @@ pub fn unescapeStringAlloc(alloc: *Allocator, input: []const u8) ![]u8 { |
| 1281 | while(inIndex < input.len) { | 1284 | while(inIndex < input.len) { |
| 1282 | if(input[inIndex] == '\\'){ | 1285 | if(input[inIndex] == '\\'){ |
| 1283 | if(input[inIndex + 1] == 'u'){ | 1286 | if(input[inIndex + 1] == 'u'){ |
| 1284 | const codepoint = std.fmt.parseInt(u32, input[inIndex+2 .. inIndex+6], 16) catch return error.InvalidUnicodeHexSymbol; | 1287 | const codepoint = std.fmt.parseInt(u32, input[inIndex+2 .. inIndex+6], 16) catch unreachable; |
| 1285 | outIndex += std.unicode.utf8Encode(codepoint, output[outIndex..]) catch return error.InvalidUnicodeHexSymbol; | 1288 | outIndex += std.unicode.utf8Encode(codepoint, output[outIndex..]) catch unreachable; |
| 1286 | inIndex += 6; | 1289 | inIndex += 6; |
| 1287 | } else { | 1290 | } else { |
| 1288 | output[outIndex] = @as(u8, | 1291 | output[outIndex] = @as(u8, |
| ... | @@ -1295,7 +1298,7 @@ pub fn unescapeStringAlloc(alloc: *Allocator, input: []const u8) ![]u8 { | ... | @@ -1295,7 +1298,7 @@ pub fn unescapeStringAlloc(alloc: *Allocator, input: []const u8) ![]u8 { |
| 1295 | 'f' => 12, | 1298 | 'f' => 12, |
| 1296 | 'b' => 8, | 1299 | 'b' => 8, |
| 1297 | '"' => '"', | 1300 | '"' => '"', |
| 1298 | else => return error.InvalidEscapeCharacter | 1301 | else => unreachable |
| 1299 | } | 1302 | } |
| 1300 | ); | 1303 | ); |
| 1301 | inIndex += 2; | 1304 | inIndex += 2; |
| ... | @@ -1441,13 +1444,13 @@ test "escaped characters" { | ... | @@ -1441,13 +1444,13 @@ test "escaped characters" { |
| 1441 | | 1444 | |
| 1442 | const obj = tree.root.Object; | 1445 | const obj = tree.root.Object; |
| 1443 | | 1446 | |
| 1444 | testing.expect(mem.eql(u8, obj.get("backslash").?.value.String, "\\")); | 1447 | testing.expectEqualSlices(u8, obj.get("backslash").?.value.String, "\\"); |
| 1445 | testing.expect(mem.eql(u8, obj.get("forwardslash").?.value.String, "/")); | 1448 | testing.expectEqualSlices(u8, obj.get("forwardslash").?.value.String, "/"); |
| 1446 | testing.expect(mem.eql(u8, obj.get("newline").?.value.String, "\n")); | 1449 | testing.expectEqualSlices(u8, obj.get("newline").?.value.String, "\n"); |
| 1447 | testing.expect(mem.eql(u8, obj.get("carriagereturn").?.value.String, "\r")); | 1450 | testing.expectEqualSlices(u8, obj.get("carriagereturn").?.value.String, "\r"); |
| 1448 | testing.expect(mem.eql(u8, obj.get("tab").?.value.String, "\t")); | 1451 | testing.expectEqualSlices(u8, obj.get("tab").?.value.String, "\t"); |
| 1449 | testing.expect(mem.eql(u8, obj.get("formfeed").?.value.String, "\x0C")); | 1452 | testing.expectEqualSlices(u8, obj.get("formfeed").?.value.String, "\x0C"); |
| 1450 | testing.expect(mem.eql(u8, obj.get("backspace").?.value.String, "\x08")); | 1453 | testing.expectEqualSlices(u8, obj.get("backspace").?.value.String, "\x08"); |
| 1451 | testing.expect(mem.eql(u8, obj.get("doublequote").?.value.String, "\"")); | 1454 | testing.expectEqualSlices(u8, obj.get("doublequote").?.value.String, "\""); |
| 1452 | testing.expect(mem.eql(u8, obj.get("unicode").?.value.String, "ą")); | 1455 | testing.expectEqualSlices(u8, obj.get("unicode").?.value.String, "ą"); |
| 1453 | } | 1456 | } |