#[non_exhaustive]pub enum LaserError {
Show 42 variants
PublishFailed(Box<PublishFailure>),
Handler(String),
HandlerConfig(String),
Rejected(String),
Timeout(&'static str),
AmbiguousMutation(String),
NoRespondTopic,
StateStore(String),
Config(&'static str),
NoStream,
Query(QueryError),
Kv(KvError),
Fork(ForkError),
Session(SessionError),
Graph(GraphError),
Authz(AuthzError),
Filter(FilterError),
FilterFault {
partition_id: u32,
offset: u64,
reason: FaultReason,
},
FilterOversizedRecord {
partition_id: u32,
offset: u64,
},
ConsumerGroupSetup {
group_id: u32,
name: String,
identity: FilterGroupIdentity,
source: Box<LaserError>,
},
Checkpoint(Box<CheckpointError>),
Codec(String),
Invalid(String),
Protocol(String),
Command(CommandError),
Unsupported {
surface: &'static str,
feature: Option<&'static str>,
message: String,
},
Integrity {
reference: String,
},
Signature(String),
PolicyBlocked(String),
StepUpRequired {
scope: String,
},
PolicyDeferred(String),
NoCapableAgent {
skill: String,
},
NoInbox {
agent: String,
},
PresenceConflict {
advertised: String,
requested: String,
},
RoutePrincipalMismatch {
agent: String,
expected: u32,
actual: Option<u32>,
},
FenceViolation {
stale: u64,
current: u64,
},
BudgetExceeded {
ceiling: u64,
spent: u64,
},
Cancelled {
run: String,
},
Quarantined {
agent: String,
},
Iggy(IggyError),
Id(IdError),
Provenance(ProvenanceError),
}Expand description
The one error type every fallible SDK call returns.
LaserData-Cloud-served surfaces fail with their typed wire error nested intact
(Query, Kv, Fork), so callers
can match on the structured cause (QueryError::TooLarge { cap, .. },
KvError::InvalidKey, …) instead of parsing strings. Client-side failures
keep their own variants: Codec (encode/decode),
Invalid (validation), Protocol
(unexpected reply shape). The classifier methods (is_retryable,
is_unsupported, is_not_found)
answer the common questions without matching variants.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
PublishFailed(Box<PublishFailure>)
A fluent or direct publish that gave up. Carries the cause, the target, the ranges that committed, and the records left unconfirmed.
Handler(String)
A transient handler-side failure a handler may return to request a retry
(the reliable consumer retries it under the RetryPolicy).
Deterministic wiring, startup, and configuration failures use
HandlerConfig instead, which never retries.
HandlerConfig(String)
A deterministic handler wiring, startup, or configuration failure: a task that stopped before becoming ready, a join failure, an invalid inbox topic or task id, a missing correlation or agent id. Retrying cannot change the outcome, so it is never retryable (the reliable consumer dead-letters it at once rather than burning the retry budget).
Rejected(String)
Timeout(&'static str)
AmbiguousMutation(String)
A managed mutation’s outcome is unknown: the attempt timed out or the
transport failed after dispatch, so the server may or may not have
applied it. This is deliberately not generically retryable. The caller
must inspect is_ambiguous_mutation and
follow the operation-specific recovery contract.
NoRespondTopic
StateStore(String)
Config(&'static str)
NoStream
Query(QueryError)
LaserData Cloud answered a query/browse/control op with a typed failure.
Kv(KvError)
LaserData Cloud answered a key-value op with a typed failure.
Fork(ForkError)
LaserData Cloud answered a fork op with a typed failure.
Session(SessionError)
LaserData Cloud answered a session read with a typed failure.
Graph(GraphError)
LaserData Cloud answered a graph op with a typed failure.
Authz(AuthzError)
The streaming server answered an authorization op with a typed failure.
Filter(FilterError)
The streaming server or the filter catalog answered a consumer-filter operation with a typed failure.
FilterFault
A filtered read stopped in front of a record the filter could not
evaluate under the stop fault policy. The record and everything after
it stay unacknowledged.
FilterOversizedRecord
A matching record alone exceeds the filtered reply cap, so no page can carry it. The record and everything after it stay unacknowledged.
ConsumerGroupSetup
The consumer group was created, or already existed, but its filter
could not be configured. The group stays as it is, unbound unless it
ran a policy before, and no reader joined it. source is the typed
catalog refusal or transport failure.
Checkpoint(Box<CheckpointError>)
Iggy answered a destination or checkpoint operation with a typed failure.
Codec(String)
A client-side encode or decode failed (payload codec, wire envelope, reply bytes). Deterministic for a given input, so never retryable.
Invalid(String)
Client-side validation rejected the input before any round-trip (size caps, reserved keys, malformed identifiers).
Protocol(String)
The reply decoded but carried an outcome the request cannot accept (e.g. a scan outcome for a get). Indicates server/client skew.
Command(CommandError)
A managed endpoint returned its original result code and message.
Unsupported
The connected infrastructure does not provide the requested feature
(Apache Iggy without LaserData Cloud, or a deployment whose backend
does not advertise the sub-capability). Permanent by definition: gate
the code path on Laser::capabilities instead
of retrying. surface names the accessor the call came through and
feature the sub-capability when one exists, so a log line says what
was refused without parsing prose. Build with
unsupported /
unsupported_feature.
Fields
Integrity
A claim-checked body failed its digest check: the blob store returned
bytes whose SHA-256 does not match the BodyRef capsule’s. Never
surfaced with the fetched bytes attached, so an integrity failure can
never be mistaken for the body.
Signature(String)
An envelope signature was absent where required, enrolled to no known key, or failed verification. The authorship and authorization gate, never retryable.
PolicyBlocked(String)
The enrolled ActionGovernor rejected
the action before the effect ran. Never retryable: the policy, not the
transport, said no.
StepUpRequired
The enrolled governor paused the action on a stronger approval.
scope names the scope the approval must grant, so a handler can run an
approval_gate and re-send.
Never retryable as-is.
PolicyDeferred(String)
The enrolled governor held the action for later execution. Retryable by definition: later is the point.
NoCapableAgent
Capability routing found no live agent advertising skill. The caller
retries after the registry refreshes, or routes elsewhere.
NoInbox
An advertised inbox route resolved a capable agent but the agent advertises
no inbox topic in its live presence, so there is nowhere to address it. The
caller waits for the agent to advertise, supplies an explicit
InboxRoute::Fixed, or routes elsewhere.
Never falls back to a shared topic name.
PresenceConflict
One physical connection may advertise one logical agent. A second agent would overwrite connection metadata and steal the first agent’s route.
RoutePrincipalMismatch
A route selected an agent claim whose live connection is not bound to the authenticated principal the caller required.
FenceViolation
A fenced write lost the fence: the held token is below the live sequence, so a newer holder owns the task. Not alarming and never retryable by the loser, it is the at-most-one-effective-writer gate doing its job.
BudgetExceeded
A spend ceiling was reached. Not retryable until the ceiling is raised.
Cancelled
A registered run’s recorded cancel intent was observed at a step boundary. The completed steps’ compensations have run. Not retryable on the same run.
Quarantined
The agent was quarantined and may not act. Not retryable.
Iggy(IggyError)
Id(IdError)
Provenance(ProvenanceError)
Implementations§
Source§impl LaserError
impl LaserError
pub fn publish_cause(&self) -> &Self
Sourcepub fn rejected(reason: impl Into<String>) -> Self
pub fn rejected(reason: impl Into<String>) -> Self
A handler returns this to reject a message permanently: the reliable consumer dead-letters it immediately instead of retrying.
Sourcepub fn unsupported(surface: &'static str, message: impl Into<String>) -> Self
pub fn unsupported(surface: &'static str, message: impl Into<String>) -> Self
An unsupported-surface refusal: the whole surface is absent on the
connected deployment (e.g. any managed call against Apache Iggy).
Sourcepub fn unsupported_feature(
surface: &'static str,
feature: &'static str,
message: impl Into<String>,
) -> Self
pub fn unsupported_feature( surface: &'static str, feature: &'static str, message: impl Into<String>, ) -> Self
An unsupported-feature refusal: the surface is served but this
sub-capability is not advertised (e.g. kv.cas_fenced, query.keyword).
Sourcepub fn is_retryable(&self) -> bool
pub fn is_retryable(&self) -> bool
Whether retrying the same call can succeed. Managed failures follow the
canonical ResultCode classifier, while transport, handler, routing,
timeout, and deferred-policy failures retain their local semantics.
Whether the failure was transient: the store was momentarily out of reach,
a connection was refused or dropped, or a concurrency conflict was
aborted. The identical request may succeed on a later attempt, so this is
the flag a retry loop keys on when it wants only the recoverable class
rather than everything is_retryable admits.
Sourcepub fn is_not_leader(&self) -> bool
pub fn is_not_leader(&self) -> bool
Whether the connected managed backend declined a conditional write because it does not own that operation’s mutation partition.
Sourcepub fn is_unsupported(&self) -> bool
pub fn is_unsupported(&self) -> bool
Whether the failure means the connected infrastructure (or backend) does not provide the feature at all. Permanent: do not retry, gate the code path instead.
Sourcepub fn is_not_found(&self) -> bool
pub fn is_not_found(&self) -> bool
Whether the failure names a missing resource (index, fork). Distinct from a backend being down: the call worked, the thing is not there.
Sourcepub fn is_version_skew(&self) -> bool
pub fn is_version_skew(&self) -> bool
Whether the failure is wire-version skew between this SDK and the
connected LaserData Cloud (the envelope’s v was not accepted). Permanent for
this client build: upgrade or downshift instead of retrying.
Sourcepub fn is_version_conflict(&self) -> bool
pub fn is_version_conflict(&self) -> bool
Whether a compare-and-swap lost its precondition (the key changed under
it, or an expect_absent create lost a race). Not a failure to retry
blindly: re-read the current value and version, recompute, and CAS again.
Sourcepub fn is_ambiguous_mutation(&self) -> bool
pub fn is_ambiguous_mutation(&self) -> bool
Whether a managed mutation may already have reached the server. A generic retry loop must stop: recovery depends on the operation. In particular, an ambiguous lease acquisition must wait through its requested TTL before a fresh acquisition, because an applied grant can otherwise conflict with itself and the reply carries no token to renew or release it.
Sourcepub fn is_stale(&self) -> bool
pub fn is_stale(&self) -> bool
Whether a read-consistency barrier could not be met: a query projector or key-value fold has not yet applied the required source position. Retryable: the read model is catching up.
Sourcepub fn is_permission_denied(&self) -> bool
pub fn is_permission_denied(&self) -> bool
Whether the connected server refused the operation for missing permissions (the substrate’s RBAC: global permissions plus per-stream and per-topic grants). The principal exists and authenticated, the grant does not. The fix is an admin conversation, not a retry: ask for the stream or topic permission the failing verb needs (read, send, create), or point the client at a stream the principal can use.
Sourcepub fn is_stream_or_topic_not_found(&self) -> bool
pub fn is_stream_or_topic_not_found(&self) -> bool
Whether the target stream or topic does not exist FOR THIS PRINCIPAL. Under RBAC an existing stream the principal cannot see answers exactly like a missing one, so treat “not found” and “not permitted” as one user-facing question: does this principal have the stream, with the grant the verb needs? Especially relevant on deployments with server-managed dynamic streams, where the stream may simply not exist yet for this principal.
Sourcepub fn is_no_capable_agent(&self) -> bool
pub fn is_no_capable_agent(&self) -> bool
Whether capability routing found no live agent for the skill.
Sourcepub fn is_lease_lost(&self) -> bool
pub fn is_lease_lost(&self) -> bool
Whether a revocable lease was lost (expired, released, or re-acquired by another
holder). For a fenced write, see is_fence_violation.
Sourcepub fn is_fence_violation(&self) -> bool
pub fn is_fence_violation(&self) -> bool
Whether a fenced write lost the fence (a stale holder stepped aside). Not alarming, never retryable by the loser.
Sourcepub fn is_budget_exceeded(&self) -> bool
pub fn is_budget_exceeded(&self) -> bool
Whether a spend ceiling was reached.
Sourcepub fn is_quarantined(&self) -> bool
pub fn is_quarantined(&self) -> bool
Whether the agent is quarantined.
Sourcepub fn iggy_error_code(&self) -> Option<u32>
pub fn iggy_error_code(&self) -> Option<u32>
The Apache Iggy error code of the failure, when an Iggy error caused it. Reads through publish wrapping and a failed producer send, like the classifiers. Another SDK variant keeps its own classification.
Sourcepub fn filter_reason(&self) -> Option<FilterErrorReason>
pub fn filter_reason(&self) -> Option<FilterErrorReason>
The typed consumer-filter cause, when the failure is one.
Sourcepub fn code(&self) -> ResultCode
pub fn code(&self) -> ResultCode
This failure’s place in the unified ResultCode space. A managed
surface error projects onto its surface code, and a client-side failure maps
to the closest code. Lets a caller branch on one dictionary instead of
matching every variant, and mirrors the HTTP status the same error gets
on the management surface.
Trait Implementations§
Source§impl Debug for LaserError
impl Debug for LaserError
Source§impl Display for LaserError
impl Display for LaserError
Source§impl Error for LaserError
impl Error for LaserError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl From<AuthzError> for LaserError
impl From<AuthzError> for LaserError
Source§fn from(source: AuthzError) -> Self
fn from(source: AuthzError) -> Self
Source§impl From<CheckpointError> for LaserError
impl From<CheckpointError> for LaserError
Source§fn from(error: CheckpointError) -> Self
fn from(error: CheckpointError) -> Self
Source§impl From<CommandError> for LaserError
impl From<CommandError> for LaserError
Source§fn from(error: CommandError) -> Self
fn from(error: CommandError) -> Self
Source§impl From<DecodeError> for LaserError
impl From<DecodeError> for LaserError
Source§fn from(error: DecodeError) -> Self
fn from(error: DecodeError) -> Self
Source§impl From<FilterError> for LaserError
impl From<FilterError> for LaserError
Source§fn from(source: FilterError) -> Self
fn from(source: FilterError) -> Self
Source§impl From<ForkError> for LaserError
impl From<ForkError> for LaserError
Source§impl From<GraphError> for LaserError
impl From<GraphError> for LaserError
Source§fn from(source: GraphError) -> Self
fn from(source: GraphError) -> Self
Source§impl From<IdError> for LaserError
impl From<IdError> for LaserError
Source§impl From<IggyError> for LaserError
impl From<IggyError> for LaserError
Source§impl From<IntentError> for LaserError
impl From<IntentError> for LaserError
Source§fn from(error: IntentError) -> Self
fn from(error: IntentError) -> Self
Source§impl From<InvalidError> for LaserError
impl From<InvalidError> for LaserError
Source§fn from(error: InvalidError) -> Self
fn from(error: InvalidError) -> Self
Source§impl From<KvError> for LaserError
impl From<KvError> for LaserError
Source§impl From<ProvenanceError> for LaserError
impl From<ProvenanceError> for LaserError
Source§fn from(source: ProvenanceError) -> Self
fn from(source: ProvenanceError) -> Self
Source§impl From<QueryError> for LaserError
impl From<QueryError> for LaserError
Source§fn from(source: QueryError) -> Self
fn from(source: QueryError) -> Self
Source§impl From<SessionError> for LaserError
impl From<SessionError> for LaserError
Source§fn from(source: SessionError) -> Self
fn from(source: SessionError) -> Self
Source§impl From<TypedDecodeError> for LaserError
Folds into the codec family so records.next() composes with ? in a
Result<_, LaserError> function, the position kept in the message.
impl From<TypedDecodeError> for LaserError
Folds into the codec family so records.next() composes with ? in a
Result<_, LaserError> function, the position kept in the message.
Source§fn from(error: TypedDecodeError) -> Self
fn from(error: TypedDecodeError) -> Self
Source§impl From<ValidateError> for LaserError
impl From<ValidateError> for LaserError
Source§fn from(error: ValidateError) -> Self
fn from(error: ValidateError) -> Self
Auto Trait Implementations§
impl Freeze for LaserError
impl RefUnwindSafe for LaserError
impl Send for LaserError
impl Sync for LaserError
impl Unpin for LaserError
impl UnsafeUnpin for LaserError
impl UnwindSafe for LaserError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.