Skip to main content

base_endpoint/
address_endpoint.rs

1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4use crate::{BindEndpoint, BindOptions, ConnectEndpoint};
5use base_scheduler::{
6    Cancellation, OperationResult, SocketAddress, SocketBind, SocketClose, SocketConnect,
7    SocketListen, SocketOpen, SocketProtocol, SocketType,
8};
9use std::fmt;
10
11/// A TCP endpoint at one numeric IPv4 or IPv6 address. Construction performs no I/O, and operations require no resolver capability.
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub struct AddressEndpoint {
14    address: SocketAddress,
15}
16
17impl AddressEndpoint {
18    /// Describe a TCP endpoint. Port zero requests an OS-selected port when binding.
19    pub const fn new(address: SocketAddress) -> Self {
20        Self { address }
21    }
22
23    /// The configured address. A bound ephemeral port is obtained from the returned listener through the scheduler.
24    pub const fn address(&self) -> SocketAddress {
25        self.address
26    }
27}
28
29impl fmt::Display for AddressEndpoint {
30    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
31        write!(formatter, "tcp://{}", self.address)
32    }
33}
34
35impl<S> ConnectEndpoint<S> for AddressEndpoint
36where
37    S: SocketOpen + SocketConnect + SocketClose + ?Sized,
38{
39    type Connection = S::Socket;
40
41    async fn connect(
42        &self,
43        scheduler: &S,
44        cancellation: &Cancellation,
45    ) -> OperationResult<S::Socket> {
46        cancellation.check()?;
47        let socket = scheduler
48            .socket_open(
49                self.address.into(),
50                SocketType::Stream,
51                Some(SocketProtocol::Tcp),
52                cancellation,
53            )
54            .await?;
55        match scheduler
56            .socket_connect(&socket, self.address, cancellation)
57            .await
58        {
59            Ok(()) => Ok(socket),
60            Err(error) => {
61                let _ = scheduler.socket_close(socket).await;
62                Err(error)
63            }
64        }
65    }
66}
67
68impl<S> BindEndpoint<S> for AddressEndpoint
69where
70    S: SocketOpen + SocketBind + SocketListen + SocketClose + ?Sized,
71{
72    type Listener = S::Socket;
73
74    async fn bind(
75        &self,
76        scheduler: &S,
77        options: BindOptions,
78        cancellation: &Cancellation,
79    ) -> OperationResult<Vec<S::Socket>> {
80        cancellation.check()?;
81        let socket = scheduler
82            .socket_open(
83                self.address.into(),
84                SocketType::Stream,
85                Some(SocketProtocol::Tcp),
86                cancellation,
87            )
88            .await?;
89        let result = async {
90            scheduler
91                .socket_bind(&socket, self.address, cancellation)
92                .await?;
93            scheduler
94                .socket_listen(&socket, options.backlog, cancellation)
95                .await
96        }
97        .await;
98        match result {
99            Ok(()) => Ok(vec![socket]),
100            Err(error) => {
101                let _ = scheduler.socket_close(socket).await;
102                Err(error)
103            }
104        }
105    }
106}