Skip to main content

confium_net/
registry.rs

1//! Open/closed transport-kind registry.
2//!
3//! Each transport (`inproc`, `mock`, and future `tcp`/`quic`/`ws`
4//! crates) submits a [`TransportKind`] implementation via the
5//! [`register_transport!`] macro. The public [`crate::connect`] and
6//! [`crate::listen`] entry points iterate registered kinds to find the
7//! one whose `schemes()` contains the URL's scheme.
8//!
9//! Adding a new transport means adding a crate that calls
10//! `register_transport!` — no edits to existing code, mirroring the
11//! `confium-core::ffi::registry` pattern used for crypto interfaces.
12
13use url::Url;
14
15use crate::Listener;
16use crate::Result;
17use crate::Transport;
18
19/// Factory for a family of transport schemes.
20///
21/// One implementation per transport backend. The implementation
22/// advertises which URL schemes it owns and constructs connected
23/// [`Transport`] handles or [`Listener`]s for them.
24pub trait TransportKind: Sync {
25    /// URL schemes this kind owns, e.g. `["inproc"]` or
26    /// `["tcp", "tcp+tls"]`. Claimed schemes must be in
27    /// [`crate::url::KNOWN_SCHEMES`].
28    fn schemes(&self) -> &'static [&'static str];
29
30    /// Open a connected transport to the peer identified by `url`.
31    fn connect(&self, url: &Url) -> Result<Box<dyn Transport>>;
32
33    /// Begin listening for inbound connections at the address in
34    /// `url`. Transports that cannot listen (client-only) return
35    /// [`crate::error::Error::Unsupported`].
36    fn listen(&self, url: &Url) -> Result<Box<dyn Listener>>;
37}
38
39/// Wrapper around `&'static dyn TransportKind` so the kind can be
40/// registered with `inventory` and discovered at link time.
41pub struct RegisteredTransport {
42    pub kind: &'static dyn TransportKind,
43}
44
45inventory::collect!(RegisteredTransport);
46
47/// Iterator over all transport kinds registered at link time.
48pub fn iter() -> impl Iterator<Item = &'static dyn TransportKind> {
49    inventory::iter::<RegisteredTransport>().map(|r| r.kind)
50}
51
52/// Find the registered kind that owns `scheme`, if any.
53pub fn find(scheme: &str) -> Option<&'static dyn TransportKind> {
54    iter().find(|k| k.schemes().contains(&scheme))
55}
56
57/// Submit a transport kind to the link-time registry.
58///
59/// ```no_run
60/// use confium_net::{TransportKind, register_transport};
61/// # use confium_net::{Listener, Result, Transport};
62/// # use url::Url;
63/// # struct MyKind;
64/// # impl TransportKind for MyKind {
65/// #     fn schemes(&self) -> &'static [&'static str] { &["my"] }
66/// #     fn connect(&self, _: &Url) -> Result<Box<dyn Transport>> { unreachable!() }
67/// #     fn listen(&self, _: &Url) -> Result<Box<dyn Listener>> { unreachable!() }
68/// # }
69/// register_transport!(MyKind);
70/// ```
71#[macro_export]
72macro_rules! register_transport {
73    ($kind:ident) => {
74        ::inventory::submit! {
75            $crate::registry::RegisteredTransport { kind: &$kind }
76        }
77    };
78}