Skip to main content

SessionManager

Struct SessionManager 

Source
pub struct SessionManager<S> {
    session_initiations: Cache<StartChallenge, MTx<One<Result<StartEstablished<SessionId>, StartErrorType<SessionId>>>>>,
    session_notifiers: Arc<OnceLock<(Arc<Mutex<Pin<Box<dyn Sink<IncomingSession, Error = SessionManagerError> + Send>>>>, MTx<Array<(SessionId, ClosureReason)>>)>>,
    start_protocol_tx: Arc<OnceLock<MTx<Array<(HoprPseudonym, HoprStartProtocol)>>>>,
    active_sessions: Arc<AtomicUsize>,
    sessions: Cache<SessionId, SessionSlot>,
    msg_sender: Arc<OnceLock<S>>,
    pix_toolbox: Arc<OnceLock<PixToolbox>>,
    cfg: SessionManagerConfig,
    slot_allocated: Arc<Mutex<HashMap<SessionId, Vec<Sender<()>>>>>,
}
Expand description

Manages lifecycles of Sessions.

Once the manager is started, the SessionManager::dispatch_message should be called for each [ApplicationData] received by the node. This way, the SessionManager takes care of proper Start sub-protocol message processing and correct dispatch of Session-related packets to individual existing Sessions.

Secondly, the manager can initiate new outgoing sessions via SessionManager::new_session, probe sessions using SessionManager::ping_session and list them via SessionManager::active_sessions.

Since the SessionManager operates over the HOPR protocol, the message transport S is required. Such transport must also be Clone, since it will be cloned into all the created HoprSession objects.

§SURB balancing

The manager also can take care of automatic SURB balancing per Session.

With each packet sent from the session initiator over to the receiving party, zero to 2 SURBs might be delivered. When the receiving party wants to send reply packets back, it must consume 1 SURB per packet. This means that if the difference between the SURBs delivered and SURBs consumed is negative, the receiving party might soon run out of SURBs. If SURBs run out, the reply packets will be dropped, causing likely quality of service degradation.

In an attempt to counter this effect, there are two co-existing automated modes of SURB balancing: local SURB balancing and remote SURB balancing.

§Local SURB balancing

Local SURB balancing is performed on the sessions that were initiated by another party (and are therefore incoming to us). The local SURB balancing mechanism continuously evaluates the rate of SURB consumption and retrieval, and if SURBs are running out, the packet egress shaping takes effect. This by itself does not avoid the depletion of SURBs but slows it down in the hope that the initiating party can deliver more SURBs over time. This might happen either organically by sending effective payloads that allow non-zero number of SURBs in the packet, or non-organically by delivering KeepAlive messages via remote SURB balancing.

The egress shaping is done automatically, unless the Session initiator sets the Capability::NoRateControl flag during Session initiation.

§Remote SURB balancing

Remote SURB balancing is performed by the Session initiator. The SURB balancer estimates the number of SURBs delivered to the other party, and also the number of SURBs consumed by seeing the amount of traffic received in replies. When enabled, a desired target level of SURBs at the Session counterparty is set. According to measured inflow and outflow of SURBs to/from the counterparty, the production of non-organic SURBs is started via keep-alive messages (sent to counterparty) and is controlled to maintain that target level.

In other words, the Session initiator tries to compensate for the usage of SURBs by the counterparty by sending new ones via the keep-alive messages.

This mechanism is configurable via the surb_management field in SessionClientConfig.

§Possible scenarios

There are 4 different scenarios of local vs. remote SURB balancing configuration, but an equilibrium (= matching the SURB production and consumption) is most likely to be reached only when both are configured (the ideal case below):

§1. Ideal local and remote SURB balancing
  1. The Session recipient (Exit) set the initial_return_session_egress_rate, max_surb_buffer_duration and maximum_surb_buffer_size values in the SessionManagerConfig.
  2. The Session initiator (Entry) sets the target_surb_buffer_size which matches the maximum_surb_buffer_size of the counterparty.
  3. The Session initiator (Entry) does NOT set the Capability::NoRateControl capability flag when opening Session.
  4. The Session initiator (Entry) sets max_surbs_per_sec slightly higher than the maximum_surb_buffer_size / max_surb_buffer_duration value configured at the counterparty.

In this situation, the maximum Session egress from Exit to the Entry is given by the maximum_surb_buffer_size / max_surb_buffer_duration ratio. If there is enough bandwidth, the (remote) SURB balancer sending SURBs to the Exit will stabilize roughly at this rate of SURBs/sec, and the whole system will be in equilibrium during the Session’s lifetime (under ideal network conditions).

§2. Remote SURB balancing only
  1. The Session initiator (Entry) DOES set the Capability::NoRateControl capability flag when opening Session.
  2. The Session initiator (Entry) sets max_surbs_per_sec and target_surb_buffer_size values in SurbBalancerConfig

In this one-sided situation, the Entry node floods the Exit node with SURBs, only based on its estimated consumption of SURBs at the Exit. The Exit’s egress is not rate-limited at all. If the Exit runs out of SURBs at any point in time, it will simply drop egress packets.

This configuration could potentially only lead to an equilibrium when the SurbBalancer at the Entry can react fast enough to Exit’s demand.

§3. Local SURB balancing only
  1. The Session recipient (Exit) set the initial_return_session_egress_rate, max_surb_buffer_duration and maximum_surb_buffer_size values in the SessionManagerConfig.
  2. The Session initiator (Entry) does NOT set the Capability::NoRateControl capability flag when opening Session.
  3. The Session initiator (Entry) does NOT set the SurbBalancerConfig at all when opening Session.

In this one-sided situation, the Entry node does not provide any additional SURBs at all (except the ones that are naturally carried by the egress packets which have space to hold SURBs). It relies only on the Session egress limiting of the Exit node. The Exit will limit the egress roughly to the rate of natural SURB occurrence in the ingress.

This configuration could potentially only lead to an equilibrium when uploading non-full packets (ones that can carry at least a single SURB), and the Exit’s egress is limiting itself to such a rate. If Exit’s egress reaches low values due to SURB scarcity, the upper layer protocols over Session might break.

§4. No SURB balancing on each side
  1. The Session initiator (Entry) DOES set the Capability::NoRateControl capability flag when opening Session.
  2. The Session initiator (Entry) does NOT set the SurbBalancerConfig at all when opening Session.

In this situation, no additional SURBs are being produced by the Entry and no Session egress rate-limiting takes place at the Exit.

This configuration can only lead to an equilibrium when Entry sends non-full packets (ones that carry at least a single SURB) and the Exit is consuming the SURBs (Session egress) at a slower or equal rate. Such configuration is very fragile, as any disturbances in the SURB flow might lead to a packet drop at the Exit’s egress.

§SURB decay

In a hypothetical scenario of a non-zero packet loss, the Session initiator (Entry) might send a certain number of SURBs to the Session recipient (Exit), but only a portion of it is actually delivered. The Entry has no way of knowing that and assumes that everything has been delivered. A similar problem happens when the Exit uses SURBs to construct return packets, but only a portion of those packets is actually delivered to the Entry. At this point, the Entry also subtracts fewer SURBs from its SURB estimate at the Exit.

In both situations, the Entry thinks there are more SURBs available at the Exit than there really are.

To compensate for a potential packet loss, the Entry’s estimation of Exit’s SURB buffer is regularly diminished by a percentage of the target_surb_buffer_size, even if no incoming traffic from the Exit is detected.

This behavior can be controlled via the surb_decay field of SurbBalancerConfig.

§SURB balance and target notification

The Session recipient (Exit) can notify the Session initiator (Entry) periodically about its estimated number of SURBs for the Session. This can help the Entry to adjust its approximation of that level so that its Local SURB balancer can better intervene. This can be set using the surb_balance_notify_period field of SessionManagerConfig for the Exit.

Likewise, the Entry can inform the Exit about its desired SURB buffer target so that the Exit can better accommodate its Remote SURB balancing. This can be set using the surb_target_notify field of the SessionManagerConfig of each new Session.

Both mechanisms leverage the Keep Alive message to report the respective values.

§PIX (Protocol for Incentivization of eXits) Protocol Flow

When a Session is opened with the Capability::UsePIX flag, the following protocol runs between the Entry (initiator) and Exit (recipient) to provide on-chain payment guarantees for the data relayed through the Session.

§1. PIX Parameter Negotiation (Session Initiation)

During SessionManager::new_session, the Entry encodes its PIX SSA (Session Stealth Address) parameters — a PixParams quadruple of polys_per_ssa, shares_per_poly, surplus_shares and the curve suite — into the upper 32 bits of the StartSession.additional_data field, via PixParams::into_additional_data. The first two describe how many polynomials and shares each SSA will use; the third is how many extra shares per polynomial the Entry emits to absorb losses. Those three define the data quota per SSA, which is polys × (threshold + surplus) × PAYLOAD_SIZE — the surplus is priced in rather than free, since a cycle emits it whether or not any share is lost (see pix_params_to_quota).

The fourth is not a dimension and does not enter the quota: it names the elliptic curve the Entry’s build instantiates PIX over, which fixes the width of every curve-sized field later in the handshake. It is fixed at build time on both sides and is therefore not negotiated — the Exit refuses anything but its own, below.

What is announced is built from the installed SsaShareGenerator’s SsaGeneratorConfig, never from the caller: the generator is what produces the shares that go on the wire, so advertising anything else would let the Session proceed while emitting shares the Exit cannot reconstruct. The caller’s pix_ssa_quota is an assertion about this node’s own PIX configuration, and a disagreement is refused so a caller whose belief is stale fails loudly rather than silently getting a different per-SSA quota — and so differently sized deposits — than it sized for. That check runs before the initiation challenge slot is reserved, so repeated misconfigurations cannot exhaust challenge slots.

On the Exit side, check_pix_params validates these parameters against:

  • The protocol ranges, which PixParams::try_from_additional_data enforces as it unpacks.
  • The configured IncomingSessionPixConfig::quota_range (by default derived from the default PIX dimensions: ≈162 MiB–649 MiB per SSA).
  • Optionally, IncomingSessionPixConfig::enforce_pix rejects Sessions that do not offer PIX.
  • The Exit only checks the product polys × (threshold + surplus), not the individual values, so the Entry can split it to suit its computing power. The computation is easily parallelizable in the number of polynomials, but not in threshold. The surplus is inside that product, so redundancy is bought rather than taken: a cycle emits threshold + surplus shares per polynomial come what may, and the deposit covers all of them.

If parameters are rejected, a [StartErrorReason::UnacceptablePixParams] error is returned.

§2. Exit SSA Request (SsaRequest → Entry)

Once the PIX parameters are accepted, the Exit calls request_next_ssa to create a new SSA commitment via the server-side SsaReconstructor. This produces an Exit commitment (a group element) that is sent back to the Entry as a [SsaServerCommitmentMessage].

One message can carry a whole batch of them: IncomingSessionPixConfig::ssas_per_request SSAs at contiguous indices, sharing the single params field, since every SSA in a Session uses the same negotiated dimensions. The Entry caps what it will accept at SessionManagerConfig::max_ssas_per_ssa_request, and rejects an over-cap request in full while replying with an UnacceptablePixParams [StartErrorType] so the Exit does not have to infer the refusal from its own deposit timeout. The default is a batch of one, which is byte-for-byte the unbatched exchange.

The Exit also installs a PIX kill switch per requested index — one shared deadline of ssas_per_request × (max_deposit_wait + max_ssa_delivery_time). Scaling it by the batch size is what lets an Entry work through a batch in order; any single deposit may be late as long as the batch lands inside the window. If a deposit is still missing when the deadline passes, the Session is closed with ClosureReason::UnrealizedDeposit.

§3. Entry SSA Commitment (SsaCommit → Exit)

Upon receiving the [SsaServerCommitmentMessage], the Entry’s handle_ssa_request generates a client commitment using the shared SsaShareGenerator (which is also used by the packet pipeline to embed PIX shares into return-path SURBs). The client commitment is combined with the Exit commitment to derive the on-chain deposit address via HoprPixSpec::group_to_deposit_address.

The Entry then sends one or more [SsaClientCommitmentMessage]s back to the Exit and emits a HoprSessionOutPixEvent::ReadyToDeposit to the upper layer, signaling that funds can be deposited at the computed address.

§4. Deposit Awaiting (Exit Side)

The Exit receives the client commitment messages in handle_ssa_commit, inserts the coefficient commitments into the SsaReconstructor, and extracts the deposit address. It emits HoprSessionOutPixEvent::DepositNeeded to the upper layer with the AgreedSsaQuota and a channel to confirm the deposit.

A deposit awaiter task waits for the deposit confirmation. Once confirmed, the PIX kill switch is aborted. If the deposit times out, the kill switch closes the Session. The awaiter’s own timeout is scaled by ssas_per_request too, and has to be: it is the only thing that aborts the kill switch, so an awaiter that gave up before the widened deadline would let a legitimately-late deposit go unobserved and the Session be closed for an unrealized deposit that was in fact realized.

§5. SSA Collection, Recovery and Pipelining

As the Entry sends return-path SURBs during the Session, each SURB can carry a PIX share generated from the client’s polynomial set. The Exit’s SsaReconstructor collects these shares.

When the reconstructor reaches the early recovery threshold (≈85%), an HoprSessionInPixEvent::SsaAlmostRecovered event fires, which triggers request_next_ssa for the next SSA index — pipelining the costly commitment exchange with the tail of the share collection for the current SSA.

Once fully recovered, HoprSessionInPixEvent::SsaRecovered fires, allowing the Exit to unlock and redeem the deposited funds. The deposit awaiter for the next SSA replaces the kill switch aborted for the previous one.

§6. Unverifiable Shares

Shares are not checked individually. Once a polynomial has collected threshold of them, the reconstructor interpolates its constant term and compares it against the commitment; if they disagree, at least one of those shares did not come from the committed polynomial and an HoprSessionInPixEvent::UnverifiableShare event fires. MAX_ALLOWED_UNVERIFIABLE_PIX_SHARES is 0, so the first such event closes the Session — the cycle is already unrecoverable, and closing immediately caps what a malicious Entry is served at threshold packets.

§Configuring PIX at the Exit

The Exit configures PIX via IncomingSessionPixConfig within SessionManagerConfig.

The PixToolbox (holding the SsaShareGenerator and SsaReconstructor) must be provided via SessionManager::start for PIX to function.

Fields§

§session_initiations: Cache<StartChallenge, MTx<One<Result<StartEstablished<SessionId>, StartErrorType<SessionId>>>>>§session_notifiers: Arc<OnceLock<(Arc<Mutex<Pin<Box<dyn Sink<IncomingSession, Error = SessionManagerError> + Send>>>>, MTx<Array<(SessionId, ClosureReason)>>)>>§start_protocol_tx: Arc<OnceLock<MTx<Array<(HoprPseudonym, HoprStartProtocol)>>>>§active_sessions: Arc<AtomicUsize>

Authoritative session count for admission control. Incremented atomically inside allocate_session_slot before the cache insertion, and decremented at every removal path (explicit close, eviction, guard rollback).

§sessions: Cache<SessionId, SessionSlot>§msg_sender: Arc<OnceLock<S>>§pix_toolbox: Arc<OnceLock<PixToolbox>>§cfg: SessionManagerConfig§slot_allocated: Arc<Mutex<HashMap<SessionId, Vec<Sender<()>>>>>

Per-SessionId waiters notified when a new session slot is allocated. Lets message handlers that arrive before the slot insertion completes (e.g. SsaRequest vs SessionEstablished) await the slot once instead of busy-looping with sleeps. Keyed by SessionId so that only waiters for the relevant session are woken.

Implementations§

Source§

impl<S> SessionManager<S>
where S: Sink<(DestinationRouting, ApplicationDataOut)> + Clone + Send + Sync + Unpin + 'static, S::Error: Error + Send + Sync + Clone + 'static,

Source

pub fn new(cfg: SessionManagerConfig) -> Self

Creates a new instance given the config.

Source

pub fn start<T>( &self, msg_sender: S, new_session_notifier: T, pix: Option<PixToolbox>, ) -> Result<Vec<AbortHandle>>
where T: Sink<IncomingSession> + Send + 'static, T::Error: Error + Send + Sync + 'static,

Starts the instance with the given msg_sender Sink and a channel new_session_notifier used to notify when a new incoming session is opened to us.

Optionally, the PIX processor and event sink can be provided for handling PIX protocol. If not specified, the SessionManager will not handle PIX protocol.

This method must be called prior to any calls to SessionManager::new_session or SessionManager::dispatch_message.

Source

pub fn is_started(&self) -> bool

Check if start has been called and the instance is running.

Source

fn allocate_session_slot( &self, session_id: SessionId, slot: SessionSlot, ) -> Option<SessionSlotGuard<'_>>

Atomically allocates a new SessionSlot for session_id and returns an RAII SessionSlotGuard for it.

Establishing a session involves several fallible steps after the slot has been inserted. The returned guard rolls the slot back - tearing the partially established session down via close_session - unless it is committed.

The active-sessions gauge is incremented here, atomically with the insertion and the guard creation, precisely so that it is always paired with the guard’s rollback decrement (performed through close_session). This keeps the gauge accurate: it is never decremented for a slot that was not counted in the first place, and every counted slot is decremented exactly once when it leaves the cache.

Returns None if a slot for session_id already exists; in that case nothing is inserted, the gauge is left untouched, and no guard is produced. The atomic entry API guarantees that only one concurrent caller can claim the slot for a given pseudonym (avoiding a TOCTOU race), which also rules out loopback sessions onto ourselves.

Capacity is enforced by an atomic counter incremented before the cache insertion, making it impossible for two concurrent callers (with different session IDs) to both succeed when the cache is already at maximum_sessions.

Source

pub async fn new_session( &self, destination: Address, target: SessionTarget, cfg: SessionClientConfig, ) -> Result<HoprSession>

Initiates a new outgoing Session to destination with the given configuration.

If the Session’s counterparty does not respond within the configured period, this method returns TransportSessionError::Timeout.

It will also fail if the instance has not been started.

Source

pub async fn ping_session(&self, id: &SessionId) -> Result<()>

Sends a keep-alive packet with the given SessionId.

This currently “fires & forgets” and does not expect nor await any “pong” response.

Source

async fn request_next_ssa( &self, session_id: SessionId, slot: SessionSlot, expected_ssa_index: Option<SsaIndex>, ) -> Result<()>

Source

pub fn num_active_sessions(&self) -> usize

Returns the current number of active sessions.

Source

pub fn active_sessions(&self) -> Vec<SessionId>

Returns SessionIds of all currently active sessions.

Source

pub fn close_session(&self, id: &SessionId) -> bool

Explicitly closes the session with the given id.

Removes the entry from the internal session cache, closes the data channel, and aborts any auxiliary tasks. Returns true if a session was found and closed, false otherwise.

This avoids waiting for the idle timeout (time_to_idle) or the LRU capacity bound to evict the entry, which is the desired behaviour when the caller (e.g. REST DELETE /session) knows the session is finished.

Source

pub fn update_surb_balancer_config( &self, id: &SessionId, config: SurbBalancerConfig, ) -> Result<()>

Updates the configuration of the SURB balancer on the given SessionId.

Returns an error if the Session with the given id does not exist, or if it does not use SURB balancing.

Source

pub fn get_surb_balancer_config( &self, id: &SessionId, ) -> Result<Option<SurbBalancerConfig>>

Retrieves the configuration of SURB balancing for the given Session.

Returns an error if the Session with the given id does not exist.

Source

pub fn get_surb_level_estimates(&self, id: &SessionId) -> Result<(u64, u64)>

Gets estimations produced/received and consumed SURBs by the Session.

For an outgoing Session (Entry) the pair is the number of SURBs sent (by us) and used (by the Exit). For an incoming Session (Exit) the pair is the number of SURBs received (from Entry) and used (by us).

Returns an error if the Session with the given id does not exist.

Source

pub async fn dispatch_pix_event( &self, event: HoprSessionInPixEvent, ) -> Result<()>

Dispatches HoprSessionInPixEvent that notifies the SessionManager about PIX protocol state update.

Such an event can affect existing Sessions that use the PIX protocol.

Source

pub fn mark_return_path_degraded( &self, destination: &NodeId, grace: Duration, ) -> usize

Marks the return path to destination as degraded on every Session routed there.

The Session layer cannot tell a dead return path from a peer with nothing to say – both simply stop consuming SURBs – so the judgement is made where sibling paths can be compared and delivered here. Sessions that did not opt in ignore the mark; the rest stop trusting their counterparty buffer estimate for grace.

Returns how many Sessions were marked, which is zero when nothing currently routes there.

Source

pub fn dispatch_message( &self, pseudonym: HoprPseudonym, in_data: ApplicationDataIn, ) -> Result<DispatchResult>

The main method to be called whenever data are received.

It tries to recognize the message and correctly dispatches either the Session protocol or Start protocol messages.

If the data are not recognized, they are returned as DispatchResult::Unrelated.

Source

fn check_pix_params( &self, req: &StartInitiation<SessionTarget, HoprSessionCapabilities>, ) -> Option<PixParams>

Checks the PIX parameters offered by the Entry during the Session Initiation.

Returns the validated parameters, or None if the offered parameters were rejected.

Source

async fn handle_incoming_session_initiation( &self, pseudonym: HoprPseudonym, session_req: StartInitiation<SessionTarget, HoprSessionCapabilities>, ) -> Result<()>

Source

async fn handle_session_established( &self, est: StartEstablished<SessionId>, ) -> Result<()>

Source

async fn handle_session_error( &self, error_type: StartErrorType<SessionId>, ) -> Result<()>

Source

async fn handle_keep_alive( &self, msg: KeepAliveMessage<SessionId>, ) -> Result<()>

Source

async fn handle_ssa_commit( &self, pseudonym: HoprPseudonym, msg: SsaClientCommitmentMessage<SessionId, HoprPixGroupElement, HoprPixCommitmentProof>, ) -> Result<()>

Handled by the Exit, when Entry replies with PIX commitment

Source

async fn refuse_ssa_request( &self, session_id: SessionId, routing: DestinationRouting, )

Tells the Exit that its [SsaServerCommitmentMessage] was refused, and tears down this half of the Session.

Without the notification the refusal is invisible to the Exit, and it has no way to recover from it: it armed one kill switch per requested index before sending, it will never receive an SsaCommit, and no PIX event can fire to make it re-request — request_next_ssa is only reached from establishment and from share-recovery events, and no shares are produced for a cycle the Entry never committed to. So it serves the Session unincentivized for the whole ssas_per_request × (max_deposit_wait + max_ssa_delivery_time) window and then closes it as UnrealizedDeposit — a reason that names the deposit rather than the refusal, on the one node whose operator can act on it. Telling it collapses that to roughly one round trip and puts the cause in its log where the failure happens.

The Exit’s handle_session_error closes the Session on a SessionId-identified error, which also retires the reconstructor cycles it registered for the batch rather than leaving them to their own expiry. It sends nothing back, so there is no error exchange to loop.

No new capability is handed to an attacker by closing on a refusal: an SsaRequest only reaches here Sphinx-authenticated and with pseudonym == session_id, so only the Exit can produce one — and the Exit can already close the Session whenever it likes.

Best-effort. A failed send changes nothing, because the Exit’s kill switch remains the backstop; the local close is unconditional because a refused request is terminal for the Session either way (the Exit re-derives every request from state that cannot drift within a Session, so a later one would be refused identically), and leaving the slot up would keep an unusable Session alive until the idle timeout.

Source

async fn handle_ssa_request( &self, pseudonym: HoprPseudonym, msg: SsaServerCommitmentMessage<SessionId, HoprPixGroupElement, HoprPixDepositData>, ) -> Result<()>

Handled by the Entry, when the Exit sends PIX initiation request

Trait Implementations§

Source§

impl<S> Clone for SessionManager<S>

Source§

fn clone(&self) -> Self

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

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

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl<S> !RefUnwindSafe for SessionManager<S>

§

impl<S> !UnwindSafe for SessionManager<S>

§

impl<S> Freeze for SessionManager<S>

§

impl<S> Send for SessionManager<S>
where S: Sync + Send,

§

impl<S> Sync for SessionManager<S>
where S: Sync + Send,

§

impl<S> Unpin for SessionManager<S>

§

impl<S> UnsafeUnpin for SessionManager<S>

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
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

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
§

impl<T> Conv for T

§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

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

§

impl<T> FmtForward for T

§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> FutureExt for T

§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. 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<T> Pipe for T
where T: ?Sized,

§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows 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) -> R
where R: 'a,

Mutably borrows 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
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows 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
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows 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
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
§

impl<T> Tap for T

§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .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
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .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
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
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
§

impl<T> TryConv for T

§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. 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