///|
/// Parse a JSON Pointer (RFC 6901) as used by JSON Patch "path"/"from"
/// members: either the empty string (the whole document) or a string
/// beginning with `/`, where `~0` escapes `~` and `~1` escapes `/`.
/// Returns `None` when the pointer is malformed (missing leading `/`,
/// an invalid escape such as `~2`, or a dangling `~`).
fn parse_pointer(pointer : String) -> Array[String]? {
  if pointer == "" {
    return Some([]) // the whole document
  }
  let tokens : Array[String] = []
  let buf = StringBuilder()
  let mut in_escape = false
  let mut started = false
  for c in pointer {
    if !started {
      if c != '/' {
        return None
      }
      started = true
      continue
    }
    if in_escape {
      match c {
        '0' => buf.write_char('~')
        '1' => buf.write_char('/')
        _ => return None // invalid escape
      }
      in_escape = false
    } else if c == '~' {
      in_escape = true
    } else if c == '/' {
      tokens.push(buf.to_string())
      buf.reset()
    } else {
      buf.write_char(c)
    }
  }
  if in_escape {
    return None // dangling '~'
  }
  tokens.push(buf.to_string())
  Some(tokens)
}

///|
/// Render one pointer token back to its escaped form (`~` -> `~0`,
/// `/` -> `~1`), for generating pointers in `diff`.
fn escape_token(token : String) -> String {
  let buf = StringBuilder()
  for c in token {
    if c == '~' {
      buf.write_string("~0")
    } else if c == '/' {
      buf.write_string("~1")
    } else {
      buf.write_char(c)
    }
  }
  buf.to_string()
}

///|
/// Parse a canonical array index (digits only, no leading zeros unless
/// the value is exactly "0"). Indices longer than 9 digits are treated
/// as unresolvable to stay clear of overflow.
fn parse_index(t : String) -> Int? {
  if t.length() == 0 || t.length() > 9 {
    return None
  }
  let mut n = 0
  for c in t {
    guard c >= '0' && c <= '9' else { return None }
    n = n * 10 + (c.to_int() - '0'.to_int())
  }
  if t.length() > 1 && t.get_char(0) == Some('0') {
    return None
  }
  Some(n)
}