pub struct TestCluster {
pub swarm: Swarm,
pub wallet: WalletContext,
pub fullnode_handle: FullNodeHandle,
/* private fields */
}
Fields§
§swarm: Swarm
§wallet: WalletContext
§fullnode_handle: FullNodeHandle
Implementations§
Source§impl TestCluster
impl TestCluster
pub fn rpc_client(&self) -> &HttpClient
pub fn sui_client(&self) -> &SuiClient
pub fn rpc_url(&self) -> &str
pub fn quorum_driver_api(&self) -> &QuorumDriverApi
pub fn wallet(&mut self) -> &WalletContext
pub fn wallet_mut(&mut self) -> &mut WalletContext
pub fn get_addresses(&self) -> Vec<SuiAddress>
pub fn get_address_0(&self) -> SuiAddress
pub fn get_address_1(&self) -> SuiAddress
pub fn get_address_2(&self) -> SuiAddress
pub fn fullnode_config_builder(&self) -> FullnodeConfigBuilder
pub fn committee(&self) -> Arc<Committee>
Sourcepub async fn spawn_new_fullnode(&mut self) -> FullNodeHandle
pub async fn spawn_new_fullnode(&mut self) -> FullNodeHandle
Convenience method to start a new fullnode in the test cluster.
pub async fn start_fullnode_from_config( &mut self, config: NodeConfig, ) -> FullNodeHandle
pub fn all_node_handles(&self) -> Vec<SuiNodeHandle>
pub fn all_validator_handles(&self) -> Vec<SuiNodeHandle>
pub fn get_validator_pubkeys(&self) -> Vec<AuthorityName>
pub fn get_genesis(&self) -> Genesis
pub fn stop_node(&self, name: &AuthorityName)
pub async fn stop_all_validators(&self)
pub async fn start_all_validators(&self)
pub async fn start_node(&self, name: &AuthorityName)
pub async fn spawn_new_validator( &mut self, genesis_config: ValidatorGenesisConfig, ) -> SuiNodeHandle
pub fn random_node_restarter(self: &Arc<Self>) -> RandomNodeRestarter
pub async fn get_reference_gas_price(&self) -> u64
pub async fn get_object_from_fullnode_store( &self, object_id: &ObjectID, ) -> Option<Object>
pub async fn get_latest_object_ref(&self, object_id: &ObjectID) -> ObjectRef
pub async fn get_object_or_tombstone_from_fullnode_store( &self, object_id: ObjectID, ) -> ObjectRef
pub async fn wait_for_run_with_range_shutdown_signal( &self, ) -> Option<RunWithRange>
pub async fn wait_for_run_with_range_shutdown_signal_with_timeout( &self, timeout_dur: Duration, ) -> Option<RunWithRange>
pub async fn wait_for_protocol_version( &self, target_protocol_version: ProtocolVersion, ) -> SuiSystemState
pub async fn wait_for_protocol_version_with_timeout( &self, target_protocol_version: ProtocolVersion, timeout_dur: Duration, ) -> SuiSystemState
Sourcepub async fn trigger_reconfiguration(&self)
pub async fn trigger_reconfiguration(&self)
Ask 2f+1 validators to close epoch actively, and wait for the entire network to reach the next epoch. This requires waiting for both the fullnode and all validators to reach the next epoch.
Sourcepub async fn wait_for_epoch(
&self,
target_epoch: Option<EpochId>,
) -> SuiSystemState
pub async fn wait_for_epoch( &self, target_epoch: Option<EpochId>, ) -> SuiSystemState
To detect whether the network has reached such state, we use the fullnode as the source of truth, since a fullnode only does epoch transition when the network has done so. If target_epoch is specified, wait until the cluster reaches that epoch. If target_epoch is None, wait until the cluster reaches the next epoch. Note that this function does not guarantee that every node is at the target epoch.
pub async fn wait_for_epoch_on_node( &self, handle: &SuiNodeHandle, target_epoch: Option<EpochId>, timeout_dur: Duration, ) -> SuiSystemState
pub async fn wait_for_epoch_with_timeout( &self, target_epoch: Option<EpochId>, timeout_dur: Duration, ) -> SuiSystemState
pub async fn wait_for_epoch_all_nodes(&self, target_epoch: EpochId)
Sourcepub async fn update_validator_supported_versions(
&self,
new_supported_versions: SupportedProtocolVersions,
)
pub async fn update_validator_supported_versions( &self, new_supported_versions: SupportedProtocolVersions, )
Upgrade the network protocol version, by restarting every validator with a new supported versions. Note that we don’t restart the fullnode here, and it is assumed that the fulnode supports the entire version range.
Sourcepub async fn wait_for_all_nodes_upgrade_to(&self, protocol_version: u64)
pub async fn wait_for_all_nodes_upgrade_to(&self, protocol_version: u64)
Wait for all nodes in the network to upgrade to protocol_version
.
pub async fn wait_for_authenticator_state_update(&self)
Sourcepub fn highest_protocol_version(&self) -> ProtocolVersion
pub fn highest_protocol_version(&self) -> ProtocolVersion
Return the highest observed protocol version in the test cluster.
pub async fn test_transaction_builder(&self) -> TestTransactionBuilder
pub async fn test_transaction_builder_with_sender( &self, sender: SuiAddress, ) -> TestTransactionBuilder
pub async fn test_transaction_builder_with_gas_object( &self, sender: SuiAddress, gas: ObjectRef, ) -> TestTransactionBuilder
pub fn sign_transaction(&self, tx_data: &TransactionData) -> Transaction
pub async fn sign_and_execute_transaction( &self, tx_data: &TransactionData, ) -> SuiTransactionBlockResponse
Sourcepub async fn execute_transaction(
&self,
tx: Transaction,
) -> SuiTransactionBlockResponse
pub async fn execute_transaction( &self, tx: Transaction, ) -> SuiTransactionBlockResponse
Execute a transaction on the network and wait for it to be executed on the rpc fullnode. Also expects the effects status to be ExecutionStatus::Success. This function is recommended for transaction execution since it most resembles the production path.
Sourcepub async fn execute_transaction_return_raw_effects(
&self,
tx: Transaction,
) -> Result<(TransactionEffects, TransactionEvents)>
pub async fn execute_transaction_return_raw_effects( &self, tx: Transaction, ) -> Result<(TransactionEffects, TransactionEvents)>
Different from execute_transaction
which returns RPC effects types, this function
returns raw effects, events and extra objects returned by the validators,
aggregated manually (without authority aggregator).
It also does not check whether the transaction is executed successfully.
In order to keep the fullnode up-to-date so that latter queries can read consistent
results, it calls execute_transaction_may_fail again which goes through fullnode.
This is less efficient and verbose, but can be used if more details are needed
from the execution results, and if the transaction is expected to fail.
pub async fn create_certificate( &self, tx: Transaction, client_addr: Option<SocketAddr>, ) -> Result<CertifiedTransaction>
Sourcepub async fn submit_transaction_to_validators(
&self,
tx: Transaction,
pubkeys: &[AuthorityName],
) -> Result<(TransactionEffects, TransactionEvents)>
pub async fn submit_transaction_to_validators( &self, tx: Transaction, pubkeys: &[AuthorityName], ) -> Result<(TransactionEffects, TransactionEvents)>
Execute a transaction on specified list of validators, and bypassing authority aggregator. This allows us to obtain the return value directly from validators, so that we can access more information directly such as the original effects, events and extra objects returned. This also allows us to control which validator to send certificates to, which is useful in some tests.
Sourcepub async fn fund_address_and_return_gas(
&self,
rgp: u64,
amount: Option<u64>,
funding_address: SuiAddress,
) -> ObjectRef
pub async fn fund_address_and_return_gas( &self, rgp: u64, amount: Option<u64>, funding_address: SuiAddress, ) -> ObjectRef
This call sends some funds from the seeded address to the funding address for the given amount and returns the gas object ref. This is useful to construct transactions from the funding address.
pub async fn transfer_sui_must_exceed( &self, sender: SuiAddress, receiver: SuiAddress, amount: u64, ) -> ObjectID
Auto Trait Implementations§
impl !Freeze for TestCluster
impl !RefUnwindSafe for TestCluster
impl Send for TestCluster
impl Sync for TestCluster
impl Unpin for TestCluster
impl !UnwindSafe for TestCluster
Blanket Implementations§
§impl<T> AnySync for T
impl<T> AnySync for T
§impl<U> As for U
impl<U> As for U
§fn as_<T>(self) -> Twhere
T: CastFrom<U>,
fn as_<T>(self) -> Twhere
T: CastFrom<U>,
self
to type T
. The semantics of numeric casting with the as
operator are followed, so <T as As>::as_::<U>
can be used in the same way as T as U
for numeric conversions. Read more§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
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<T> Conv for T
impl<T> Conv for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§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.§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.§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.§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.§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.§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.§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.§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.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T> FutureExt for T
impl<T> FutureExt for T
§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a Request
§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a tonic::Request
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a tonic::Request
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a tonic::Request
§impl<T> IntoSql for T
impl<T> IntoSql for T
§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered
].§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§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 more§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 more§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
§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
§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.§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.§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.§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
§impl<T, Conn> RunQueryDsl<Conn> for T
impl<T, Conn> RunQueryDsl<Conn> for T
§fn execute<'conn, 'query>(
self,
conn: &'conn mut Conn,
) -> <Conn as AsyncConnection>::ExecuteFuture<'conn, 'query>where
Conn: AsyncConnection + Send,
Self: ExecuteDsl<Conn> + 'query,
fn execute<'conn, 'query>(
self,
conn: &'conn mut Conn,
) -> <Conn as AsyncConnection>::ExecuteFuture<'conn, 'query>where
Conn: AsyncConnection + Send,
Self: ExecuteDsl<Conn> + 'query,
§fn load<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>, fn(_: Self::Stream<'conn>) -> TryCollect<Self::Stream<'conn>, Vec<U>>>where
U: Send,
Conn: AsyncConnection,
Self: LoadQuery<'query, Conn, U> + 'query,
fn load<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>, fn(_: Self::Stream<'conn>) -> TryCollect<Self::Stream<'conn>, Vec<U>>>where
U: Send,
Conn: AsyncConnection,
Self: LoadQuery<'query, Conn, U> + 'query,
§fn load_stream<'conn, 'query, U>(
self,
conn: &'conn mut Conn,
) -> Self::LoadFuture<'conn>where
Conn: AsyncConnection,
U: 'conn,
Self: LoadQuery<'query, Conn, U> + 'query,
fn load_stream<'conn, 'query, U>(
self,
conn: &'conn mut Conn,
) -> Self::LoadFuture<'conn>where
Conn: AsyncConnection,
U: 'conn,
Self: LoadQuery<'query, Conn, U> + 'query,
Stream
] with the returned rows. Read more§fn get_result<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, Map<StreamFuture<Pin<Box<Self::Stream<'conn>>>>, fn(_: (Option<Result<U, Error>>, Pin<Box<Self::Stream<'conn>>>)) -> Result<U, Error>>, fn(_: Self::Stream<'conn>) -> Map<StreamFuture<Pin<Box<Self::Stream<'conn>>>>, fn(_: (Option<Result<U, Error>>, Pin<Box<Self::Stream<'conn>>>)) -> Result<U, Error>>>where
U: Send + 'conn,
Conn: AsyncConnection,
Self: LoadQuery<'query, Conn, U> + 'query,
fn get_result<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, Map<StreamFuture<Pin<Box<Self::Stream<'conn>>>>, fn(_: (Option<Result<U, Error>>, Pin<Box<Self::Stream<'conn>>>)) -> Result<U, Error>>, fn(_: Self::Stream<'conn>) -> Map<StreamFuture<Pin<Box<Self::Stream<'conn>>>>, fn(_: (Option<Result<U, Error>>, Pin<Box<Self::Stream<'conn>>>)) -> Result<U, Error>>>where
U: Send + 'conn,
Conn: AsyncConnection,
Self: LoadQuery<'query, Conn, U> + 'query,
§fn get_results<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>, fn(_: Self::Stream<'conn>) -> TryCollect<Self::Stream<'conn>, Vec<U>>>where
U: Send,
Conn: AsyncConnection,
Self: LoadQuery<'query, Conn, U> + 'query,
fn get_results<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>, fn(_: Self::Stream<'conn>) -> TryCollect<Self::Stream<'conn>, Vec<U>>>where
U: Send,
Conn: AsyncConnection,
Self: LoadQuery<'query, Conn, U> + 'query,
Vec
with the affected rows. Read more§fn first<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<<Self::Output as LoadQuery<'query, Conn, U>>::LoadFuture<'conn>, Map<StreamFuture<Pin<Box<<Self::Output as LoadQuery<'query, Conn, U>>::Stream<'conn>>>>, fn(_: (Option<Result<U, Error>>, Pin<Box<<Self::Output as LoadQuery<'query, Conn, U>>::Stream<'conn>>>)) -> Result<U, Error>>, fn(_: <Self::Output as LoadQuery<'query, Conn, U>>::Stream<'conn>) -> Map<StreamFuture<Pin<Box<<Self::Output as LoadQuery<'query, Conn, U>>::Stream<'conn>>>>, fn(_: (Option<Result<U, Error>>, Pin<Box<<Self::Output as LoadQuery<'query, Conn, U>>::Stream<'conn>>>)) -> Result<U, Error>>>
fn first<'query, 'conn, U>( self, conn: &'conn mut Conn, ) -> AndThen<<Self::Output as LoadQuery<'query, Conn, U>>::LoadFuture<'conn>, Map<StreamFuture<Pin<Box<<Self::Output as LoadQuery<'query, Conn, U>>::Stream<'conn>>>>, fn(_: (Option<Result<U, Error>>, Pin<Box<<Self::Output as LoadQuery<'query, Conn, U>>::Stream<'conn>>>)) -> Result<U, Error>>, fn(_: <Self::Output as LoadQuery<'query, Conn, U>>::Stream<'conn>) -> Map<StreamFuture<Pin<Box<<Self::Output as LoadQuery<'query, Conn, U>>::Stream<'conn>>>>, fn(_: (Option<Result<U, Error>>, Pin<Box<<Self::Output as LoadQuery<'query, Conn, U>>::Stream<'conn>>>)) -> Result<U, Error>>>
§impl<T> Tap for T
impl<T> Tap for T
§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 more§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 more§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 more§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 more§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 more§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 more§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.§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.§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.§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.§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.§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.§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.