pub struct Config {
pub listen_addr: SocketAddr,
pub external_addr: Option<SocketAddr>,
pub network: Network,
pub initial_mainnet_peers: IndexSet<String>,
pub initial_testnet_peers: IndexSet<String>,
pub cache_dir: CacheDir,
pub peerset_initial_target_size: usize,
pub crawl_new_peer_interval: Duration,
pub max_connections_per_ip: usize,
}Expand description
Configuration for networking code.
Fields§
§listen_addr: SocketAddrThe address on which this node should listen for connections.
Can be address:port or just address. If there is no configured
port, Zebra will use the default port for the configured network.
address can be an IP address or a DNS name. DNS names are
only resolved once, when Zebra starts up.
By default, Zebra listens on [::] (all IPv6 and IPv4 addresses).
This enables dual-stack support, accepting both IPv4 and IPv6 connections.
If a specific listener address is configured, Zebra will advertise it to other nodes. But by default, Zebra uses an unspecified address (“[::]:port”), which is not advertised to other nodes.
Zebra does not currently support:
- Advertising a different external IP address #1890, or
- Auto-discovering its own external IP address #1893.
However, other Zebra instances compensate for unspecified or incorrect listener addresses by adding the external IP addresses of peers to their address books.
external_addr: Option<SocketAddr>The external address of this node if any.
Zebra bind to listen_addr but this can be an internal address if the node
is behind a firewall, load balancer or NAT. This field can be used to
advertise a different address to peers making it possible to receive inbound
connections and contribute to the P2P network from behind a firewall, load balancer, or NAT.
network: NetworkThe network to connect to.
initial_mainnet_peers: IndexSet<String>A list of initial peers for the peerset when operating on mainnet.
initial_testnet_peers: IndexSet<String>A list of initial peers for the peerset when operating on testnet.
cache_dir: CacheDirAn optional root directory for storing cached peer address data.
§Configuration
Set to:
trueto read and write peer addresses to disk using the default cache path,falseto disable reading and writing peer addresses to disk,'/custom/cache/directory'to read and write peer addresses to a custom directory.
By default, all Zebra instances run by the same user will share a single peer cache.
If you use a custom cache path, you might also want to change state.cache_dir.
§Functionality
The peer cache is a list of the addresses of some recently useful peers.
For privacy reasons, the cache does not include any other information about peers, such as when they were connected to the node.
Deleting or modifying the peer cache can impact your node’s:
- reliability: if DNS or the Zcash DNS seeders are unavailable or broken
- security: if DNS is compromised with malicious peers
If you delete it, Zebra will replace it with a fresh set of peers from the DNS seeders.
§Defaults
The default directory is platform dependent, based on
dirs::cache_dir():
| Platform | Value | Example |
|---|---|---|
| Linux | $XDG_CACHE_HOME/zebra or $HOME/.cache/zebra | /home/alice/.cache/zebra |
| macOS | $HOME/Library/Caches/zebra | /Users/Alice/Library/Caches/zebra |
| Windows | {FOLDERID_LocalAppData}\zebra | C:\Users\Alice\AppData\Local\zebra |
| Other | std::env::current_dir()/cache/zebra | /cache/zebra |
§Security
If you are running Zebra with elevated permissions (“root”), create the directory for this file before running Zebra, and make sure the Zebra user account has exclusive access to that directory, and other users can’t modify its parent directories.
§Implementation Details
Each network has a separate peer list, which is updated regularly from the current
address book. These lists are stored in network/mainnet.peers and
network/testnet.peers files, underneath the cache_dir path.
Previous peer lists are automatically loaded at startup, and used to populate the initial peer set and address book.
peerset_initial_target_size: usizeThe initial target size for the peer set.
Also used to limit the number of inbound and outbound connections made by Zebra, and the size of the cached peer list.
If you have a slow network connection, and Zebra is having trouble syncing, try reducing the peer set size. You can also reduce the peer set size to reduce Zebra’s bandwidth usage.
crawl_new_peer_interval: DurationHow frequently we attempt to crawl the network to discover new peer addresses.
Zebra asks its connected peers for more peer addresses:
- regularly, every time
crawl_new_peer_intervalelapses, and - if the peer set is busy, and there aren’t any peer addresses for the next connection attempt.
max_connections_per_ip: usizeThe maximum number of peer connections Zebra will keep for a given IP address before it drops any additional peer connections with that IP.
The default and minimum value are 1.
§Security
Increasing this config above 1 reduces Zebra’s network security.
If this config is greater than 1, Zebra can initiate multiple outbound handshakes to the same IP address.
This config does not currently limit the number of inbound connections that Zebra will accept from the same IP address.
If Zebra makes multiple inbound or outbound connections to the same IP, they will be dropped
after the handshake, but before adding them to the peer set. The total numbers of inbound and
outbound connections are also limited to a multiple of peerset_initial_target_size.
Implementations§
Source§impl Config
impl Config
Sourcepub fn peerset_outbound_connection_limit(&self) -> usize
pub fn peerset_outbound_connection_limit(&self) -> usize
The maximum number of outbound connections that Zebra will open at the same time. When this limit is reached, Zebra stops opening outbound connections.
§Security
See the note at INBOUND_PEER_LIMIT_MULTIPLIER.
§Performance
Zebra’s peer set should be limited to a reasonable size, to avoid queueing too many in-flight block downloads. A large queue of in-flight block downloads can choke a constrained local network connection.
We assume that Zebra nodes have at least 10 Mbps bandwidth. Therefore, a maximum-sized block can take up to 2 seconds to download. So the initial outbound peer set adds up to 100 seconds worth of blocks to the queue. If Zebra has reached its outbound peer limit, that adds an extra 200 seconds of queued blocks.
But the peer set for slow nodes is typically much smaller, due to the handshake RTT timeout. And Zebra responds to inbound request overloads by dropping peer connections.
Sourcepub fn peerset_inbound_connection_limit(&self) -> usize
pub fn peerset_inbound_connection_limit(&self) -> usize
The maximum number of inbound connections that Zebra will accept at the same time. When this limit is reached, Zebra drops new inbound connections, without handshaking on them.
§Security
See the note at INBOUND_PEER_LIMIT_MULTIPLIER.
Sourcepub fn peerset_total_connection_limit(&self) -> usize
pub fn peerset_total_connection_limit(&self) -> usize
The maximum number of inbound and outbound connections that Zebra will have at the same time.
Sourcepub fn initial_peer_hostnames(&self) -> IndexSet<String>
pub fn initial_peer_hostnames(&self) -> IndexSet<String>
Returns the initial seed peer hostnames for the configured network.
Sourcepub async fn initial_peers(&self) -> HashSet<PeerSocketAddr>
pub async fn initial_peers(&self) -> HashSet<PeerSocketAddr>
Resolve initial seed peer IP addresses, based on the configured network, and load cached peers from disk, if available.
§Panics
If a configured address is an invalid SocketAddr or DNS name.
Sourceasync fn resolve_peers(peers: &HashSet<String>) -> HashSet<PeerSocketAddr>
async fn resolve_peers(peers: &HashSet<String>) -> HashSet<PeerSocketAddr>
Concurrently resolves peers into zero or more IP addresses, with a
timeout of a few seconds on each DNS request.
If DNS resolution fails or times out for all peers, continues retrying until at least one peer is found.
Sourceasync fn resolve_host(host: &str, max_retries: usize) -> HashSet<PeerSocketAddr>
async fn resolve_host(host: &str, max_retries: usize) -> HashSet<PeerSocketAddr>
Resolves host into zero or more IP addresses, retrying up to
max_retries times.
If DNS continues to fail, returns an empty list of addresses.
§Panics
If a configured address is an invalid SocketAddr or DNS name.
Sourceasync fn resolve_host_once(
host: &str,
) -> Result<HashSet<PeerSocketAddr>, BoxError>
async fn resolve_host_once( host: &str, ) -> Result<HashSet<PeerSocketAddr>, BoxError>
Resolves host into zero or more IP addresses.
If host is a DNS name, performs DNS resolution with a timeout of a few seconds.
If DNS resolution fails or times out, returns an error.
§Panics
If a configured address is an invalid SocketAddr or DNS name.
Sourcepub async fn load_peer_cache(&self) -> Result<HashSet<PeerSocketAddr>>
pub async fn load_peer_cache(&self) -> Result<HashSet<PeerSocketAddr>>
Returns the addresses in the peer list cache file, if available.
Sourcepub async fn update_peer_cache(
&self,
peer_list: HashSet<PeerSocketAddr>,
) -> Result<()>
pub async fn update_peer_cache( &self, peer_list: HashSet<PeerSocketAddr>, ) -> Result<()>
Atomically writes a new peer_list to the peer list cache file, if configured.
If the list is empty, keeps the previous cache file.
Also creates the peer cache directory, if it doesn’t already exist.
Atomic writes avoid corrupting the cache if Zebra panics or crashes, or if multiple Zebra instances try to read and write the same cache file.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Config
impl<'de> Deserialize<'de> for Config
Source§fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
impl Eq for Config
impl StructuralPartialEq for Config
Auto Trait Implementations§
impl Freeze for Config
impl RefUnwindSafe for Config
impl Send for Config
impl Sync for Config
impl Unpin for Config
impl UnwindSafe for Config
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
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Conv for T
impl<T> Conv for T
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.§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> 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> 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<D> OwoColorize for D
impl<D> OwoColorize for D
§fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>where
C: Color,
fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>where
C: Color,
§fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>where
C: Color,
fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>where
C: Color,
§fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>
fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>
§fn default_color(&self) -> FgColorDisplay<'_, Default, Self>
fn default_color(&self) -> FgColorDisplay<'_, Default, Self>
§fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>
fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>
§fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>
fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>
§fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>
fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>
§fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>
fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>
§fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>
fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>
§fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>
fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>
§fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>
fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>
§fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>
fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>
§fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>
fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>
§fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>
fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>
§fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>
fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>
§fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
§fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
§fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
§fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
§fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>
fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>
§fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>
fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>
§fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>
fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>
§fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>
fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>
§fn blink_fast(&self) -> BlinkFastDisplay<'_, Self>
fn blink_fast(&self) -> BlinkFastDisplay<'_, Self>
§fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>
fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>
§fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
OwoColorize::fg] or
a color-specific method, such as [OwoColorize::green], Read more§fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
OwoColorize::bg] or
a color-specific method, such as [OwoColorize::on_yellow], Read more§fn fg_rgb<const R: u8, const G: u8, const B: u8>(
&self,
) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>
fn fg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>
§fn bg_rgb<const R: u8, const G: u8, const B: u8>(
&self,
) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>
fn bg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>
§fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>
fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>
§fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>
fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>
§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
Source§impl<Response, Error> ResponseResult<Response, Error> for Response
impl<Response, Error> ResponseResult<Response, Error> for Response
Source§fn into_result(self) -> Result<Response, Error>
fn into_result(self) -> Result<Response, Error>
Result that can be sent as a response.§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.