use std::{marker::PhantomData, mem::MaybeUninit, sync::Arc};
use enet_sys::{
enet_host_bandwidth_limit, enet_host_channel_limit, enet_host_check_events, enet_host_connect,
enet_host_destroy, enet_host_flush, enet_host_service, ENetHost, ENetPeer,
ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT,
};
use crate::{Address, EnetKeepAlive, Error, Event, Peer};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BandwidthLimit {
Unlimited,
Limited(u32),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ChannelLimit {
Maximum,
Limited(enet_sys::size_t),
}
impl ChannelLimit {
pub(in crate) fn to_enet_val(self) -> enet_sys::size_t {
match self {
ChannelLimit::Maximum => 0,
ChannelLimit::Limited(l) => l,
}
}
fn from_enet_val(enet_val: enet_sys::size_t) -> ChannelLimit {
const MAX_COUNT: enet_sys::size_t = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT as enet_sys::size_t;
match enet_val {
MAX_COUNT => ChannelLimit::Maximum,
0 => panic!("ChannelLimit::from_enet_usize: got 0"),
lim => ChannelLimit::Limited(lim),
}
}
}
impl BandwidthLimit {
pub(in crate) fn to_enet_u32(self) -> u32 {
match self {
BandwidthLimit::Unlimited => 0,
BandwidthLimit::Limited(l) => l,
}
}
}
pub struct Host<T> {
inner: *mut ENetHost,
_keep_alive: Arc<EnetKeepAlive>,
_peer_data: PhantomData<*const T>,
}
impl<T> Host<T> {
pub(in crate) fn new(_keep_alive: Arc<EnetKeepAlive>, inner: *mut ENetHost) -> Host<T> {
assert!(!inner.is_null());
Host {
inner,
_keep_alive,
_peer_data: PhantomData,
}
}
pub fn flush(&mut self) {
unsafe {
enet_host_flush(self.inner);
}
}
pub fn set_bandwith_limits(
&mut self,
incoming_bandwith: BandwidthLimit,
outgoing_bandwidth: BandwidthLimit,
) {
unsafe {
enet_host_bandwidth_limit(
self.inner,
incoming_bandwith.to_enet_u32(),
outgoing_bandwidth.to_enet_u32(),
);
}
}
pub fn set_channel_limit(&mut self, max_channel_count: ChannelLimit) {
unsafe {
enet_host_channel_limit(self.inner, max_channel_count.to_enet_val());
}
}
pub fn channel_limit(&self) -> ChannelLimit {
ChannelLimit::from_enet_val(unsafe { (*self.inner).channelLimit })
}
pub fn incoming_bandwidth(&self) -> u32 {
unsafe { (*self.inner).incomingBandwidth }
}
pub fn outgoing_bandwidth(&self) -> u32 {
unsafe { (*self.inner).outgoingBandwidth }
}
pub fn address(&self) -> Address {
Address::from_enet_address(&unsafe { (*self.inner).address })
}
pub fn peer_count(&self) -> enet_sys::size_t {
unsafe { (*self.inner).peerCount }
}
pub fn peers(&'_ mut self) -> impl Iterator<Item = Peer<'_, T>> {
let peer_count = unsafe { (*self.inner).peerCount.try_into().expect("too many peers") };
let raw_peers = unsafe { std::slice::from_raw_parts_mut((*self.inner).peers, peer_count) };
raw_peers.iter_mut().map(|rp| Peer::new(rp))
}
pub fn service(&'_ mut self, timeout_ms: u32) -> Result<Option<Event<'_, T>>, Error> {
let mut sys_event = MaybeUninit::uninit();
let res = unsafe { enet_host_service(self.inner, sys_event.as_mut_ptr(), timeout_ms) };
match res {
r if r > 0 => Ok(Event::from_sys_event(unsafe { &sys_event.assume_init() })),
0 => Ok(None),
r if r < 0 => Err(Error(r)),
_ => panic!("unreachable"),
}
}
pub fn check_events(&'_ mut self) -> Result<Option<Event<'_, T>>, Error> {
let mut sys_event = MaybeUninit::uninit();
let res = unsafe { enet_host_check_events(self.inner, sys_event.as_mut_ptr()) };
match res {
r if r > 0 => Ok(Event::from_sys_event(unsafe { &sys_event.assume_init() })),
0 => Ok(None),
r if r < 0 => Err(Error(r)),
_ => panic!("unreachable"),
}
}
pub fn connect(
&mut self,
address: &Address,
channel_count: enet_sys::size_t,
user_data: u32,
) -> Result<Peer<'_, T>, Error> {
let res: *mut ENetPeer = unsafe {
enet_host_connect(
self.inner,
&address.to_enet_address() as *const _,
channel_count,
user_data,
)
};
if res.is_null() {
return Err(Error(0));
}
Ok(Peer::new(res))
}
}
impl<T> Drop for Host<T> {
fn drop(&mut self) {
unsafe {
enet_host_destroy(self.inner);
}
}
}