///|
pub(all) struct UserInfo {
  github_id : Int64
  login : String
  avatar_url : String
  status : UserStatus
  is_admin : Bool
} derive(Eq)

///|
pub impl ToJson for UserInfo with fn to_json(self) {
  {
    "github_id": Json::number(
      self.github_id.to_double(),
      repr=self.github_id.to_string(),
    ),
    "login": self.login,
    "avatar_url": self.avatar_url,
    "status": self.status,
    "is_admin": self.is_admin,
  }
}

///|
pub impl @json.FromJson for UserInfo with fn from_json(json, path) {
  guard json is Object(fields) else {
    raise JsonDecodeError((path, "expected JSON object"))
  }
  let github_id : Int64 = match fields.get("github_id") {
    Some(Number(n, ..)) => n.to_int64()
    _ => raise JsonDecodeError((path, "missing field 'github_id'"))
  }
  let login : String = match fields.get("login") {
    Some(String(s)) => s
    _ => raise JsonDecodeError((path, "missing field 'login'"))
  }
  let avatar_url : String = match fields.get("avatar_url") {
    Some(String(s)) => s
    _ => raise JsonDecodeError((path, "missing field 'avatar_url'"))
  }
  let status : UserStatus = match fields.get("status") {
    Some(v) => @json.from_json(v, path~)
    _ => raise JsonDecodeError((path, "missing field 'status'"))
  }
  let is_admin : Bool = match fields.get("is_admin") {
    Some(True) => true
    Some(False) => false
    _ => raise JsonDecodeError((path, "missing field 'is_admin'"))
  }
  { github_id, login, avatar_url, status, is_admin }
}