use std::{marker::PhantomData, time::Duration};
use enet_sys::{
enet_peer_disconnect, enet_peer_disconnect_later, enet_peer_disconnect_now, enet_peer_receive,
enet_peer_reset, enet_peer_send, ENetPeer, _ENetPeerState,
_ENetPeerState_ENET_PEER_STATE_ACKNOWLEDGING_CONNECT,
_ENetPeerState_ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT,
_ENetPeerState_ENET_PEER_STATE_CONNECTED, _ENetPeerState_ENET_PEER_STATE_CONNECTING,
_ENetPeerState_ENET_PEER_STATE_CONNECTION_PENDING,
_ENetPeerState_ENET_PEER_STATE_CONNECTION_SUCCEEDED,
_ENetPeerState_ENET_PEER_STATE_DISCONNECTED, _ENetPeerState_ENET_PEER_STATE_DISCONNECTING,
_ENetPeerState_ENET_PEER_STATE_DISCONNECT_LATER, _ENetPeerState_ENET_PEER_STATE_ZOMBIE,
};
use crate::{Address, Error, Packet};
#[derive(Clone, Debug)]
pub struct Peer<'a, T: 'a> {
inner: *mut ENetPeer,
_data: PhantomData<&'a mut T>,
}
#[derive(Debug)]
pub struct PeerPacket<'b, 'a, T: 'a> {
pub packet: Packet,
pub channel_id: u8,
_priv_guard: PhantomData<&'b Peer<'a, T>>,
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum PeerState {
Disconnected,
Connected,
Connecting,
AcknowledgingConnect,
ConnectionPending,
ConnectionSucceeded,
DisconnectLater,
Disconnecting,
AcknowledgingDisconnect,
Zombie,
}
impl PeerState {
fn from_sys_state(enet_sys_state: _ENetPeerState) -> PeerState {
#[allow(non_upper_case_globals)]
match enet_sys_state {
_ENetPeerState_ENET_PEER_STATE_DISCONNECTED => PeerState::Disconnected,
_ENetPeerState_ENET_PEER_STATE_CONNECTING => PeerState::Connecting,
_ENetPeerState_ENET_PEER_STATE_ACKNOWLEDGING_CONNECT => PeerState::AcknowledgingConnect,
_ENetPeerState_ENET_PEER_STATE_CONNECTION_PENDING => PeerState::ConnectionPending,
_ENetPeerState_ENET_PEER_STATE_CONNECTION_SUCCEEDED => PeerState::ConnectionSucceeded,
_ENetPeerState_ENET_PEER_STATE_CONNECTED => PeerState::Connected,
_ENetPeerState_ENET_PEER_STATE_DISCONNECT_LATER => PeerState::DisconnectLater,
_ENetPeerState_ENET_PEER_STATE_DISCONNECTING => PeerState::Disconnecting,
_ENetPeerState_ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT => {
PeerState::AcknowledgingDisconnect
}
_ENetPeerState_ENET_PEER_STATE_ZOMBIE => PeerState::Zombie,
val => panic!("unexpected peer state: {}", val),
}
}
}
impl<'a, T> Peer<'a, T> {
pub(crate) fn new(inner: *mut ENetPeer) -> Peer<'a, T> {
Peer {
inner,
_data: PhantomData,
}
}
pub fn address(&self) -> Address {
Address::from_enet_address(&unsafe { (*self.inner).address })
}
pub fn channel_count(&self) -> enet_sys::size_t {
unsafe { (*self.inner).channelCount }
}
pub fn data(&self) -> Option<&T> {
unsafe {
let raw_data = (*self.inner).data as *const T;
if raw_data.is_null() {
None
} else {
Some(&(*raw_data))
}
}
}
pub fn data_mut(&mut self) -> Option<&mut T> {
unsafe {
let raw_data = (*self.inner).data as *mut T;
if raw_data.is_null() {
None
} else {
Some(&mut (*raw_data))
}
}
}
pub fn set_data(&mut self, data: Option<T>) {
unsafe {
let raw_data = (*self.inner).data as *mut T;
if !raw_data.is_null() {
let _: Box<T> = Box::from_raw(raw_data);
}
let new_data = match data {
Some(data) => Box::into_raw(Box::new(data)) as *mut _,
None => std::ptr::null_mut(),
};
(*self.inner).data = new_data;
}
}
pub fn incoming_bandwidth(&self) -> u32 {
unsafe { (*self.inner).incomingBandwidth }
}
pub fn outgoing_bandwidth(&self) -> u32 {
unsafe { (*self.inner).outgoingBandwidth }
}
pub fn mean_rtt(&self) -> Duration {
Duration::from_millis(unsafe { (*self.inner).roundTripTime } as u64)
}
pub fn reset(self) {
unsafe {
enet_peer_reset(self.inner);
}
}
pub fn state(&self) -> PeerState {
PeerState::from_sys_state(unsafe { (*self.inner).state })
}
pub fn send_packet(&mut self, packet: Packet, channel_id: u8) -> Result<(), Error> {
let res = unsafe { enet_peer_send(self.inner, channel_id, packet.into_inner()) };
match res {
r if r > 0 => panic!("unexpected res: {}", r),
0 => Ok(()),
r if r < 0 => Err(Error(r)),
_ => panic!("unreachable"),
}
}
pub fn disconnect(&mut self, user_data: u32) {
unsafe {
enet_peer_disconnect(self.inner, user_data);
}
}
pub fn disconnect_now(self, user_data: u32) {
unsafe {
enet_peer_disconnect_now(self.inner, user_data);
}
}
pub fn disconnect_later(&mut self, user_data: u32) {
unsafe {
enet_peer_disconnect_later(self.inner, user_data);
}
}
pub fn receive<'b>(&'b mut self) -> Option<PeerPacket<'b, 'a, T>> {
let mut channel_id = 0u8;
let res = unsafe { enet_peer_receive(self.inner, &mut channel_id as *mut _) };
if res.is_null() {
return None;
}
Some(PeerPacket {
packet: Packet::from_sys_packet(res),
channel_id,
_priv_guard: PhantomData,
})
}
}