///|
fn decode_pointer_token(token : String) -> String {
let builder = StringBuilder()
for i = 0; i < token.length(); {
if token[i] == '~' && i + 1 < token.length() {
if token[i + 1] == '0' {
builder.write_string("~")
continue i + 2
} else if token[i + 1] == '1' {
builder.write_string("/")
continue i + 2
}
}
builder.write_string(token.unsafe_substring(start=i, end=i + 1))
continue i + 1
} nobreak {
builder.to_string()
}
}
///|
fn parse_index(token : String) -> Int? {
if token.length() == 0 {
None
} else {
for value = 0, i = 0; i < token.length(); {
let ch = token[i]
if ch < '0' || ch > '9' {
continue -1, token.length()
} else {
continue value * 10 + (ch.to_int() - ('0' : UInt16).to_int()), i + 1
}
} nobreak {
if value < 0 {
None
} else {
Some(value)
}
}
}
}
///|
pub fn json_pointer(value : Json, pointer : String) -> Json? {
if pointer == "" {
Some(value)
} else if !pointer.has_prefix("/") {
None
} else {
let parts = pointer[1:]
.split("/")
.map(fn(part) { part.to_owned() })
.to_array()
for current = Some(value), i = 0; i < parts.length(); {
match current {
None => continue None, parts.length()
Some(node) => {
let token = decode_pointer_token(parts[i])
match node {
Object(fields) => continue fields.get(token), i + 1
Array(items) =>
match parse_index(token) {
Some(index) =>
if index >= 0 && index < items.length() {
continue Some(items[index]), i + 1
} else {
continue None, parts.length()
}
None => continue None, parts.length()
}
_ => continue None, parts.length()
}
}
}
} nobreak {
current
}
}
}