PoolProfiler

Struct PoolProfiler 

Source
pub struct PoolProfiler {
    pub pool: SharedPool,
    pub tick_map: TickMap,
    pub state: PoolState,
    pub analytics: PoolAnalytics,
    pub is_initialized: bool,
    /* private fields */
}
Expand description

A DeFi pool state tracker and event processor for UniswapV3-style AMM pools.

The PoolProfiler provides complete pool state management including:

  • Liquidity position tracking and management.
  • Tick crossing and price movement simulation.
  • Fee accumulation and distribution tracking.
  • Protocol fee calculation.
  • Pool state validation and maintenance.

This profiler can both process historical events and execute new operations, making it suitable for both backtesting and simulation scenarios.

§Usage

Create a new profiler with a pool definition, initialize it with a starting price, then either process historical events or execute new pool operations to simulate trading activity and analyze pool behavior.

Fields§

§pool: SharedPool

Pool definition.

§tick_map: TickMap

Tick map managing liquidity distribution across price ranges.

§state: PoolState

Global pool state including current price, tick, and cumulative flows with fees.

§analytics: PoolAnalytics

Analytics counters tracking pool operations and performance metrics.

§is_initialized: bool

Flag indicating whether the pool has been initialized with a starting price.

Implementations§

Source§

impl PoolProfiler

Source

pub fn new(pool: SharedPool) -> Self

Creates a new PoolProfiler instance for tracking pool state and events.

§Panics

Panics if the pool’s tick spacing is not set.

Source

pub fn initialize(&mut self, price_sqrt_ratio_x96: U160)

Initializes the pool with a starting price and activates the profiler.

§Panics

This function panics if:

  • Pool is already initialized (checked via is_initialized flag)
  • Calculated tick from price doesn’t match pool’s initial_tick (if set)
Source

pub fn check_if_initialized(&self)

Verifies that the pool has been initialized.

§Panics

Panics if the pool hasn’t been initialized with a starting price via initialize().

Source

pub fn process(&mut self, event: &DexPoolData) -> Result<()>

Processes a historical pool event and updates internal state.

Handles all types of pool events (swaps, mints, burns, fee collections), and updates the profiler’s internal state accordingly. This is the main entry point for processing historical blockchain events.

§Errors

This function returns an error if:

  • Pool is not initialized.
  • Event contains invalid data (tick ranges, amounts).
  • Mathematical operations overflow.
Source

pub fn process_swap(&mut self, swap: &PoolSwap) -> Result<()>

Processes a historical swap event from blockchain data.

Replays the swap by simulating it through Self::simulate_swap_through_ticks, then verifies the simulation results against the actual event data. If mismatches are detected (tick or liquidity), the pool state is corrected to match the event values and warnings are logged.

This self-healing approach ensures pool state stays synchronized with on-chain reality even if simulation logic differs slightly from actual contract behavior.

§Use Case

Historical event processing when rebuilding pool state from blockchain events.

§Errors

This function returns an error if:

§Panics

Panics if the pool has not been initialized.

Source

pub fn execute_swap( &mut self, sender: Address, recipient: Address, block: BlockPosition, zero_for_one: bool, amount_specified: I256, sqrt_price_limit_x96: U160, ) -> Result<PoolSwap>

Executes a new simulated swap and returns the resulting event.

This is the public API for forward simulation of swap operations. It delegates the core swap mathematics to Self::simulate_swap_through_ticks, then wraps the results in a PoolSwap event structure with full metadata.

§Errors

Returns errors from Self::simulate_swap_through_ticks:

  • Pool metadata missing or invalid
  • Price limit violations
  • Arithmetic overflow in fee or liquidity calculations
§Panics

This function panics if:

  • Pool fee is not initialized
  • Pool is not initialized
Source

pub fn simulate_swap_through_ticks( &mut self, amount_specified: I256, zero_for_one: bool, sqrt_price_limit_x96: U160, ) -> Result<(I256, I256)>

Core swap simulation engine implementing UniswapV3 mathematics.

This private method contains the complete AMM swap algorithm and is the computational heart of both Self::execute_swap (forward simulation) and Self::process_swap (historical replay).

§Algorithm Overview
  1. Iterative price curve traversal: Walks through liquidity ranges until the input/output amount is exhausted or the price limit is reached
  2. Tick crossing: When reaching an initialized tick boundary, updates active liquidity by applying the tick’s liquidity_net
  3. Fee calculation: Splits fees between LPs (via fee growth globals) and protocol (via protocol fee percentage)
  4. State mutation: Updates current tick, sqrt price, liquidity, and fee growth accumulators
§Errors

Returns error if:

  • Pool fee is not configured
  • Fee growth arithmetic overflows when scaling by liquidity
  • Invalid state encountered during tick crossing
§Panics

Panics if pool is not initialized

Source

pub fn swap_exact0_for_1( &mut self, sender: Address, recipient: Address, block: BlockPosition, amount0_in: U256, sqrt_price_limit_x96: Option<U160>, ) -> Result<PoolSwap>

Swaps an exact amount of token0 for token1.

Convenience method for executing exact input swaps from token0 to token1. Sets up parameters and delegates to execute_swap.

§Errors

Returns error from Self::execute_swap when swap execution fails.

Source

pub fn swap_0_for_exact1( &mut self, sender: Address, recipient: Address, block: BlockPosition, amount1_out: U256, sqrt_price_limit_x96: Option<U160>, ) -> Result<PoolSwap>

Swaps token0 for an exact amount of token1.

Convenience method for executing exact output swaps from token0 to token1. Uses negative amount to indicate exact output specification.

§Errors

Returns error from Self::execute_swap when swap execution fails.

Source

pub fn swap_exact1_for_0( &mut self, sender: Address, recipient: Address, block: BlockPosition, amount1_in: U256, sqrt_price_limit_x96: Option<U160>, ) -> Result<PoolSwap>

Swaps an exact amount of token1 for token0.

Convenience method for executing exact input swaps from token1 to token0. Sets up parameters and delegates to execute_swap.

§Errors

Returns error from Self::execute_swap when swap execution fails.

Source

pub fn swap_1_for_exact0( &mut self, sender: Address, recipient: Address, block: BlockPosition, amount0_out: U256, sqrt_price_limit_x96: Option<U160>, ) -> Result<PoolSwap>

Swaps token1 for an exact amount of token0.

Convenience method for executing exact output swaps from token1 to token0. Uses negative amount to indicate the exact output specification.

§Errors

Returns error from Self::execute_swap when swap execution fails.

Source

pub fn swap_to_lower_sqrt_price( &mut self, sender: Address, recipient: Address, block: BlockPosition, sqrt_price_limit_x96: U160, ) -> Result<PoolSwap>

Swaps to move the pool price down to a target price.

Performs a token0-for-token1 swap with maximum input to reach the target price.

§Errors

Returns error from Self::execute_swap when swap execution fails.

Source

pub fn swap_to_higher_sqrt_price( &mut self, sender: Address, recipient: Address, block: BlockPosition, sqrt_price_limit_x96: U160, ) -> Result<PoolSwap>

Swaps to move the pool price up to a target price.

Performs a token1-for-token0 swap with maximum input to reach the target price.

§Errors

Returns error from Self::execute_swap when swap execution fails.

Source

pub fn process_mint(&mut self, update: &PoolLiquidityUpdate) -> Result<()>

Processes a mint (liquidity add) event from historical data.

Updates pool state when liquidity is added to a position, validates ticks, and delegates to internal liquidity management methods.

§Errors

This function returns an error if:

  • Pool is not initialized.
  • Tick range is invalid or not properly spaced.
  • Position updates fail.
Source

pub fn execute_mint( &mut self, recipient: Address, block: BlockPosition, tick_lower: i32, tick_upper: i32, liquidity: u128, ) -> Result<PoolLiquidityUpdate>

Executes a simulated mint (liquidity addition) operation.

Calculates required token amounts for the specified liquidity amount, updates pool state, and returns the resulting mint event.

§Errors

This function returns an error if:

  • Pool is not initialized.
  • Tick range is invalid.
  • Amount calculations fail.
§Panics

Panics if the current sqrt price has not been initialized.

Source

pub fn process_burn(&mut self, update: &PoolLiquidityUpdate) -> Result<()>

Processes a burn (liquidity removal) event from historical data.

Updates pool state when liquidity is removed from a position. Uses negative liquidity delta to reduce the position size and tracks withdrawn amounts.

§Errors

This function returns an error if:

  • Pool is not initialized.
  • Tick range is invalid.
  • Position updates fail.
Source

pub fn execute_burn( &mut self, recipient: Address, block: BlockPosition, tick_lower: i32, tick_upper: i32, liquidity: u128, ) -> Result<PoolLiquidityUpdate>

Executes a simulated burn (liquidity removal) operation.

Calculates token amounts that would be withdrawn for the specified liquidity, updates pool state, and returns the resulting burn event.

§Errors

This function returns an error if:

  • Pool is not initialized.
  • Tick range is invalid.
  • Amount calculations fail.
  • Insufficient liquidity in position.
§Panics

Panics if the current sqrt price has not been initialized.

Source

pub fn process_collect(&mut self, collect: &PoolFeeCollect) -> Result<()>

Processes a fee collect event from historical data.

Updates position state when accumulated fees are collected. Finds the position and delegates fee collection to the position object.

Note: Tick validation is intentionally skipped to match Uniswap V3 behavior. Invalid positions have no fees to collect, so they’re silently ignored.

§Errors

This function returns an error if:

  • Pool is not initialized.
Source

pub fn process_flash(&mut self, flash: &PoolFlash) -> Result<()>

Processes a flash loan event from historical data.

§Errors

Returns an error if:

  • Pool has no active liquidity.
  • Fee growth arithmetic overflows.
§Panics

Panics if the pool has not been initialized.

Source

pub fn execute_flash( &mut self, sender: Address, recipient: Address, block: BlockPosition, amount0: U256, amount1: U256, ) -> Result<PoolFlash>

Executes a simulated flash loan operation and returns the resulting event.

§Errors

Returns an error if:

  • Mathematical operations overflow when calculating fees.
  • Pool has no active liquidity.
  • Fee growth arithmetic overflows.
§Panics

Panics if:

  • Pool is not initialized
  • Pool fee is not set
Source

pub fn get_active_liquidity(&self) -> u128

Returns the pool’s active liquidity tracked by the tick map.

This represents the effective liquidity available for trading at the current price. The tick map maintains this value efficiently by updating it during tick crossings as the price moves through different ranges.

§Returns

The active liquidity (u128) at the current tick from the tick map

Source

pub fn get_total_liquidity_from_active_positions(&self) -> u128

Calculates total liquidity by summing all individual positions at the current tick.

This computes liquidity by iterating through all positions and summing those that span the current tick. Unlike Self::get_active_liquidity, which returns the maintained tick map value, this method performs a fresh calculation from position data.

Source

pub fn restore_from_snapshot(&mut self, snapshot: PoolSnapshot) -> Result<()>

Restores the profiler state from a saved snapshot.

This method allows resuming profiling from a previously saved state, enabling incremental processing without reprocessing all historical events.

§Errors

Returns an error if:

  • Tick insertion into the tick map fails.
§Panics

Panics if the pool’s tick spacing is not set.

Source

pub fn get_active_tick_values(&self) -> Vec<i32>

Gets a list of all initialized tick values.

Returns tick values that have been initialized (have liquidity positions). Useful for understanding the liquidity distribution across price ranges.

Source

pub fn get_active_tick_count(&self) -> usize

Gets the number of active ticks.

Source

pub fn get_tick(&self, tick: i32) -> Option<&PoolTick>

Gets tick information for a specific tick value.

Returns the tick data structure containing liquidity and fee information for the specified tick, if it exists.

Source

pub fn get_current_tick(&self) -> i32

Gets the current tick position of the pool.

Returns the tick that corresponds to the current pool price. The pool must be initialized before calling this method.

Source

pub fn get_total_tick_count(&self) -> usize

Gets the total number of ticks tracked by the tick map.

Returns count of all ticks that have ever been initialized, including those that may no longer have active liquidity.

§Returns

Total tick count in the tick map

Source

pub fn get_position( &self, owner: &Address, tick_lower: i32, tick_upper: i32, ) -> Option<&PoolPosition>

Gets position information for a specific owner and tick range.

Looks up a position by its unique key (owner + tick range) and returns the position data if it exists.

Source

pub fn get_active_positions(&self) -> Vec<&PoolPosition>

Returns a list of all currently active positions.

Active positions are those with liquidity > 0 whose tick range includes the current pool tick, meaning they have tokens actively deployed in the pool and are earning fees from trades at the current price.

§Returns

A vector of references to active PoolPosition objects.

Source

pub fn get_all_positions(&self) -> Vec<&PoolPosition>

Returns a list of all positions tracked by the profiler.

This includes both active and inactive positions, regardless of their liquidity or tick range relative to the current pool tick.

§Returns

A vector of references to all PoolPosition objects.

Source

pub fn extract_snapshot(&self) -> PoolSnapshot

Extracts a complete snapshot of the current pool state.

Extracts and bundles the complete pool state including global variables, all liquidity positions, and the full tick distribution into a portable PoolSnapshot structure. This snapshot can be serialized, persisted to database, or used to restore pool state later.

§Panics

Panics if no events have been processed yet.

Source

pub fn get_total_active_positions(&self) -> usize

Gets the count of positions that are currently active.

Active positions are those with liquidity > 0 and whose tick range includes the current pool tick (meaning they have tokens in the pool).

Source

pub fn get_total_inactive_positions(&self) -> usize

Gets the count of positions that are currently inactive.

Inactive positions are those that exist but don’t span the current tick, meaning their liquidity is entirely in one token or the other.

Source

pub fn estimate_balance_of_token0(&self) -> U256

Estimates the total amount of token0 in the pool.

Calculates token0 balance by summing:

  • Token0 amounts from all active liquidity positions
  • Accumulated trading fees (approximated from fee growth)
  • Protocol fees collected
Source

pub fn estimate_balance_of_token1(&self) -> U256

Estimates the total amount of token1 in the pool.

Calculates token1 balance by summing:

  • Token1 amounts from all active liquidity positions
  • Accumulated trading fees (approximated from fee growth)
  • Protocol fees collected
Source

pub fn set_fee_growth_global( &mut self, fee_growth_global_0: U256, fee_growth_global_1: U256, )

Sets the global fee growth for both tokens.

This is primarily used for testing to simulate specific fee growth scenarios. In production, fee growth is updated through swap operations.

§Arguments
  • fee_growth_global_0 - New global fee growth for token0
  • fee_growth_global_1 - New global fee growth for token1
Source

pub fn get_total_processing_time(&self) -> Duration

Returns the total time spent processing all events.

Source

pub fn get_total_events(&self) -> u64

Returns the total number of events processed.

Source

pub fn log_performance_report( &self, total_time: Duration, streaming_time: Duration, )

Logs a formatted performance report showing event processing breakdown.

Trait Implementations§

Source§

impl Clone for PoolProfiler

Source§

fn clone(&self) -> PoolProfiler

Returns a duplicate of the value. Read more
1.0.0 · Source§

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

Performs copy-assignment from source. Read more
Source§

impl Debug for PoolProfiler

Source§

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

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

impl<'py> IntoPyObject<'py> for PoolProfiler

Source§

type Target = PoolProfiler

The Python output type
Source§

type Output = Bound<'py, <PoolProfiler as IntoPyObject<'py>>::Target>

The smart pointer type to use. Read more
Source§

type Error = PyErr

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

fn into_pyobject( self, py: Python<'py>, ) -> Result<<Self as IntoPyObject<'_>>::Output, <Self as IntoPyObject<'_>>::Error>

Performs the conversion.
Source§

impl PyClass for PoolProfiler

Source§

type Frozen = False

Whether the pyclass is frozen. Read more
Source§

impl PyClassImpl for PoolProfiler

Source§

const IS_BASETYPE: bool = false

#[pyclass(subclass)]
Source§

const IS_SUBCLASS: bool = false

#[pyclass(extends=…)]
Source§

const IS_MAPPING: bool = false

#[pyclass(mapping)]
Source§

const IS_SEQUENCE: bool = false

#[pyclass(sequence)]
Source§

const IS_IMMUTABLE_TYPE: bool = false

#[pyclass(immutable_type)]
Source§

const RAW_DOC: &'static CStr = /// A DeFi pool state tracker and event processor for UniswapV3-style AMM pools. /// /// The `PoolProfiler` provides complete pool state management including: /// - Liquidity position tracking and management. /// - Tick crossing and price movement simulation. /// - Fee accumulation and distribution tracking. /// - Protocol fee calculation. /// - Pool state validation and maintenance. /// /// This profiler can both process historical events and execute new operations, /// making it suitable for both backtesting and simulation scenarios. /// /// # Usage /// /// Create a new profiler with a pool definition, initialize it with a starting price, /// then either process historical events or execute new pool operations to simulate /// trading activity and analyze pool behavior.

Docstring for the class provided on the struct or enum. Read more
Source§

const DOC: &'static CStr

Fully rendered class doc, including the text_signature if a constructor is defined. Read more
Source§

type BaseType = PyAny

Base class
Source§

type ThreadChecker = SendablePyClass<PoolProfiler>

This handles following two situations: Read more
Source§

type PyClassMutability = <<PyAny as PyClassBaseType>::PyClassMutability as PyClassMutability>::MutableChild

Immutable or mutable
Source§

type Dict = PyClassDummySlot

Specify this class has #[pyclass(dict)] or not.
Source§

type WeakRef = PyClassDummySlot

Specify this class has #[pyclass(weakref)] or not.
Source§

type BaseNativeType = PyAny

The closest native ancestor. This is PyAny by default, and when you declare #[pyclass(extends=PyDict)], it’s PyDict.
Source§

fn items_iter() -> PyClassItemsIter

Source§

fn lazy_type_object() -> &'static LazyTypeObject<Self>

§

fn dict_offset() -> Option<isize>

§

fn weaklist_offset() -> Option<isize>

Source§

impl<'a, 'holder, 'py> PyFunctionArgument<'a, 'holder, 'py, false> for &'holder PoolProfiler

Source§

type Holder = Option<PyClassGuard<'a, PoolProfiler>>

Source§

fn extract( obj: &'a Bound<'py, PyAny>, holder: &'holder mut Self::Holder, ) -> PyResult<Self>

Source§

impl<'a, 'holder, 'py> PyFunctionArgument<'a, 'holder, 'py, false> for &'holder mut PoolProfiler

Source§

type Holder = Option<PyClassGuardMut<'a, PoolProfiler>>

Source§

fn extract( obj: &'a Bound<'py, PyAny>, holder: &'holder mut Self::Holder, ) -> PyResult<Self>

Source§

impl PyMethods<PoolProfiler> for PyClassImplCollector<PoolProfiler>

Source§

fn py_methods(self) -> &'static PyClassItems

Source§

impl PyTypeInfo for PoolProfiler

Source§

const NAME: &'static str = "PoolProfiler"

Class name.
Source§

const MODULE: Option<&'static str>

Module name, if any.
Source§

fn type_object_raw(py: Python<'_>) -> *mut PyTypeObject

Returns the PyTypeObject instance for this type.
§

fn type_object(py: Python<'_>) -> Bound<'_, PyType>

Returns the safe abstraction over the type object.
§

fn is_type_of(object: &Bound<'_, PyAny>) -> bool

Checks if object is an instance of this type or a subclass of this type.
§

fn is_exact_type_of(object: &Bound<'_, PyAny>) -> bool

Checks if object is an instance of this type.
Source§

impl DerefToPyAny for PoolProfiler

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> 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.

§

impl<T> FromPyObject<'_> for T
where T: PyClass + Clone,

§

fn extract_bound(obj: &Bound<'_, PyAny>) -> Result<T, PyErr>

Extracts Self from the bound smart pointer obj. Read more
§

impl<'py, T> FromPyObjectBound<'_, 'py> for T
where T: FromPyObject<'py>,

§

fn from_py_object_bound(ob: Borrowed<'_, 'py, PyAny>) -> Result<T, PyErr>

Extracts Self from the bound smart pointer obj. Read more
§

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
§

impl<'py, T> IntoPyObjectExt<'py> for T
where T: IntoPyObject<'py>,

§

fn into_bound_py_any(self, py: Python<'py>) -> Result<Bound<'py, PyAny>, PyErr>

Converts self into an owned Python object, dropping type information.
§

fn into_py_any(self, py: Python<'py>) -> Result<Py<PyAny>, PyErr>

Converts self into an owned Python object, dropping type information and unbinding it from the 'py lifetime.
§

fn into_pyobject_or_pyerr(self, py: Python<'py>) -> Result<Self::Output, PyErr>

Converts self into a Python object. Read more
Source§

impl<'py, T> IntoPyObjectNautilusExt<'py> for T
where T: IntoPyObjectExt<'py>,

Source§

fn into_py_any_unwrap(self, py: Python<'py>) -> Py<PyAny>

Convert self into a [Py<PyAny>] while panicking if the conversion fails. Read more
§

impl<T> PyErrArguments for T
where T: for<'py> IntoPyObject<'py> + Send + Sync,

§

fn arguments(self, py: Python<'_>) -> Py<PyAny>

Arguments for exception
§

impl<T> PyTypeCheck for T
where T: PyTypeInfo,

§

const NAME: &'static str = <T as PyTypeInfo>::NAME

Name of self. This is used in error messages, for example.
§

fn type_check(object: &Bound<'_, PyAny>) -> bool

Checks if object is an instance of Self, which may include a subtype. Read more
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, 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<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

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
§

impl<T> Ungil for T
where T: Send,