Skip to main content

vox_core/
link_source.rs

1//! `LinkSource` and `Attachment`: how the session machinery is given the
2//! transport link it should use.
3//!
4//! Originally these lived in `stable_conduit` because reconnect was the
5//! only consumer. With reconnect removed, they're just "give me a link
6//! once" — kept as a trait so the existing session API still composes,
7//! and so callers that want to swap implementations (e.g. tests vs
8//! production sockets) keep working without changes.
9
10use std::future::Future;
11
12use vox_types::{Link, MaybeSend};
13
14/// One transport attachment consumed by [`LinkSource::next_link`].
15pub struct Attachment<L> {
16    link: L,
17}
18
19impl<L> Attachment<L> {
20    /// Build an attachment around a single ready-to-use link.
21    pub fn initiator(link: L) -> Self {
22        Self { link }
23    }
24
25    pub fn into_link(self) -> L {
26        self.link
27    }
28}
29
30/// Source of transport links. With reconnect machinery removed there's
31/// only ever one call to `next_link` per session, but the trait remains
32/// so existing code paths don't have to special-case the single-link
33/// case.
34pub trait LinkSource: MaybeSend + 'static {
35    type Link: Link + MaybeSend;
36
37    fn next_link(
38        &mut self,
39    ) -> impl Future<Output = std::io::Result<Attachment<Self::Link>>> + MaybeSend + '_;
40}
41
42/// One-shot link source: hands out its single attachment, then errors on
43/// every subsequent call.
44pub struct SingleAttachmentSource<L> {
45    attachment: Option<Attachment<L>>,
46}
47
48pub fn single_attachment_source<L: Link + MaybeSend + 'static>(
49    attachment: Attachment<L>,
50) -> SingleAttachmentSource<L> {
51    SingleAttachmentSource {
52        attachment: Some(attachment),
53    }
54}
55
56pub fn single_link_source<L: Link + MaybeSend + 'static>(link: L) -> SingleAttachmentSource<L> {
57    single_attachment_source(Attachment::initiator(link))
58}
59
60impl<L: Link + MaybeSend + 'static> LinkSource for SingleAttachmentSource<L> {
61    type Link = L;
62
63    async fn next_link(&mut self) -> std::io::Result<Attachment<Self::Link>> {
64        self.attachment.take().ok_or_else(|| {
65            std::io::Error::new(
66                std::io::ErrorKind::ConnectionRefused,
67                "single-use LinkSource exhausted",
68            )
69        })
70    }
71}