///|
pub fn[T] string_view_find_match(
  view : StringView,
  matcher : (StringView) -> (T, Int)?,
) -> (T, Int, Int)? {
  let mut start = 0
  while start < view.length() {
    let suffix = view.view(start_offset=start)
    match matcher(suffix) {
      Some((tag, len)) if len > 0 && start + len <= view.length() =>
        return Some((tag, start, len))
      _ => start = start + 1
    }
  }
  None
}

///|
pub fn[T] string_view_split_match(
  view : StringView,
  matcher : (StringView) -> (T, Int)?,
  default : T,
) -> Iter[(T, StringView)] {
  let mut remaining = Some(view)
  Iter::new(() => {
    guard remaining is Some(view) else { None }
    guard string_view_find_match(view, matcher)
      is Some((tag, start, delimiter_length)) else {
      remaining = None
      Some((default, view))
    }
    remaining = Some(view.view(start_offset=start + delimiter_length))
    Some((tag, view.view(end_offset=start)))
  })
}