pub fn resolve_query_offset(position: i64, total: usize) -> usizeExpand description
Resolve a request-side position argument (RFC 8620 §5.5) into a
0-based start index suitable for slicing the full ordered result
list (bd:JMAP-qz9v.48).
position is the signed offset from the /query request. The
foundation handler at crate::handlers::handle_query parses it
via serde_json::Value::as_i64, so the value reaching the
backend is any i64 (including i64::MIN). Non-negative values
are absolute offsets from the start of the result list; negative
values are end-relative offsets per RFC 8620 §5.5 (“-1 represents
the last entry, -2 the second to last, and so on”).
Returns a usize clamped to [0, total]. The clamp at the high
end matches the slice-safety property: all_ids[start..] is
guaranteed not to panic regardless of the input position.
§Edge cases this helper exists to centralize
position == 0→0.position > total→total(yields an empty page, matching the RFC’s silent-clamp semantics —/querydoes not error on out-of-range positions).position == i64::MIN→ handled viai64::saturating_neg, which returnsi64::MAXrather than overflowing. The resultingusize::MAX-magnitude offset is then absorbed byusize::saturating_sub.positionexceedingusize::MAXon a 32-bit target (i64values above2^32 - 1) → clamped tototalrather than truncated. The previous workspace idiom (position as usize) silently wrapped the high bits on 32-bit, returning a smallstartindex that did not match the caller’s intent.
§Why this lives in the foundation
The pattern is identical across every extension server’s /query
backend impl. Centralizing it eliminates the per-crate
(position as usize) / (position.saturating_neg() as usize)
idiom that clippy::pedantic flags as cast_possible_truncation +
cast_sign_loss, and prevents future siblings from re-introducing
the strictly-worse (-position) as usize variant (which panics on
i64::MIN in debug builds and wraps in release).
§Example
use jmap_server::resolve_query_offset;
// Absolute offset.
assert_eq!(resolve_query_offset(0, 100), 0);
assert_eq!(resolve_query_offset(25, 100), 25);
// End-relative offset.
assert_eq!(resolve_query_offset(-1, 100), 99);
assert_eq!(resolve_query_offset(-100, 100), 0);
// Out-of-range clamps to total.
assert_eq!(resolve_query_offset(1_000, 100), 100);
assert_eq!(resolve_query_offset(-1_000, 100), 0);
// i64::MIN does not overflow.
assert_eq!(resolve_query_offset(i64::MIN, 100), 0);