///|
fn StringView::parse_int_part(self : StringView) -> Int? {
  Some(@string.parse_int(self)) catch {
    _ => None
  }
}

///|
fn StringView::parse_float_part(self : StringView) -> Float? {
  Some(Float::from_double(@string.parse_double(self))) catch {
    _ => None
  }
}

///|
/// Parse a `used,total` pair in GiB, e.g. `"46.3,128"`.
fn String::parse_memory(self : String) -> Memory? {
  guard self.split_once(",") is Some((used_s, total_s)) else { return None }
  guard used_s.parse_float_part() is Some(used) else { return None }
  guard total_s.parse_float_part() is Some(total) else { return None }
  Some({ used, total })
}

///|
/// Parse a `width,height` pair, e.g. `"3456,2234"`.
fn String::parse_resolution(self : String) -> Resolution? {
  guard self.split_once(",") is Some((width_s, height_s)) else { return None }
  guard width_s.parse_int_part() is Some(width) else { return None }
  guard height_s.parse_int_part() is Some(height) else { return None }
  Some({ width, height })
}

///|
/// Parse an `hours,mins` pair, e.g. `"3,12"`.
fn String::parse_uptime(self : String) -> Uptime? {
  guard self.split_once(",") is Some((hours_s, mins_s)) else { return None }
  guard hours_s.parse_int_part() is Some(hours) else { return None }
  guard mins_s.parse_int_part() is Some(mins) else { return None }
  Some({ hours, mins })
}

///|
/// Parse `name,cores,clock` in GHz, e.g. `"Apple M3 Max,16,4.05"`.
fn String::parse_cpu(self : String) -> Cpu? {
  let parts = self.split(",").to_array()
  guard parts.length() == 3 else { return None }
  guard parts[1].parse_int_part() is Some(cores) else { return None }
  guard parts[2].parse_float_part() is Some(clock) else { return None }
  Some({ name: parts[0].to_owned(), cores, clock })
}

///|
/// Parse `name` or `name,vram` in GB, e.g. `"Apple M3 Max"` or `"RTX 4090,24"`.
fn String::parse_gpu(self : String) -> Gpu? {
  match self.split_once(",") {
    Some((name_s, vram_s)) => {
      guard vram_s.parse_int_part() is Some(vram) else { return None }
      Some({ name: name_s.to_owned(), vram })
    }
    None => Some({ name: self, vram: 0 })
  }
}