///|
/// JSON Pointer(RFC 6901)token 转义:`~` → `~0`,`/` → `~1`。
fn escape_pointer_token(t : String) -> String {
let b = StringBuilder()
for c in t {
if c == '~' {
b.write_string("~0")
} else if c == '/' {
b.write_string("~1")
} else {
b.write_char(c)
}
}
b.to_string()
}
///|
fn unescape_pointer_token(t : String) -> String {
let b = StringBuilder()
let mut pending_escape = false
for c in t {
if pending_escape {
if c == '0' {
b.write_char('~')
} else if c == '1' {
b.write_char('/')
} else {
// 非法转义,宽容处理
b.write_char(c)
}
pending_escape = false
} else if c == '~' {
pending_escape = true
} else {
b.write_char(c)
}
}
b.to_string()
}
///|
/// 实例路径渲染为 JSON Pointer;根为空字符串。
fn instance_pointer(path : Array[String]) -> String {
let b = StringBuilder()
for t in path {
b.write_string("/")
b.write_string(escape_pointer_token(t))
}
b.to_string()
}
///|
/// 模式路径渲染为以 `#` 开头的 JSON Pointer 形式。
fn schema_pointer(path : Array[String]) -> String {
let b = StringBuilder()
for i in 0.. Array[String]? {
if pointer == "#" {
return Some([])
}
let chars = pointer.to_array()
if chars.length() < 2 || chars[0] != '#' || chars[1] != '/' {
return None
}
let tokens : Array[String] = []
let cur = StringBuilder()
let mut i = 2
while i < chars.length() {
let c = chars[i]
if c == '/' {
tokens.push(unescape_pointer_token(percent_decode(cur.to_string())))
cur.reset()
} else {
cur.write_char(c)
}
i += 1
}
tokens.push(unescape_pointer_token(percent_decode(cur.to_string())))
Some(tokens)
}
///|
fn hex_val(c : Char) -> Int? {
if c >= '0' && c <= '9' {
Some(c.to_int() - '0'.to_int())
} else if c >= 'a' && c <= 'f' {
Some(c.to_int() - 'a'.to_int() + 10)
} else if c >= 'A' && c <= 'F' {
Some(c.to_int() - 'A'.to_int() + 10)
} else {
None
}
}
///|
/// URI fragment 的百分号解码(`%25` -> `%` 等)。
/// 仅处理 ASCII 范围的字节,非法序列原样保留。
fn percent_decode(t : String) -> String {
let chars = t.to_array()
let b = StringBuilder()
let mut i = 0
let n = chars.length()
while i < n {
let c = chars[i]
if c == '%' && i + 2 < n {
let h = hex_val(chars[i + 1])
let l = hex_val(chars[i + 2])
match (h, l) {
(Some(hh), Some(ll)) =>
match (hh * 16 + ll).to_char() {
Some(decoded) => {
b.write_char(decoded)
i += 3
}
None => {
b.write_char(c)
i += 1
}
}
_ => {
b.write_char(c)
i += 1
}
}
} else {
b.write_char(c)
i += 1
}
}
b.to_string()
}
///|
fn parse_pointer_index(s : String) -> Int? {
let chars = s.to_array()
if chars.length() == 0 {
return None
}
if chars.length() > 1 && chars[0] == '0' {
// 规范要求数组索引不允许前导零
return None
}
let mut v = 0
for i in 0.. '9' {
return None
}
v = v * 10 + (c.to_int() - '0'.to_int())
if v > 100000000 {
return None
}
}
Some(v)
}
///|
/// 按 token 列表在文档中取值。token 已在 `parse_local_ref` 中解码完毕。
fn resolve_pointer(root : Json, tokens : Array[String]) -> Json? {
let mut cur : Json? = Some(root)
for key in tokens {
let next : Json? = match cur {
Some(Object(m)) => m.get(key)
Some(Array(a)) =>
match parse_pointer_index(key) {
Some(i) => if i < a.length() { Some(a[i]) } else { None }
None => None
}
_ => None
}
cur = next
}
cur
}