Skip to main content

resolve_query_offset

Function resolve_query_offset 

Source
pub fn resolve_query_offset(position: i64, total: usize) -> usize
Expand 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

  1. position == 00.
  2. position > totaltotal (yields an empty page, matching the RFC’s silent-clamp semantics — /query does not error on out-of-range positions).
  3. position == i64::MIN → handled via i64::saturating_neg, which returns i64::MAX rather than overflowing. The resulting usize::MAX-magnitude offset is then absorbed by usize::saturating_sub.
  4. position exceeding usize::MAX on a 32-bit target (i64 values above 2^32 - 1) → clamped to total rather than truncated. The previous workspace idiom (position as usize) silently wrapped the high bits on 32-bit, returning a small start index 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);