pub struct ClientCirc {
mutable: Arc<Mutex<MutableState>>,
unique_id: UniqId,
control: UnboundedSender<CtrlMsg>,
channel: Arc<Channel>,
reactor_closed_rx: Shared<Receiver<Void>>,
memquota: CircuitAccount,
}
Expand description
A circuit that we have constructed over the Tor network.
§Circuit life cycle
ClientCirc
s are created in an initially unusable state using Channel::new_circ
,
which returns a PendingClientCirc
. To get a real (one-hop) circuit from
one of these, you invoke one of its create_firsthop
methods (currently
create_firsthop_fast()
or
create_firsthop_ntor()
).
Then, to add more hops to the circuit, you can call
extend_ntor()
on it.
For higher-level APIs, see the tor-circmgr
crate: the ones here in
tor-proto
are probably not what you need.
After a circuit is created, it will persist until it is closed in one of five ways:
- A remote error occurs.
- Some hop on the circuit sends a
DESTROY
message to tear down the circuit. - The circuit’s channel is closed.
- Someone calls
ClientCirc::terminate
on the circuit. - The last reference to the
ClientCirc
is dropped. (Note that every stream on aClientCirc
keeps a reference to it, which will in turn keep the circuit from closing until all those streams have gone away.)
Note that in cases 1-4 the ClientCirc
object itself will still exist: it
will just be unusable for most purposes. Most operations on it will fail
with an error.
Fields§
§mutable: Arc<Mutex<MutableState>>
Mutable state shared with the Reactor
.
unique_id: UniqId
A unique identifier for this circuit.
control: UnboundedSender<CtrlMsg>
Channel to send control messages to the reactor.
channel: Arc<Channel>
The channel that this ClientCirc is connected to and using to speak with its first hop.
§Warning
Don’t use this field to send or receive any data, or perform any network operations for this circuit! All network operations should be done by the circuit reactor.
TODO: This limitation strongly suggests that we have made a mistake somewhere, and should not be holding this field in this structure. Or maybe the object that lets us send/receive from a channel should be separate from Channel itself, like how StreamTarget is separate from Circuit.
reactor_closed_rx: Shared<Receiver<Void>>
A future that resolves to Cancelled once the reactor is shut down, meaning that the circuit is closed.
memquota: CircuitAccount
Memory quota account
Implementations§
Source§impl ClientCirc
impl ClientCirc
Sourcepub fn first_hop(&self) -> OwnedChanTarget
pub fn first_hop(&self) -> OwnedChanTarget
Return a description of the first hop of this circuit.
§Panics
Panics if there is no first hop. (This should be impossible outside of the tor-proto crate, but within the crate it’s possible to have a circuit with no hops.)
Sourcepub fn last_hop_num(&self) -> Result<HopNum>
pub fn last_hop_num(&self) -> Result<HopNum>
Return the HopNum
of the last hop of this circuit.
Returns an error if there is no last hop. (This should be impossible outside of the tor-proto crate, but within the crate it’s possible to have a circuit with no hops.)
Sourcepub fn path(&self) -> Vec<OwnedChanTarget>
👎Deprecated since 0.11.1: Use path_ref() instead.
pub fn path(&self) -> Vec<OwnedChanTarget>
Return a description of all the hops in this circuit.
This method is deprecated for several reasons:
- It performs a deep copy.
- It ignores virtual hops.
- It’s not so extensible.
Use ClientCirc::path_ref()
instead.
Sourcepub fn path_ref(&self) -> Arc<Path>
pub fn path_ref(&self) -> Arc<Path>
Return a Path
object describing all the hops in this circuit.
Note that this Path
is not automatically updated if the circuit is
extended.
Sourcepub fn channel(&self) -> &Channel
pub fn channel(&self) -> &Channel
Return a reference to the channel that this circuit is connected to.
A client circuit is always connected to some relay via a Channel
.
That relay has to be the same relay as the first hop in the client’s
path.
Sourcepub fn mq_account(&self) -> &CircuitAccount
pub fn mq_account(&self) -> &CircuitAccount
Return a reference to this circuit’s memory quota account
Sourcepub fn binding_key(&self, hop: HopNum) -> Option<CircuitBinding>
pub fn binding_key(&self, hop: HopNum) -> Option<CircuitBinding>
Return the cryptographic material used to prove knowledge of a shared
secret with with hop
.
See CircuitBinding
for more information on how this is used.
Return None if we have no circuit binding information for the hop, or if the hop does not exist.
Sourcepub async fn start_conversation(
&self,
msg: Option<AnyRelayMsg>,
reply_handler: impl MsgHandler + Send + 'static,
hop_num: HopNum,
) -> Result<Conversation<'_>>
Available on crate feature send-control-msg
only.
pub async fn start_conversation( &self, msg: Option<AnyRelayMsg>, reply_handler: impl MsgHandler + Send + 'static, hop_num: HopNum, ) -> Result<Conversation<'_>>
send-control-msg
only.Start an ad-hoc protocol exchange to the specified hop on this circuit
To use this:
-
Create an inter-task channel you’ll use to receive the outcome of your conversation, and bundle it into a
MsgHandler
. -
Call
start_conversation
. This will install a your handler, for incoming messages, and send the outgoing message (if you provided one). After that, each message on the circuit that isn’t handled by the core machinery is passed to your providedreply_handler
. -
Possibly call
send_msg
on theConversation
, from the call site ofstart_conversation
, possibly multiple times, from time to time, to send further desired messages to the peer. -
In your
MsgHandler
, process the incoming messages. You may respond by sending additional messages (using theConversationInHandler
provided toMsgHandler::handle_msg
, or, outside the handler using theConversation
) When the protocol exchange is finished,MsgHandler::handle_msg
should returnConversationFinished
.
If you don’t need the Conversation
to send followup messages,
you may simply drop it,
and rely on the responses you get from your handler,
on the channel from step 0 above.
Your handler will remain installed and able to process incoming messages
until it returns ConversationFinished
.
(If you don’t want to accept any replies at all, it may be
simpler to use ClientCirc::send_raw_msg
.)
Note that it is quite possible to use this function to violate the tor protocol; most users of this API will not need to call it. It is used to implement most of the onion service handshake.
§Limitations
Only one conversation may be active at any one time, for any one circuit. This generally means that this function should not be called on a circuit which might be shared with anyone else.
Likewise, it is forbidden to try to extend the circuit, while the conversation is in progress.
After the conversation has finished, the circuit may be extended.
Or, start_conversation
may be called again;
but, in that case there will be a gap between the two conversations,
during which no MsgHandler
is installed,
and unexpected incoming messages would close the circuit.
If these restrictions are violated, the circuit will be closed with an error.
§Precise definition of the lifetime of a conversation
A conversation is in progress from entry to start_conversation
,
until entry to the body of the MsgHandler::handle_msg
call which returns ConversationFinished
.
(Entry since handle_msg
is synchronously embedded
into the incoming message processing.)
So you may start a new conversation as soon as you have the final response
via your inter-task channel from (0) above.
The lifetime relationship of the Conversation
,
vs the handler returning ConversationFinished
is not enforced by the type system.
Sourcepub async fn start_conversation_last_hop(
&self,
msg: Option<AnyRelayMsg>,
reply_handler: impl MsgHandler + Send + 'static,
) -> Result<Conversation<'_>>
👎Deprecated since 0.13.0: Use start_conversation instead.Available on crate feature send-control-msg
only.
pub async fn start_conversation_last_hop( &self, msg: Option<AnyRelayMsg>, reply_handler: impl MsgHandler + Send + 'static, ) -> Result<Conversation<'_>>
send-control-msg
only.Start an ad-hoc protocol exchange to the final hop on this circuit
See the ClientCirc::start_conversation
docs for more information.
Sourcepub async fn send_raw_msg(
&self,
msg: AnyRelayMsg,
hop_num: HopNum,
) -> Result<()>
Available on crate feature send-control-msg
only.
pub async fn send_raw_msg( &self, msg: AnyRelayMsg, hop_num: HopNum, ) -> Result<()>
send-control-msg
only.Send an ad-hoc message to a given hop on the circuit, without expecting a reply.
(If you want to handle one or more possible replies, see
ClientCirc::start_conversation
.)
Sourcepub async fn allow_stream_requests(
self: &Arc<ClientCirc>,
allow_commands: &[RelayCmd],
hop_num: HopNum,
filter: impl IncomingStreamRequestFilter,
) -> Result<impl Stream<Item = IncomingStream>>
Available on crate feature hs-service
only.
pub async fn allow_stream_requests( self: &Arc<ClientCirc>, allow_commands: &[RelayCmd], hop_num: HopNum, filter: impl IncomingStreamRequestFilter, ) -> Result<impl Stream<Item = IncomingStream>>
hs-service
only.Tell this circuit to begin allowing the final hop of the circuit to try to create new Tor streams, and to return those pending requests in an asynchronous stream.
Ordinarily, these requests are rejected.
There can only be one Stream
of this type created on a given circuit.
If a such a Stream
already exists, this method will return
an error.
After this method has been called on a circuit, the circuit is expected
to receive requests of this type indefinitely, until it is finally closed.
If the Stream
is dropped, the next request on this circuit will cause it to close.
Only onion services (and eventually) exit relays should call this method.
Sourcepub async fn extend_ntor<Tg>(
&self,
target: &Tg,
params: &CircParameters,
) -> Result<()>where
Tg: CircTarget,
pub async fn extend_ntor<Tg>(
&self,
target: &Tg,
params: &CircParameters,
) -> Result<()>where
Tg: CircTarget,
Extend the circuit via the ntor handshake to a new target last hop.
Sourcepub async fn extend_ntor_v3<Tg>(
&self,
target: &Tg,
params: &CircParameters,
) -> Result<()>where
Tg: CircTarget,
Available on crate feature ntor_v3
only.
pub async fn extend_ntor_v3<Tg>(
&self,
target: &Tg,
params: &CircParameters,
) -> Result<()>where
Tg: CircTarget,
ntor_v3
only.Extend the circuit via the ntor handshake to a new target last hop.
Sourcepub async fn extend_virtual(
&self,
protocol: RelayProtocol,
role: HandshakeRole,
seed: impl KeyGenerator,
params: CircParameters,
) -> Result<()>
Available on crate feature hs-common
only.
pub async fn extend_virtual( &self, protocol: RelayProtocol, role: HandshakeRole, seed: impl KeyGenerator, params: CircParameters, ) -> Result<()>
hs-common
only.Extend this circuit by a single, “virtual” hop.
A virtual hop is one for which we do not add an actual network connection between separate hosts (such as Relays). We only add a layer of cryptography.
This is used to implement onion services: the client and the service
both build a circuit to a single rendezvous point, and tell the
rendezvous point to relay traffic between their two circuits. Having
completed a handshake
out of band1, the parties each extend their
circuits by a single “virtual” encryption hop that represents their
shared cryptographic context.
Once a circuit has been extended in this way, it is an error to try to extend it in any other way.
Technically, the handshake is only mostly out of band: the client sends their half of the handshake in an
message, and the service's response is inline in its
RENDEZVOUS2` message. ↩
Sourceasync fn begin_stream_impl(
self: &Arc<ClientCirc>,
begin_msg: AnyRelayMsg,
cmd_checker: Box<dyn CmdChecker + Send + 'static>,
) -> Result<(StreamReader, StreamTarget, StreamAccount)>
async fn begin_stream_impl( self: &Arc<ClientCirc>, begin_msg: AnyRelayMsg, cmd_checker: Box<dyn CmdChecker + Send + 'static>, ) -> Result<(StreamReader, StreamTarget, StreamAccount)>
Helper, used to begin a stream.
This function allocates a stream ID, and sends the message (like a BEGIN or RESOLVE), but doesn’t wait for a response.
The caller will typically want to see the first cell in response, to see whether it is e.g. an END or a CONNECTED.
Sourceasync fn begin_data_stream(
self: &Arc<ClientCirc>,
msg: AnyRelayMsg,
optimistic: bool,
) -> Result<DataStream>
async fn begin_data_stream( self: &Arc<ClientCirc>, msg: AnyRelayMsg, optimistic: bool, ) -> Result<DataStream>
Start a DataStream (anonymized connection) to the given address and port, using a BEGIN cell.
Sourcepub async fn begin_stream(
self: &Arc<ClientCirc>,
target: &str,
port: u16,
parameters: Option<StreamParameters>,
) -> Result<DataStream>
pub async fn begin_stream( self: &Arc<ClientCirc>, target: &str, port: u16, parameters: Option<StreamParameters>, ) -> Result<DataStream>
Start a stream to the given address and port, using a BEGIN cell.
The use of a string for the address is intentional: you should let the remote Tor relay do the hostname lookup for you.
Sourcepub async fn begin_dir_stream(self: Arc<ClientCirc>) -> Result<DataStream>
pub async fn begin_dir_stream(self: Arc<ClientCirc>) -> Result<DataStream>
Start a new stream to the last relay in the circuit, using a BEGIN_DIR cell.
Sourcepub async fn resolve(
self: &Arc<ClientCirc>,
hostname: &str,
) -> Result<Vec<IpAddr>>
pub async fn resolve( self: &Arc<ClientCirc>, hostname: &str, ) -> Result<Vec<IpAddr>>
Perform a DNS lookup, using a RESOLVE cell with the last relay in this circuit.
Note that this function does not check for timeouts; that’s the caller’s responsibility.
Sourcepub async fn resolve_ptr(
self: &Arc<ClientCirc>,
addr: IpAddr,
) -> Result<Vec<String>>
pub async fn resolve_ptr( self: &Arc<ClientCirc>, addr: IpAddr, ) -> Result<Vec<String>>
Perform a reverse DNS lookup, by sending a RESOLVE cell with the last relay on this circuit.
Note that this function does not check for timeouts; that’s the caller’s responsibility.
Sourceasync fn try_resolve(self: &Arc<ClientCirc>, msg: Resolve) -> Result<Resolved>
async fn try_resolve(self: &Arc<ClientCirc>, msg: Resolve) -> Result<Resolved>
Helper: Send the resolve message, and read resolved message from resolve stream.
Sourcepub fn terminate(&self)
pub fn terminate(&self)
Shut down this circuit, along with all streams that are using it. Happens asynchronously (i.e. the circuit won’t necessarily be done shutting down immediately after this function returns!).
Note that other references to this circuit may exist. If they do, they will stop working after you call this function.
It’s not necessary to call this method if you’re just done with a circuit: the circuit should close on its own once nothing is using it any more.
Sourcepub(crate) fn protocol_error(&self)
pub(crate) fn protocol_error(&self)
Called when a circuit-level protocol error has occurred and the circuit needs to shut down.
This is a separate function because we may eventually want to have it do more than just shut down.
As with terminate
, this function is asynchronous.
Sourcepub fn is_closing(&self) -> bool
pub fn is_closing(&self) -> bool
Return true if this circuit is closed and therefore unusable.
Sourcepub fn n_hops(&self) -> usize
pub fn n_hops(&self) -> usize
Return the number of hops in this circuit.
NOTE: This function will currently return only the number of hops currently in the circuit. If there is an extend operation in progress, the currently pending hop may or may not be counted, depending on whether the extend operation finishes before this call is done.
Sourcepub fn wait_for_close(&self) -> impl Future<Output = ()> + Send + Sync + 'static
Available on crate feature experimental-api
only.
pub fn wait_for_close(&self) -> impl Future<Output = ()> + Send + Sync + 'static
experimental-api
only.Return a future that will resolve once this circuit has closed.
Note that this method does not itself cause the circuit to shut down.
TODO: Perhaps this should return some kind of status indication instead of just ()
Trait Implementations§
Auto Trait Implementations§
impl Freeze for ClientCirc
impl !RefUnwindSafe for ClientCirc
impl Send for ClientCirc
impl Sync for ClientCirc
impl Unpin for ClientCirc
impl !UnwindSafe for ClientCirc
Blanket Implementations§
§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> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.§impl<T> DowncastSync for T
impl<T> DowncastSync 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> 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>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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<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> 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.