///|
pub(all) struct ObjectReader(Map[String, Json])

///|
pub fn ObjectReader::get(self : ObjectReader, key : String) -> Json? {
  self.0.get(key)
}

///|
pub fn ObjectReader::new(
  json : Json,
  path~ : JsonPath,
) -> ObjectReader raise JsonDecodeError {
  guard json is Object(object) else {
    raise JsonDecodeError(path~, "expected object")
  }
  ObjectReader(object)
}

///|
/// Returns an iterator over the key-value pairs in the JSON object.
///
/// Parameters:
///
/// * `self` : The JSON object to iterate over.
///
/// Returns an `Iter2[String, Json]` that yields each key-value pair in the
/// object, where keys are strings and values are JSON values.
pub fn ObjectReader::iter2(self : ObjectReader) -> Iter2[String, Json] {
  self.0.iter2()
}

///|
/// Extracts and deserializes a nullable field from a JSON object.
///
/// Parameters:
///
/// * `object` : The JSON object to extract the field from.
/// * `key` : The name of the nullable field to extract.
/// * `path` : The current JSON path for error reporting context.
///
/// Returns the deserialized value of type `T` from the specified field if the
/// field is present and not `null`, `None` otherwise.
///
/// Throws an error of type `JsonDecodeError` if the field is present but
/// deserialization fails.
pub fn[T : FromJson] ObjectReader::optional(
  object : ObjectReader,
  key : String,
  path~ : JsonPath,
) -> T? raise JsonDecodeError {
  match object.get(key) {
    None | Some(Null) => None
    Some(value) => Some(from_json(value, path=path.add_key(key)))
  }
}

///|
/// Extracts and deserializes a required field from a JSON object.
///
/// Parameters:
///
/// * `object` : The JSON object to extract the field from.
/// * `key` : The name of the required field to extract.
/// * `path` : The current JSON path for error reporting context.
///
/// Returns the deserialized value of type `T` from the specified field.
///
/// Throws an error of type `JsonDecodeError` if the field is missing from
/// the object or if deserialization fails.
pub fn[T : FromJson] ObjectReader::required(
  object : ObjectReader,
  key : String,
  path~ : JsonPath,
) -> T raise JsonDecodeError {
  match object.get(key) {
    Some(value) => from_json(value, path~)
    None =>
      raise JsonDecodeError(
        path=path.add_key(key),
        "field '\{key}' is required",
      )
  }
}