///|
priv struct JsonNumberCursor {
values : Array[String]
mut index : Int
}
///|
fn restore_json_number_reprs(value : Json, source : String) -> Json {
let cursor : JsonNumberCursor = {
values: collect_json_number_reprs(source),
index: 0,
}
restore_json_number_reprs_in_value(value, cursor)
}
///|
fn restore_json_number_reprs_in_value(
value : Json,
cursor : JsonNumberCursor,
) -> Json {
match value {
Number(number, ..) => {
let repr = cursor.values[cursor.index]
cursor.index += 1
Json::number(number, repr~)
}
Array(values) =>
Json::array(
values.map(value => restore_json_number_reprs_in_value(value, cursor)),
)
Object(values) => {
let restored : Array[(String, Json)] = []
for key, value in values {
restored.push((key, restore_json_number_reprs_in_value(value, cursor)))
}
Json::object(Map(restored))
}
String(value) => Json::string(value)
True => Json::boolean(true)
False => Json::boolean(false)
Null => Json::null()
}
}
///|
fn collect_json_number_reprs(source : String) -> Array[String] {
let values : Array[String] = []
let mut index = 0
let mut in_string = false
let mut escaped = false
while index < source.length() {
let code = source[index]
if in_string {
if escaped {
escaped = false
} else if code == '\\' {
escaped = true
} else if code == '"' {
in_string = false
}
index += 1
} else if code == '"' {
in_string = true
index += 1
} else if code == '-' || code is ('0'..='9') {
let start = index
index += 1
while index < source.length() && is_json_number_code(source[index]) {
index += 1
}
values.push(source[start:index].to_owned())
} else {
index += 1
}
}
values
}
///|
fn is_json_number_code(code : UInt16) -> Bool {
code is ('0'..='9' | '.' | 'e' | 'E' | '+' | '-')
}