use std::{
net::{SocketAddr, TcpListener as StdTcpListener},
sync::Arc,
};
use tokio::net::TcpListener;
use super::{ServerState, Unbound, WireframeServer};
use crate::{
app::Packet,
codec::FrameCodec,
preamble::Preamble,
serializer::Serializer,
server::{AppFactory, Bound, ServerError},
};
trait WireframeFactory<Ser, Ctx, E, Codec>: AppFactory<Ser, Ctx, E, Codec>
where
Ser: Serializer + Send + Sync,
Ctx: Send + 'static,
E: Packet,
Codec: FrameCodec,
{
}
impl<F, Ser, Ctx, E, Codec> WireframeFactory<Ser, Ctx, E, Codec> for F
where
F: AppFactory<Ser, Ctx, E, Codec>,
Ser: Serializer + Send + Sync,
Ctx: Send + 'static,
E: Packet,
Codec: FrameCodec,
{
}
trait WireframePreamble: Preamble {}
impl<T> WireframePreamble for T where T: Preamble {}
type BoundServer<F, T, Ser, Ctx, E, Codec> = WireframeServer<F, T, Bound, Ser, Ctx, E, Codec>;
#[expect(
private_bounds,
reason = "helper trait aliases are module-private by design"
)]
impl<F, T, S, Ser, Ctx, E, Codec> WireframeServer<F, T, S, Ser, Ctx, E, Codec>
where
F: WireframeFactory<Ser, Ctx, E, Codec>,
T: WireframePreamble,
S: ServerState,
Ser: Serializer + Send + Sync,
Ctx: Send + 'static,
E: Packet,
Codec: FrameCodec,
{
fn bind_to_listener(
self,
std_listener: StdTcpListener,
) -> Result<BoundServer<F, T, Ser, Ctx, E, Codec>, ServerError> {
let WireframeServer {
factory,
workers,
on_preamble_success,
on_preamble_failure,
ready_tx,
backoff_config,
preamble_timeout,
_app: app_marker,
_preamble: preamble_marker,
..
} = self;
std_listener
.set_nonblocking(true)
.map_err(ServerError::Bind)?;
let tokio_listener = TcpListener::from_std(std_listener).map_err(ServerError::Bind)?;
Ok(WireframeServer {
factory,
workers,
on_preamble_success,
on_preamble_failure,
ready_tx,
backoff_config,
preamble_timeout,
state: Bound {
listener: Arc::new(tokio_listener),
},
_app: app_marker,
_preamble: preamble_marker,
})
}
}
#[expect(
private_bounds,
reason = "helper trait aliases are module-private by design"
)]
impl<F, T, Ser, Ctx, E, Codec> WireframeServer<F, T, Unbound, Ser, Ctx, E, Codec>
where
F: WireframeFactory<Ser, Ctx, E, Codec>,
T: WireframePreamble,
Ser: Serializer + Send + Sync,
Ctx: Send + 'static,
E: Packet,
Codec: FrameCodec,
{
#[must_use]
pub const fn local_addr(&self) -> Option<SocketAddr> { None }
pub fn bind(
self,
addr: SocketAddr,
) -> Result<BoundServer<F, T, Ser, Ctx, E, Codec>, ServerError> {
let std_listener = StdTcpListener::bind(addr).map_err(ServerError::Bind)?;
self.bind_existing_listener(std_listener)
}
pub fn bind_existing_listener(
self,
std_listener: StdTcpListener,
) -> Result<BoundServer<F, T, Ser, Ctx, E, Codec>, ServerError> {
self.bind_to_listener(std_listener)
}
}
#[expect(
private_bounds,
reason = "helper trait aliases are module-private by design"
)]
impl<F, T, Ser, Ctx, E, Codec> WireframeServer<F, T, Bound, Ser, Ctx, E, Codec>
where
F: WireframeFactory<Ser, Ctx, E, Codec>,
T: WireframePreamble,
Ser: Serializer + Send + Sync,
Ctx: Send + 'static,
E: Packet,
Codec: FrameCodec,
{
#[must_use]
pub fn local_addr(&self) -> Option<SocketAddr> { self.state.listener.local_addr().ok() }
pub fn bind(self, addr: SocketAddr) -> Result<Self, ServerError> {
let std_listener = StdTcpListener::bind(addr).map_err(ServerError::Bind)?;
self.bind_existing_listener(std_listener)
}
pub fn bind_existing_listener(self, std_listener: StdTcpListener) -> Result<Self, ServerError> {
self.bind_to_listener(std_listener)
}
}