use mcport::Value;
pub struct Page {
pub cursor: usize,
pub limit: usize,
}
pub fn page(arguments: &Value, default_limit: usize, max_limit: usize) -> Result<Page, String> {
object(arguments)?;
let cursor = usize_value(arguments, "cursor", 0)?;
let limit = usize_value(arguments, "limit", default_limit)?;
if limit == 0 || limit > max_limit {
return Err(format!("limit must be between 1 and {max_limit}"));
}
Ok(Page { cursor, limit })
}
pub fn revision(arguments: &Value, name: &str, default: Option<&str>) -> Result<String, String> {
object(arguments)?;
match arguments.get(name) {
Some(Value::String(value)) if !value.is_empty() && value.len() <= 256 => Ok(value.clone()),
Some(Value::String(_)) => Err(format!("{name} must contain 1 to 256 bytes")),
Some(_) => Err(format!("{name} must be a string")),
None => default
.map(str::to_owned)
.ok_or_else(|| format!("{name} is required")),
}
}
pub fn boolean(arguments: &Value, name: &str, default: bool) -> Result<bool, String> {
object(arguments)?;
match arguments.get(name) {
Some(Value::Bool(value)) => Ok(*value),
Some(_) => Err(format!("{name} must be a boolean")),
None => Ok(default),
}
}
pub fn optional_i64(arguments: &Value, name: &str) -> Result<Option<i64>, String> {
object(arguments)?;
match arguments.get(name) {
Some(value) => value
.as_i64()
.map(Some)
.ok_or_else(|| format!("{name} must be a signed integer")),
None => Ok(None),
}
}
pub fn object(arguments: &Value) -> Result<(), String> {
if matches!(arguments, Value::Object(_)) {
Ok(())
} else {
Err("arguments must be an object".to_owned())
}
}
fn usize_value(arguments: &Value, name: &str, default: usize) -> Result<usize, String> {
match arguments.get(name) {
Some(value) => {
let value = value
.as_u64()
.ok_or_else(|| format!("{name} must be a non-negative integer"))?;
usize::try_from(value).map_err(|_| format!("{name} is too large"))
}
None => Ok(default),
}
}