Skip to main content

DiffSubsystem

Struct DiffSubsystem 

Source
pub struct DiffSubsystem { /* private fields */ }
Expand description

Process-wide registry + routing layer for diff sessions.

Lifecycle (D.2.a):

  • register(buffer_id, algorithm) — idempotent; pure-compute path with no sources, no debouncer, no routing entries. For tests and the future :describe-diff standalone path.
  • register_with_sources(buffer_id, algorithm, descriptor) (D.2.c) — production registration. Installs the descriptor + watch entries + a per-session Debouncer. Edits to any buffer in descriptor.watch will route to this session.
  • lookup(buffer_id) — returns Some(Arc<DiffSession>) if registered.
  • lookup_descriptor(buffer_id) (D.2.c) — returns Some(DiffDescriptor) if registered with sources.
  • drop_session(buffer_id) — removes session, descriptor, debouncer, and the session’s entries from every watchers bucket. In-flight Arc holders are unaffected.
  • iter_sessions() — snapshot of all currently-registered sessions. Powers :describe-diff (D.2.d).

Routing (D.2.c):

  • bind(bus, resolver) — installs the bus subscription + drainer task. Returns a DiffSubscriptionGuard whose Drop unsubscribes and aborts.
  • note_buffer_edited(buffer_id) — pokes the debouncer for every session in watchers[buffer_id]. Public so tests and (future) non-bus drivers can fire it directly.
  • note_buffer_closed(buffer_id) — calls drop_session.

The registry is Default-able and zero-cost to construct; the host owns one instance, threaded through Editor. Debounce window defaults to DEFAULT_DEBOUNCE_WINDOW and can be overridden via Self::with_debounce_window.

Implementations§

Source§

impl DiffSubsystem

Source

pub fn new() -> Self

Source

pub fn with_debounce_window(window: Duration) -> Self

Construct a subsystem with a non-default debounce window. Primarily a test hook (so unit tests can run with Duration::from_millis(1) and avoid wall-clock waits) but hosts can also tune the window via the typed options registry once that wiring lands (D.2.e).

Source

pub fn debounce_window(&self) -> Duration

Source

pub fn mode_bridge(&self) -> Arc<DiffModeBridge> ⓘ

D.5.a (2026-05-30): access the diff-mode lifecycle bridge so the editor’s dispatch tail can drain queued activations. The subsystem owns the bridge identity; the returned Arc is a cheap reference clone, not a take.

Source

pub fn register( &self, buffer_id: BufferId, algorithm: DiffAlgorithm, ) -> Arc<DiffSession> ⓘ

Register a session for buffer_id with no sources. The session has no debouncer, no descriptor, no watchers entries — used by tests and by the pure-compute API path. Production callers want Self::register_with_sources.

Idempotent: returns the existing Arc<DiffSession> if one is already registered (the algorithm argument is ignored in that case).

Source

pub fn register_with_sources( &self, buffer_id: BufferId, algorithm: DiffAlgorithm, descriptor: DiffDescriptor, ) -> Arc<DiffSession> ⓘ

D.2.c: register a session with a full DiffDescriptor. Inserts (or reuses) the session, stores the descriptor, rebuilds the inverse watchers entries to include this session for every buffer in descriptor.watch, and installs a per-session Debouncer.

Idempotent on session identity (same Arc<DiffSession> returned on re-registration) but descriptor is replaced on re-registration — the caller may be updating sources (e.g. switching baseline from StaticSource to GitBaseline). The old watch entries are scrubbed before the new ones are installed so a re-register with a shrunken watch list doesn’t leave stale routes.

Source

pub fn lookup_session_for( &self, buffer_id: BufferId, ) -> Option<Arc<DiffSession>>

D.4.d.3.a (2026-05-30): resolve a session from any buffer that participates in it (primary or secondary). Returns the same Arc<DiffSession> whether the caller passes the session’s primary key or one of its descriptor’s watched buffers. The teardown path (do_diff_off) uses this so :diffoff from either pane of a two-way diff finds the same session.

Source

pub fn all_sessions_for(&self, buffer_id: BufferId) -> Vec<Arc<DiffSession>>

D.6.g (2026-05-31): every session buffer_id participates in — as primary key or as a member of any descriptor’s watch list. Used by :diffoff! (the force bang) to cascade tear-down across all sessions the active buffer belongs to, not just the one Self::lookup_session_for happens to resolve.

Today’s secondary_index is single-valued (HashMap<BufferId, BufferId>), so a buffer participating in two simultaneous sessions only resolves to the most-recently-registered one via lookup_session_for. This method iterates the descriptors map directly and returns every session whose descriptor’s watch list contains buffer_id. Order is unspecified (HashMap iteration). Empty when the buffer is not a participant anywhere.

Source

pub fn sessions_awaiting_outcome(&self) -> Vec<Arc<DiffSession>>

Snapshot of every registered session still awaiting a verdict — a bound completion sender (a programmatic / agent review opened via DiffSession::bind_completion). Ordered by primary BufferId ascending; since ids are monotonic, the LAST entry is the most-recently-opened review. :diff-accept / :diff-reject fall back to this when the active buffer isn’t itself a diff pane, so a verdict typed from the :claude terminal (or anywhere) resolves the pending review instead of doing nothing and stranding the agent. Empty when no review is pending (e.g. only inline :diff / :diffsplit views exist).

Source

pub fn lookup(&self, buffer_id: BufferId) -> Option<Arc<DiffSession>>

Look up the session for buffer_id. Returns None if no session is registered.

Source

pub fn lookup_descriptor(&self, buffer_id: BufferId) -> Option<DiffDescriptor>

D.2.c: look up the descriptor for buffer_id. Returns None if the session was registered via Self::register (sources-less) or not registered at all.

Source

pub fn participant_slot(&self, buffer_id: BufferId) -> Option<usize>

D-fix.5: the Hunk::ranges slot buffer_id occupies in its session (0 = baseline / two-way left, 1 = current / right, 2 = remote in three-way). The diff modes need this so a per-side fold source (HunkFoldSource, UnchangedFoldSource) folds the buffer’s OWN side rather than always ranges[1]. None when the buffer participates in no session, or the session was registered sources-less (no descriptor). Resolves from either side via Self::descriptor_for_participant.

Source

pub fn first_change_line(&self, buffer_id: BufferId) -> Option<u32>

D-fix.5: the line (on buffer_id’s own side) of the first hunk — the auto-scroll target on diff open (vim positions the cursor at the first diff). None when buffer_id participates in no session, has no descriptor (no resolvable slot), or the published HunkIndex is empty (a clean diff — nothing to scroll to). The host moves the pane’s cursor here + centres it (zz) through the generic cursor primitive; the decision (which line, which side) is the diff subsystem’s.

Source

pub fn compute_get_edit( &self, active_buffer_id: BufferId, cursor_row: u32, target: Option<BufferId>, ) -> DiffGetOutcome

D.5.b (2026-05-30): compute the edit the diff-mode do chord would apply for buffer_id at cursor_row.

Returns None (silent no-op) when:

  • no session is registered for buffer_id,
  • no descriptor is registered (sources-less test registration — there’s no baseline to read from),
  • no hunk covers cursor_row on the current side,
  • the matched hunk is a three-way HunkKind::Conflict (D.6 lands the conflict-resolution path).

Behaviour by hunk kind on the two-way current side (ranges[1]):

  • Change: replace ranges[1] with the baseline slice for ranges[0].
  • Add: current side has the extra lines; baseline range is empty → delete ranges[1] (revert the add).
  • Remove: current side is empty at the deletion point; baseline has the removed lines → insert the baseline text at ranges[1].start (revert the remove). For a Remove hunk the current range is empty; cursor_row must equal ranges[1].start exactly for the lookup to match (vim parity — do only fires while the cursor sits on the deletion- marker row).

Reads the baseline through [DiffDescriptor::baseline].snapshot(). The snapshot is potentially expensive (file re-read for OnDiskSource); callers invoke once per do keystroke, never inside a tight loop. D.6.d (2026-05-31): compute the edit the diff-mode do chord or :diffget [<bufnr>] ex-command would apply at cursor_row on active_buffer_id.

target semantics:

  • None in two-way: pull from the peer (the only other side) — preserves D.5.b’s do chord behaviour.
  • Some(buffer) in two-way: pull from that side (must be the peer, else DiffGetOutcome::Nothing).
  • None in three-way: ambiguous → DiffGetOutcome::TargetRequired with the two available targets.
  • Some(buffer) in three-way: pull from that participant’s side; allows resolving Conflict hunks by picking which side wins.

Reads the target side’s rope via [snapshot_for_pane]. Cheap for buffer-backed sources (rope-Arc clone); the snapshot is called once per dispatch, never inside a tight loop.

Source

pub fn compute_keep_both_edit( &self, active_buffer_id: BufferId, cursor_row: u32, theirs: BufferId, ) -> DiffGetOutcome

CR.2 (2026-06-24): compute the “keep both” resolution edit for the conflict hunk under cursor_row on the active (local / “ours”) side of a three-way session — the dB chord. Splices the active side’s lines followed by theirs’ lines (ours-then-theirs, the v1 convention; base is omitted, matching git’s non-diff3 style) into the active range, so the conflict region ends up holding both sides’ content in order. The edit applies to the active buffer (like keep-ours / keep-theirs, which reuse Self::compute_get_edit with the resolved slot→bufnr target); target_buffer_id in the returned DiffGetOutcome::Edit is the active buffer — the apply destination.

Conflict-only: a non-Conflict covering hunk (or none) → Nothing, as does an unknown / self theirs, or a session/descriptor miss. The whole-line ranges are newline-terminated, so the splice is a clean line concatenation.

Source

pub fn compute_put_plan( &self, active_buffer_id: BufferId, cursor_row: u32, target: Option<BufferId>, ) -> DiffPutOutcome

D.5.c (2026-05-30): compute the outcome the diff-mode dp chord would produce for buffer_id at cursor_row. Mirror of Self::compute_get_edit but pushes the current side’s text into the peer instead of pulling from the baseline.

Returns:

  • DiffPutOutcome::Edit for two-pane sessions — carries peer_buffer_id, the Edit to apply to the peer, and the current-side cursor row.
  • DiffPutOutcome::NoPeerBuffer when the session’s participants don’t include a peer buffer (inline file-on-disk; D.7 git baseline). Dispatch surfaces the clear error rather than silently doing nothing.
  • DiffPutOutcome::Nothing for the same silent no-op cases as Self::compute_get_edit: no session, no descriptor, no covering hunk, three-way Conflict.

Reads the current side via [DiffDescriptor::current].snapshot(). Cheap for buffer-backed current sources (rope-Arc clone); the snapshot reads happen once per dp keystroke at the production rate.

Three-way scope. Participants length other than 2 is treated as “no peer” rather than synthesising a best-guess target. D.6 lands :diffput <bufnr> / :diffget <bufnr> with the disambiguating argument and replaces this conservative bail-out with a participant-indexed peer lookup. v1’s two-pane shape (the only one D.5.c claims) cleanly hits the 2 arm.

Source

pub fn diff_get_effect( &self, active_buffer: BufferId, cursor_row: u32, target: Option<BufferId>, ) -> Option<Effect>

CR.1 (2026-06-24): resolve the diff-get (do chord / :diffget) at cursor_row on active_buffer into an [Effect] the host applies — the mode-owned replacement for the host’s former Editor::do_diff_get. Diff-get rewrites the active side’s hunk to match the resolved baseline, so the edit targets active_buffer (the cursor’s buffer); the target_buffer_id from Self::compute_get_edit names only the source side and is NOT the apply target.

  • covering hunk → Effect::ApplyEdit { target: active_buffer, .. } carrying the post-edit cursor row;
  • three-way without a disambiguating target → an error Echo listing the available bufnrs;
  • nothing under the cursor / no session → None (silent no-op).
Source

pub fn diff_put_effect( &self, active_buffer: BufferId, cursor_row: u32, target: Option<BufferId>, ) -> Option<Effect>

CR.1 (2026-06-24): resolve the diff-put (dp chord / :diffput) at cursor_row on active_buffer into an [Effect] — the mode-owned replacement for Editor::do_diff_put. Diff-put pushes the active side’s hunk INTO the peer, so the edit targets the resolved target_buffer_id (the peer); the cursor parks on the active side.

  • peer + covering hunk → Effect::ApplyEdit { target: peer, .. };
  • inline baseline (no live peer buffer) → an error Echo (“dp: baseline is not a buffer; use :write”);
  • three-way without a target → an error Echo listing bufnrs;
  • nothing under the cursor / no session → None.
Source

pub fn session_participants( &self, session_key: BufferId, ) -> Option<Vec<BufferId>>

CR.3 (2026-06-24): the participant buffers of the session keyed by session_key, in slot order ([base, local, remote] for a three-way). Used by the host to drive diff-conflict-mode activation off the published sign map.

Source

pub fn diff_keep_ours_effect( &self, active_buffer: BufferId, cursor_row: u32, ) -> Option<Effect>

CR.3 d2o keep-ours: the local side already holds ours, so there is nothing to apply — but the chord is a recognised resolution command (Dhruva 2026-06-24: full fugitive set, degenerate → informative echo, not a silent no-op). Echoes over a conflict region; None off-hunk (silent, like the other chords).

Source

pub fn diff_keep_theirs_effect( &self, active_buffer: BufferId, cursor_row: u32, ) -> Option<Effect>

CR.3 d3o keep-theirs: pull theirs (remote) into the local range — compute_get_edit with target = theirs (already conflict-capable). None when there’s no three-way session, no covering conflict, etc.

Source

pub fn diff_put_ours_effect( &self, active_buffer: BufferId, cursor_row: u32, ) -> Option<Effect>

CR.3 d2p put-ours: the local side IS ours, so there is nothing to push — informative echo over a conflict region (degenerate self-target), else None.

Source

pub fn diff_put_theirs_effect( &self, active_buffer: BufferId, cursor_row: u32, ) -> Option<Effect>

CR.3 d3p put-theirs: push the local side’s hunk into theirs (remote) — compute_put_plan with target = theirs.

Source

pub fn diff_keep_both_effect( &self, active_buffer: BufferId, cursor_row: u32, ) -> Option<Effect>

CR.3 dB keep-both: splice ours⌢theirs into the local range via Self::compute_keep_both_edit, returning an Effect::ApplyEdit targeting the active (local) buffer. None when there’s no three-way session or no covering conflict.

Source

pub fn diff_next_hunk_effect( &self, active_buffer: BufferId, cursor_row: u32, ) -> Option<Effect>

CR.6 ]c / :hunk-next: move the cursor to the next hunk start (slot 1, wraps to the first) — the mode-owned replacement for the host’s do_next_hunk. Returns a generic Effect::SelectionChange (the host owns the cursor write), or an info Echo (“no diff session” / “no hunks”) preserving the former host messages for the :hunk-next ex-command path (the ]c chord is K.1.c-gated and never hits those).

Source

pub fn diff_prev_hunk_effect( &self, active_buffer: BufferId, cursor_row: u32, ) -> Option<Effect>

CR.6 [c / :hunk-prev: mirror of Self::diff_next_hunk_effect — largest slot-1 start strictly before cursor_row, wrapping to the last hunk.

Source

pub fn watchers_of(&self, watched_buffer: BufferId) -> Vec<BufferId>

D.2.c: snapshot of the inverse routing index for watched_buffer. Returns the session keys whose descriptors include watched_buffer in their watch list. Empty if no sessions watch it.

Test-friendly; production code uses Self::note_buffer_edited.

Source

pub fn drop_session(&self, buffer_id: BufferId) -> bool

Drop the registry entry for buffer_id. Removes the session, descriptor, every watchers-bucket entry, and the debouncer. Returns true if a session entry was removed. Safe to call on a non-registered id.

In-flight Arc<DiffSession> holders stay coherent; the registry’s job is naming, not lifetime enforcement.

Source

pub fn add_participant( self: &Arc<Self>, session_key: BufferId, source: Arc<dyn DiffParticipantSource>, participant_buffer: Option<BufferId>, ) -> Result<usize, MembershipError>

D.8.d (2026-05-31): add a participant to an existing session. Appends source to descriptor.sources and (if participant_buffer is Some) to descriptor. watch + descriptor.participants + the inverse watcher index. Triggers a recompute through the existing debouncer so the new arity shows up immediately.

Returns the new arity after the add (on success).

Errors:

Source

pub fn remove_participant( self: &Arc<Self>, session_key: BufferId, slot: usize, ) -> Result<usize, MembershipError>

D.8.d (2026-05-31): remove the participant at slot slot from session_key. Drops the corresponding sources[slot]; if the slot corresponded to a buffer in participants, scrubs it from the watcher index + notifies the bridge.

Auto-collapse semantics:

  • New arity ≥ 2: session stays active, recompute fires with the smaller participant set.
  • New arity == 1: session is dormant (registered, refcount stays on the remaining buffer, but compute_diff publishes an empty HunkIndex since there’s no peer to diff against).
  • New arity == 0: session auto-drops (calls drop_session internally).

Returns the new arity (0 on auto-drop).

Source

pub fn remove_participant_buffer( self: &Arc<Self>, session_key: BufferId, buffer_id: BufferId, ) -> Result<usize, MembershipError>

D.8.d (2026-05-31): convenience — remove the slot whose participants entry equals buffer_id. Looks up the slot via [pane_index_of] (D.6.d helper), then delegates to Self::remove_participant. Updates watch + participants + bridge in this path (unlike slot-only removal, since we know which buffer leaves).

This is the typical entry point for :diffthis / per-buffer :diffoff (D.8.e / D.8.f).

Source

pub fn replace_descriptor( self: &Arc<Self>, session_key: BufferId, descriptor: DiffDescriptor, ) -> Result<(), MembershipError>

D.8.d (2026-05-31): atomically swap a session’s descriptor while preserving session identity. The Arc<DiffSession> stays the same — any holder (compute_get_edit / compute_put_plan callers, renderer-side current_hunks readers) sees a smooth transition. Useful for transitioning a session from N=1 dormant to N=2 active (the natural :diffthis flow) when we want to swap the entire source list rather than add_participant-ing one at a time.

Internally: drop_session’s scrub semantic for the old descriptor, then register_with_sources’s install semantic for the new one — but without dropping the session entry from the registry. The mode-bridge re-scrubs + re-installs participants the same way note_session_opened already does on re-open.

Source

pub fn is_empty(&self) -> bool

true if no sessions are registered. Test-friendly.

Source

pub fn len(&self) -> usize

Number of registered sessions. Test-friendly.

Source

pub fn iter_sessions(&self) -> Vec<Arc<DiffSession>>

Snapshot of all currently-registered sessions. Returns fresh Arc clones — callers may hold them past a concurrent drop_session without affecting registry state. Order is unspecified (HashMap iteration); D.2.d sorts for display.

Source

pub fn describe_sessions(&self) -> Vec<DiffSessionDescription>

Snapshot of all currently-registered sessions for :describe-diff introspection. Sorted by BufferId so the rendered output is stable across calls.

Each row carries everything the renderer needs to format one line of the help buffer: the session key, the algorithm, the currently-published revision + hunk count, and (when a descriptor is registered) the declared watch list.

Source

pub fn build_describe_diff_content(&self) -> String

Build the :describe-diff help-buffer body — the human-readable text rendered into the synthetic Document buffer that do_describe_diff opens.

Output shape:

Active diff sessions: 2

BufferId  Algorithm     Rev  Hunks  Watches
--------  ------------  ---  -----  -------
1         Histogram     5    3      [1, 2]
7         MyersMinimal  0    0      [7]
Source

pub fn schedule_recompute( &self, buffer_id: BufferId, sources: Vec<Arc<dyn DiffParticipantSource>>, ) -> Option<JoinHandle<Option<Arc<HunkIndex>>>>

D.2.b: schedule a recompute of buffer_id’s session on the tokio blocking pool. Returns None if no session is registered.

The returned JoinHandle resolves to the publish result (Some(Arc<HunkIndex>) on take, None if dropped as stale). Production callers can fire-and-forget — the session’s ArcSwap<HunkIndex> is the source of truth and reads stay coherent regardless of whether anyone awaits the handle. Tests and :describe-diff await for observability.

Supersede semantics: when two recomputes are scheduled in rapid succession, both run to completion on the blocking pool — there is no abort. Whichever finishes second allocates the higher revision and wins the DiffSession::try_publish_if_newer gate; whichever finishes first either gets there first (and is then superseded by the second’s publish) or loses the gate. Either way the final state is the latest scheduled recompute’s hunks. D.2.c’s debounce will eliminate most of the redundant spawn cost before it hits the pool.

Source

pub fn note_buffer_edited(self: &Arc<Self>, buffer_id: BufferId)

Notify the subsystem that buffer_id was edited. Walks the inverse watchers index and pokes the debouncer for every session whose descriptor’s watch list includes buffer_id. Each poke schedules a recompute after the debounce window; multiple pokes during the window collapse to one recompute (see Debouncer).

Production driver is Self::bind’s drainer task; tests (and future non-bus drivers) can call this directly.

Source

pub fn note_buffer_closed(&self, buffer_id: BufferId)

Notify the subsystem that buffer_id was closed. Drops the session for that buffer. If the closed buffer was a watched-only dependency of some other session (e.g. BufferSource(closed_id) for session X), session X’s watcher entry for closed_id is left in place — the next snapshot returns an empty rope per the BufferTextProvider contract, and the session will recompute the all-Add diff. The session itself is not dropped on a watched-side close; only on a current-side close.

Source

pub fn bind( self: &Arc<Self>, bus: Arc<EventBus>, resolver: Arc<dyn DocumentBufferResolver>, ) -> DiffSubscriptionGuard

D.2.c: bind the subsystem to an event bus. Subscribes to EventKind::DocumentChanged + EventKind::DocumentClosed, spawns one drainer task that translates each event’s DocumentId to BufferId via resolver and fans the signal into the routing path.

Returns a DiffSubscriptionGuard whose Drop unsubscribes the bus subscription and aborts the drainer task. Hosts hold the guard for the editor’s lifetime; tests drop it to verify cleanup.

Trait Implementations§

Source§

impl Debug for DiffSubsystem

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for DiffSubsystem

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more