Skip to content

Expose a stable identifier or raw pointer for tokio::mpsc::Sender to support O(1) identity-based lookup in higher-level abstractions #7334

Open
@WIGGLES-dev

Description

@WIGGLES-dev

Summary

I’m working on an actor-style framework in Rust where each tokio::mpsc::Sender represents an addressable “mailbox.” In order to implement zero-cost proxying and O(1) routing (e.g. forwarding messages to the correct actor instance in a proxy or fan-out scenario), I need a way to distinguish one Sender from another without resorting to global registries or linear scans with is_same_channel. Currently the internal Arc that backs the sender is private, so there is no stable, hash-able identifier exposed in the public API.
Use Case

Actor proxies & fan-out: I generate code that wraps a single actor interface into multiple channels. When a proxy receives a reply it needs to forward back to the original sender in O(1) time.

Zero-cost abstractions: I want to avoid boxing or adding manual integer IDs into every ActorRef; ideally the channel handle itself would carry identity.

High-performance routing: In a large actor system or microservices mesh, linear scans over potentially thousands of mailboxes create unacceptable overhead.

Example

// Without a stable ID, proxies must scan a Vec and call is_same_channel():
for target in targets.iter() {
    if target.is_same_channel(&reply_to) {
        target.send(reply_msg).await?;
        break;
    }
}
// O(n) scan—too slow at scale.

Proposal

Add one of the following to tokio::mpsc::Sender:

fn id(&self) -> usize
Returns a stable, unique identifier (e.g. pointer or hash of the internal Arc) that remains constant for the lifetime of the channel.

fn as_ptr(&self) -> *const ()
Exposes the raw, heap-allocated pointer of the internal Arc. Users can then safely compare or hash that pointer for identity.

With either API, proxy code can build a HashMap<usize, Sender> at setup time and do O(1) lookups for forwarding.
Alternatives Considered

Manual wrapper with atomic counter:

struct IdentifiedSender<T> { id: usize, sender: Sender<T> }

Works but pushes ID-management boilerplate onto every user and duplicates functionality that already exists internally in Tokio.

Unsafe Arc pointer extraction:
Transmute the Sender wrapper to its hidden Arc<...> and call Arc::as_ptr(). Reliant on Tokio internals and brittle across versions.

Global registries:
Central HashMap<SenderKey, Sender> guarded by a lock—adds complexity, overhead, and global mutable state.

Impact & Backwards Compatibility

This would be a non-breaking API addition.

Existing code using is_same_channel continues working unchanged.

Lightweight to implement: under the hood, id() could call Arc::as_ptr(...) as usize or similar.

Enables higher-level libraries (actor frameworks, RPC proxies, debugging/tracing tools) to build more efficient routing on top of Tokio channels.

Thanks for considering this enhancement! I’m happy to provide a PR or further details if the maintainers are open to adding a stable‐identity API for Sender.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-tokioArea: The main tokio crateC-feature-requestCategory: A feature request.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions