Skip to main content

Imperfect

Enum Imperfect 

Source
pub enum Imperfect<T, E, L>
where L: Loss,
{ Success(T), Partial(T, L), Failure(E, L), }
Expand description

Result extended with partial success.

Three states:

  • Success(T) — perfect result, zero loss.
  • Partial(T, L) — value present, some information lost getting here.
  • Failure(E, L) — failure, no value, but the cost of getting here is measured.

The design descends from PbtA (Powered by the Apocalypse) tabletop games, which use three outcome tiers: 10+ is full success, 7-9 is success with complications, 6- is failure. The middle tier — success with cost — is the design innovation that PbtA contributed to game design. This crate encodes that structure in types.

Follows Result conventions: is_ok() means “has a value” (Success or Partial). The .ok() and .err() extractor methods follow Result naming conventions.

Variants§

§

Success(T)

Perfect result, zero loss.

§

Partial(T, L)

Value present, some information lost getting here.

§

Failure(E, L)

Failure, no value, but the cost of getting here is measured.

Implementations§

Source§

impl<T, E, L> Imperfect<T, E, L>
where L: Loss,

Source

pub fn success(value: T) -> Imperfect<T, E, L>

Construct a success. Alias for Success(value).

Source

pub fn partial(value: T, loss: L) -> Imperfect<T, E, L>

Construct a partial result with measured loss. Alias for Partial(value, loss).

Source

pub fn failure(error: E) -> Imperfect<T, E, L>

Construct a failure with zero accumulated loss.

Source

pub fn failure_with_loss(error: E, loss: L) -> Imperfect<T, E, L>

Construct a failure carrying accumulated loss from prior steps.

Source

pub fn is_ok(&self) -> bool

Returns true if the result has a value (Success or Partial).

Source

pub fn is_partial(&self) -> bool

Returns true if this is a Partial result.

Source

pub fn is_err(&self) -> bool

Returns true if this is a Failure.

Source

pub fn ok(self) -> Option<T>

Extract the value, discarding loss information. Returns None on Failure.

Source

pub fn err(self) -> Option<E>

Extract the error. Returns None on Success or Partial.

Source

pub fn err_with_loss(self) -> Option<(E, L)>

Extract the error and accumulated loss. Returns None on Success or Partial.

Unlike .err() which drops the loss, this returns both the error and the loss that accumulated before the failure. This is information you can’t recover any other way — L::total() can always be reconstructed from the type, but the pre-failure loss cannot.

Source

pub fn loss(&self) -> L

The loss incurred. Zero for Success, carried for Partial and Failure.

Failure carries the accumulated loss from before the failure — the cost of getting here. If you need L::total(), check is_err().

Source

pub fn as_ref(&self) -> Imperfect<&T, &E, L>

Borrow the inner value and error without consuming self.

Source

pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Imperfect<U, E, L>

Transform the value, preserving loss and failure.

Source

pub fn map_err<F>(self, f: impl FnOnce(E) -> F) -> Imperfect<T, F, L>

Transform the error, preserving value and loss.

Source

pub fn eh<U>( self, f: impl FnOnce(T) -> Imperfect<U, E, L>, ) -> Imperfect<U, E, L>

Terni-functor bind. Chain an operation, accumulating loss.

  • Success: apply f, return its result
  • Partial: apply f, combine losses
  • Failure: short-circuit, f never called
Source

pub fn imp<U>( self, f: impl FnOnce(T) -> Imperfect<U, E, L>, ) -> Imperfect<U, E, L>

Alias for eh. The name. For the mischievous ones.

Source

pub fn tri<U>( self, f: impl FnOnce(T) -> Imperfect<U, E, L>, ) -> Imperfect<U, E, L>

Alias for eh. Mathematical form — the terni-functor bind.

Source

pub fn recover( self, f: impl FnOnce(E) -> Imperfect<T, E, L>, ) -> Imperfect<T, E, L>

Attempt recovery from Failure. The loss carries forward.

Success and Partial pass through unchanged. Failure → recovery function → result carries the failure’s accumulated loss.

Recovery from Failure never produces Success — because the failure happened. The loss is real. The best you can do is recover a value and carry the cost.

Source

pub fn unwrap_or_else(self, f: impl FnOnce(E) -> T) -> Imperfect<T, E, L>

Recover a default value from Failure. Always produces Partial. You can’t un-fail. But you can get something back. The loss survives.

Source

pub fn unwrap_or(self, default: T) -> Imperfect<T, E, L>

Recover with a static default. Always produces Partial on Failure.

Source

pub fn compose<T2, E2>(self, next: Imperfect<T2, E2, L>) -> Imperfect<T2, E2, L>
where E: Into<E2>,

Propagate accumulated loss from self through next.

Deprecated in favor of eh / imp / tri. Kept for backward compatibility.

  • Success + next → next (no loss to propagate)
  • Partial(_, loss) + Success(v) → Partial(v, loss)
  • Partial(_, loss1) + Partial(v, loss2) → Partial(v, loss1.combine(loss2))
  • Partial(_, loss1) + Failure(e, loss2) → Failure(e, loss1.combine(loss2))
  • Failure(e, loss) + anything → Failure(e, loss) (short-circuits, next is discarded)
Source§

impl<E, L> Imperfect<(), E, L>
where L: Loss,

Source

pub fn settled() -> Imperfect<(), E, L>

The geometry didn’t move.

Source

pub fn measured(loss: L) -> Imperfect<(), E, L>

The geometry moved. Here’s the cost.

Source

pub fn failed(error: E, loss: L) -> Imperfect<(), E, L>

The measurement broke.

Source

pub fn is_settled(&self) -> bool

Did the geometry move?

Source

pub fn is_dirty(&self) -> bool

Did the geometry move? (inverse of is_settled)

Source

pub fn accumulate(self, other: Imperfect<(), E, L>) -> Imperfect<(), E, L>

Accumulate another measurement. If either moved, the result moved. Loss combines.

Trait Implementations§

Source§

impl<T, E, L> Clone for Imperfect<T, E, L>
where T: Clone, E: Clone, L: Clone + Loss,

Source§

fn clone(&self) -> Imperfect<T, E, L>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T, E, L> Debug for Imperfect<T, E, L>
where T: Debug, E: Debug, L: Debug + Loss,

Source§

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

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

impl<T, L> From<Option<T>> for Imperfect<T, (), L>
where L: Loss,

None maps to Failure(()) because absence is total loss — there is no value and no meaningful error to report. Some(v) maps to Success(v).

Source§

fn from(o: Option<T>) -> Imperfect<T, (), L>

Converts to this type from the input type.
Source§

impl<T, E, L> From<Result<T, E>> for Imperfect<T, E, L>
where L: Loss,

Source§

fn from(r: Result<T, E>) -> Imperfect<T, E, L>

Converts to this type from the input type.
Source§

impl<T, E, L> IntoEh<T, E, L> for Imperfect<T, E, L>
where L: Loss,

Source§

fn into_eh(self, ctx: &mut Eh<L>) -> Result<T, E>

Extract the value, accumulating loss if applicable.
Source§

impl<T, E, L> PartialEq for Imperfect<T, E, L>
where T: PartialEq, E: PartialEq, L: PartialEq + Loss,

Source§

fn eq(&self, other: &Imperfect<T, E, L>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T, E, L> StructuralPartialEq for Imperfect<T, E, L>
where L: Loss,

Auto Trait Implementations§

§

impl<T, E, L> Freeze for Imperfect<T, E, L>
where T: Freeze, L: Freeze, E: Freeze,

§

impl<T, E, L> RefUnwindSafe for Imperfect<T, E, L>

§

impl<T, E, L> Send for Imperfect<T, E, L>
where T: Send, L: Send, E: Send,

§

impl<T, E, L> Sync for Imperfect<T, E, L>
where T: Sync, L: Sync, E: Sync,

§

impl<T, E, L> Unpin for Imperfect<T, E, L>
where T: Unpin, L: Unpin, E: Unpin,

§

impl<T, E, L> UnsafeUnpin for Imperfect<T, E, L>

§

impl<T, E, L> UnwindSafe for Imperfect<T, E, L>
where T: UnwindSafe, L: UnwindSafe, E: UnwindSafe,

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> Traced for T
where T: Any + Debug + Send + Sync,

Source§

fn as_any(&self) -> &(dyn Any + 'static)

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.