use std;
use ll;
use crate::{
peer, Address, EnetDrop, Event, Packet, Peer, MAX_PEERS, MAX_CHANNEL_COUNT
};
#[derive(Clone, Debug)]
pub struct Host {
hostdrop : std::rc::Rc <HostDrop>
}
#[derive(Debug, PartialEq)]
pub(crate) struct HostDrop {
raw : *mut ll::ENetHost,
enetdrop : std::sync::Arc <EnetDrop>
}
#[derive(Debug)]
pub enum Error {
ServiceError,
DispatchError
}
#[derive(Clone, Debug)]
pub enum CreateError {
TooManyPeers (u32),
TooManyChannels (u32),
ReturnedNull
}
impl Host {
pub(crate) fn new (
address : Option <Address>,
peer_count : u32,
channel_limit : Option <u32>,
incoming_bandwidth : Option <u32>,
outgoing_bandwidth : Option <u32>,
enetdrop : std::sync::Arc <EnetDrop>
) -> Result <Self, CreateError> {
if MAX_PEERS < peer_count {
return Err (CreateError::TooManyPeers (peer_count))
}
let channel_limit = channel_limit.unwrap_or (0);
if MAX_CHANNEL_COUNT < channel_limit {
return Err (CreateError::TooManyChannels (channel_limit))
}
let host;
match address {
Some (a) => unsafe {
host = ll::enet_host_create (
a.raw(),
peer_count as usize,
channel_limit as usize,
incoming_bandwidth.unwrap_or (0),
outgoing_bandwidth.unwrap_or (0)
);
if host.is_null() {
return Err (CreateError::ReturnedNull)
}
},
None => unsafe {
host = ll::enet_host_create (
std::ptr::null(),
peer_count as usize,
channel_limit as usize,
incoming_bandwidth.unwrap_or (0),
outgoing_bandwidth.unwrap_or (0)
);
if host.is_null() {
return Err (CreateError::ReturnedNull)
}
}
} Ok (Host {
hostdrop: std::rc::Rc::new (HostDrop {
raw: host, enetdrop
})
})
}
#[inline]
pub unsafe fn raw (&self) -> *mut ll::ENetHost {
unsafe { self.hostdrop.raw() }
}
#[inline]
pub fn peer_count (&self) -> usize {
unsafe { (*self.raw()).peerCount }
}
#[inline]
pub fn connected_peers (&self) -> usize {
unsafe { (*self.raw()).connectedPeers }
}
#[inline]
pub fn channel_limit (&self) -> usize {
unsafe { (*self.raw()).channelLimit }
}
#[inline]
pub fn total_sent_packets (&self) -> u32 {
unsafe { (*self.raw()).totalSentPackets }
}
pub fn reset_total_sent_packets (&mut self) {
unsafe {
(*self.raw()).totalSentPackets = 0;
}
}
#[inline]
pub fn total_sent_data (&self) -> u32 {
unsafe { (*self.raw()).totalSentPackets }
}
pub fn reset_total_sent_data (&mut self) {
unsafe {
(*self.raw()).totalSentData = 0;
}
}
#[inline]
pub fn total_received_packets (&self) -> u32 {
unsafe { (*self.raw()).totalReceivedPackets }
}
pub fn reset_total_received_packets (&mut self) {
unsafe {
(*self.raw()).totalReceivedPackets = 0;
}
}
#[inline]
pub fn total_received_data (&self) -> u32 {
unsafe { (*self.raw()).totalReceivedPackets }
}
pub fn reset_total_received_data (&mut self) {
unsafe {
(*self.raw()).totalReceivedData = 0;
}
}
pub fn connect (&mut self, address : &Address, channel_count : u8, data : u32)
-> Result <Peer, peer::ConnectError>
{
unsafe {
if self.peer_count() <= self.connected_peers() {
return Err (peer::ConnectError::NoPeersAvailable)
}
let peer = ll::enet_host_connect (
self.raw(),
address.raw(),
channel_count as usize,
data
);
if peer.is_null() {
return Err (peer::ConnectError::Failure)
}
Ok (Peer::from_raw(peer, self.hostdrop.clone()))
}
}
pub fn service (&mut self, timeout : u32) -> Result <Option <Event>, Error> {
let event = unsafe {
let mut mem = std::mem::MaybeUninit::<ll::ENetEvent>::uninit();
let event = mem.as_mut_ptr();
if ll::enet_host_service (self.hostdrop.raw, event, timeout) < 0 {
return Err (Error::ServiceError)
}
*event
};
Ok (Event::from_ll (event, self.hostdrop.clone()))
}
#[inline]
pub fn check_events (&mut self) -> Result <Option <Event>, Error> {
let event = unsafe {
let mut mem = std::mem::MaybeUninit::<ll::ENetEvent>::uninit();
let event = mem.as_mut_ptr();
if ll::enet_host_check_events (self.hostdrop.raw, event) < 0 {
return Err (Error::DispatchError)
}
*event
};
Ok (Event::from_ll (event, self.hostdrop.clone()))
}
#[inline]
pub fn flush (&mut self) {
unsafe { ll::enet_host_flush (self.hostdrop.raw) }
}
pub fn broadcast (&mut self, channel_id : u8, packet : Packet) {
unsafe {
let raw = match packet {
Packet::Allocate { bytes, flags } => {
ll::enet_packet_create (
bytes.as_ptr() as *const std::os::raw::c_void,
bytes.len(),
flags.bits())
}
#[expect(clippy::unnecessary_cast)] Packet::NoAllocate { bytes, flags } => {
ll::enet_packet_create (
bytes.as_ptr() as *const std::os::raw::c_void,
bytes.len(),
flags.bits() | ll::_ENetPacketFlag_ENET_PACKET_FLAG_NO_ALLOCATE as u32)
}
};
ll::enet_host_broadcast (self.raw(), channel_id, raw)
}
}
}
impl HostDrop {
#[inline]
pub(crate) const unsafe fn raw (&self) -> *mut ll::ENetHost {
self.raw
}
}
impl Drop for HostDrop {
#[inline]
fn drop (&mut self) {
unsafe { ll::enet_host_destroy (self.raw) }
}
}