std.json: Fix parsing of large numbers
Numbers greater than about 2^53 are encoded as strings in JSON. std.json.parseInternal previously errored out in this condition.
This commit is contained in:
parent
a8bfddfaea
commit
889efddd1a
|
@ -1422,23 +1422,37 @@ fn parseInternal(
|
|||
};
|
||||
},
|
||||
.Float, .ComptimeFloat => {
|
||||
const numberToken = switch (token) {
|
||||
.Number => |n| n,
|
||||
switch (token) {
|
||||
.Number => |numberToken| return try std.fmt.parseFloat(T, numberToken.slice(tokens.slice, tokens.i - 1)),
|
||||
.String => |stringToken| return try std.fmt.parseFloat(T, stringToken.slice(tokens.slice, tokens.i - 1)),
|
||||
else => return error.UnexpectedToken,
|
||||
};
|
||||
return try std.fmt.parseFloat(T, numberToken.slice(tokens.slice, tokens.i - 1));
|
||||
}
|
||||
},
|
||||
.Int, .ComptimeInt => {
|
||||
const numberToken = switch (token) {
|
||||
.Number => |n| n,
|
||||
switch (token) {
|
||||
.Number => |numberToken| {
|
||||
if (numberToken.is_integer)
|
||||
return try std.fmt.parseInt(T, numberToken.slice(tokens.slice, tokens.i - 1), 10);
|
||||
const float = try std.fmt.parseFloat(f128, numberToken.slice(tokens.slice, tokens.i - 1));
|
||||
if (@round(float) != float) return error.InvalidNumber;
|
||||
if (float > std.math.maxInt(T) or float < std.math.minInt(T)) return error.Overflow;
|
||||
return @floatToInt(T, float);
|
||||
},
|
||||
.String => |stringToken| {
|
||||
return std.fmt.parseInt(T, stringToken.slice(tokens.slice, tokens.i - 1), 10) catch |err| {
|
||||
switch (err) {
|
||||
error.Overflow => return err,
|
||||
error.InvalidCharacter => {
|
||||
const float = try std.fmt.parseFloat(f128, stringToken.slice(tokens.slice, tokens.i - 1));
|
||||
if (@round(float) != float) return error.InvalidNumber;
|
||||
if (float > std.math.maxInt(T) or float < std.math.minInt(T)) return error.Overflow;
|
||||
return @floatToInt(T, float);
|
||||
},
|
||||
}
|
||||
};
|
||||
},
|
||||
else => return error.UnexpectedToken,
|
||||
};
|
||||
if (numberToken.is_integer)
|
||||
return try std.fmt.parseInt(T, numberToken.slice(tokens.slice, tokens.i - 1), 10);
|
||||
const float = try std.fmt.parseFloat(f128, numberToken.slice(tokens.slice, tokens.i - 1));
|
||||
if (@round(float) != float) return error.InvalidNumber;
|
||||
if (float > std.math.maxInt(T) or float < std.math.minInt(T)) return error.Overflow;
|
||||
return @floatToInt(T, float);
|
||||
}
|
||||
},
|
||||
.Optional => |optionalInfo| {
|
||||
if (token == .Null) {
|
||||
|
|
|
@ -2046,6 +2046,11 @@ test "parse" {
|
|||
try testing.expectEqual(@as([3]u8, "foo".*), try parse([3]u8, &ts, ParseOptions{}));
|
||||
ts = TokenStream.init("[]");
|
||||
try testing.expectEqual(@as([0]u8, undefined), try parse([0]u8, &ts, ParseOptions{}));
|
||||
|
||||
ts = TokenStream.init("\"12345678901234567890\"");
|
||||
try testing.expectEqual(@as(u64, 12345678901234567890), try parse(u64, &ts, ParseOptions{}));
|
||||
ts = TokenStream.init("\"123.456\"");
|
||||
try testing.expectEqual(@as(f64, 123.456), try parse(f64, &ts, ParseOptions{}));
|
||||
}
|
||||
|
||||
test "parse into enum" {
|
||||
|
|
Loading…
Reference in New Issue
Block a user