WalkCursor
Overview
Walkable position/movement contract (WalkCursor): a first-class position and movement API in the same
conceptual slot as Iterator / Supply.
A WalkCursor answers where a walk is and how it can move. It is distinct from
pull result streams (Qwiratry::QueryIterator) and from tree shape adaptors
(Qwiratry::Tree::Navigator::Base). Qwiratryβs first specialization is
Qwiratry::QueryCursor. Design notes live in
docs/rakudoc/Developing/Cursor-Proposal.md.
Note: Raku already binds CORE::Cursor to Match, so this contract
cannot ship as a bare Cursor role/module. WalkCursor is the short name
until/unless core frees that symbol. See Cursor-Proposal.md.
This module exports:
Sectorβ oriented half-lines from the current node (child, following, β¦)Axisβ a matched pair of opposite Sectors (one bidirectional line)WalkCursorβ the position /fetch-*/move-*roledirection-argsβ helper to build optional:axis/:sectorcaptures
Sector and Axis
Sector names XPath/Qwiratry navigation half-lines (child, parent,
following, β¦). Prefer Sector::β¦ qualification so barewords do not collide
with query-slang infixes.
Axis pairs opposite sectors for signed motion:
| Axis | Forward (+) | Backward (β) |
| preceding-following | following | preceding |
| preceding-following-sibling | following-sibling | preceding-sibling |
| ancestor-descendant | descendant | ancestor |
Sector::child / Sector::parent do not get their own Axis; they are one-step
moves on Axis.ancestor-descendant (fetch/move-relative(Β±1)).
An advertised Axis is always bidirectional. One-way-only backends advertise Sectors instead of an Axis.
Fetch vs Move
PostgreSQL-class scroll comes in two families:
fetch-*β reposition and return the item at the new position (Mu), orIterationEndwhen the step is empty. Count-taking forms aremultis onInt(single item) andRange(Seqover the span;*/Inf= until exhausted; open and closed ranges both allowed).move-*β same repositioning algebra, return anIntstep count (how many positions advanced;0if none). Count-takingmove-*takeIntonly.
Passing both :axis and :sector is an error. With :sector, steps must be
< $n >= 0 > (0 = self). With :axis / default axis, positive steps use the
forward sector and negative steps the backward sector.
Implementing
Compose WalkCursor and implement the stubbed (...) methods at minimum:
current, fetch-first, fetch-last, fetch-absolute, fetch-relative,
fetch-backward(Range), and clone-position. Default bodies already provide
fetch-next / fetch-prior / fetch-forward(Int) and the move-* family
in terms of those.
Example
use WalkCursor;
class PointCursor does WalkCursor {
has @.items;
has Int $.index is rw = 0;
method current(--> Mu) { @!items[$!index] }
method fetch-relative(Int $n, Axis :$axis, Sector :$sector --> Mu) {
my $i = $!index + $n;
return IterationEnd unless 0 <= $i < @!items.elems;
$!index = $i;
self.current
}
# ... other required multis / first / last / clone-position ...
}
Class Axis
Matched opposite pair of Sectors β one bidirectional navigation line.
Type methods preceding-following, preceding-following-sibling, and
ancestor-descendant return the standard Axes.
Sub direction-args
Build a Hash of defined :axis / :sector pairs for |-flattening into
scroll method calls. Omits undefined direction arguments.
Role WalkCursor
Position and PostgreSQL-class fetch-* / move-* movement.
Attributes
$.default-axisβ Axis used when neither:axisnor:sectoris passed (defaultAxis.preceding-following).
Capability probing
cursor-capabilities() returns an Associative (same pattern as Walker
capabilities). Typical keys: axes, sectors, absolute. first /
last are always supported.
Required stubs
Methods whose bodies are ... must be supplied by the composing class.
current()
method current(--> Mu)
The node or row at the Cursorβs position.
cursor-capabilities()
method cursor-capabilities(--> Associative)
Structured capability metadata for this Cursor implementation.
Scroll methods
PostgreSQL-class repositioning. fetch-* return the item at the new
position; move-* return how many positions advanced. See also the module
overview Fetch vs Move.
Shared parameters
These named arguments appear on every scroll method (except where noted).
Pass at most one of :axis or :sector; both together is an error.
When neither is passed, $.default-axis is used.
:$axis
An L<Axis> selecting the bidirectional line. Positive steps use
C<$axis.forward>; negative steps use C<$axis.backward>.
:$sector
A single L<Sector> half-line. Steps must be C<< $n >= 0 >> (C<0> means
self / no move along that sector).
$n
Count or span for absolute / relative / forward / backward forms:
Intβ one step of that magnitude (sign selects direction on an Axis; must be non-negative with:sector).Rangeβfetch-*only; yield aSeqover the span. Open and closed ranges are allowed;*/Infmeans until exhausted.move-*do not takeRange.
fetch-next / fetch-prior / fetch-previous
method fetch-next(Axis :$axis, Sector :$sector --> Mu)
method fetch-prior(Axis :$axis, Sector :$sector --> Mu)
method fetch-previous(|c) # alias of fetch-prior
One step forward or backward along the chosen line. Implemented as
fetch-relative(+1) / fetch-relative(-1).
fetch-first / fetch-last
method fetch-first(Axis :$axis, Sector :$sector --> Mu)
method fetch-last(Axis :$axis, Sector :$sector --> Mu)
Jump to the first or last position on the chosen line. Required stubs for composing classes.
fetch-absolute / fetch-relative
multi method fetch-absolute(Int $n, Axis :$axis, Sector :$sector --> Mu)
multi method fetch-absolute(Range $n, Axis :$axis, Sector :$sector --> Seq)
multi method fetch-relative(Int $n, Axis :$axis, Sector :$sector --> Mu)
multi method fetch-relative(Range $n, Axis :$axis, Sector :$sector --> Seq)
$n
Absolute: 1-based (or implementation-defined) index on the line, or a
C<Range> of such indices. Relative: signed step count from C<current>, or
a C<Range> of relative steps.
Required stubs for composing classes.
fetch-forward / fetch-backward
multi method fetch-forward(Int $n = 1, Axis :$axis, Sector :$sector --> Mu)
multi method fetch-forward(Range $n, Axis :$axis, Sector :$sector --> Seq)
multi method fetch-backward(Int $n = 1, Axis :$axis, Sector :$sector --> Mu)
multi method fetch-backward(Range $n, Axis :$axis, Sector :$sector --> Seq)
$n
Defaults to C<1> for the C<Int> candidates. Forward is
C<fetch-relative($n)>; backward is C<fetch-relative(-$n)> for C<Int>, with
a Range multi stubbed for composing classes.
move-*
method move-next(Axis :$axis, Sector :$sector --> Int)
method move-prior(Axis :$axis, Sector :$sector --> Int)
method move-previous(|c) # alias of move-prior
method move-first(Axis :$axis, Sector :$sector --> Int)
method move-last(Axis :$axis, Sector :$sector --> Int)
method move-absolute(Int $n, Axis :$axis, Sector :$sector --> Int)
method move-relative(Int $n, Axis :$axis, Sector :$sector --> Int)
method move-forward(Int $n = 1, Axis :$axis, Sector :$sector --> Int)
method move-backward(Int $n = 1, Axis :$axis, Sector :$sector --> Int)
Same repositioning as the matching fetch-*, but return an Int step
count instead of the item. Count-taking forms take Int only (no
Range). Default bodies wrap the corresponding fetch-*.
$n
As for C<fetch-absolute> / C<fetch-relative> / C<fetch-forward> /
C<fetch-backward>, restricted to C<Int>. C<move-forward> /
C<move-backward> default C<$n> to C<1>.
Return Value
fetch-*withInt(or no count)
The item at the new position (C<Mu>), or C<IterationEnd> when the step is
empty. Unsupported operations should throw (Qwiratry uses
C<X::Qwiratry::Cursor::*>).
fetch-*withRange
A C<Seq> of items along the span.
move-*
An C<Int> count of positions advanced (C<0> if none).
clone-position()
method clone-position(--> ::?CLASS)
Return a new WalkCursor with the same position-relevant state and independent mutable position (for backtracking). Must not share live position or walk-local Navigator caches with the original.