Skip to main content

enet/
peer.rs

1use std;
2use enum_primitive_derive::Primitive;
3use num_traits;
4
5use ll;
6use crate::{host, Address, Packet};
7
8/// (65536)
9#[expect(clippy::unnecessary_cast)]  // on windows ll flags are i32
10pub const PACKET_LOSS_SCALE : u32 = ll::ENET_PEER_PACKET_LOSS_SCALE as u32;
11
12////////////////////////////////////////////////////////////////////////////////
13//  structs                                                                   //
14////////////////////////////////////////////////////////////////////////////////
15
16/// A type representing a connection to an ENet peer (client or server).
17///
18/// The first available peer (with `State::Disconnected`) is returned when
19/// *connecting* to a remote server host:
20///
21/// ```text
22/// let mut peer = host.connect (channels, data);
23/// ```
24///
25/// Note that the peer will be able to communicate on at least as many channels
26/// as the server supports, not necessarily the number requested.
27/// TODO: is this reflected after a connection event is received?
28///
29/// A peer is an endpoint of a bi-directional channel, so any connected peer can
30/// send messages:
31///
32/// ```text
33/// peer.send (channel, packet);
34/// ```
35///
36/// On the receiving end of the endpoint, each time an `Event` is received, a
37/// reference to the corresponding peer is included.
38///
39/// Internally a peer is a pointer into the host's allocated array of peers.
40#[derive(Clone, Debug, PartialEq)]
41pub struct Peer {
42  raw      : *mut ll::ENetPeer,
43  hostdrop : std::rc::Rc <host::HostDrop>
44}
45
46////////////////////////////////////////////////////////////////////////////////
47//  enums                                                                     //
48////////////////////////////////////////////////////////////////////////////////
49
50#[derive(Copy, Clone, Debug, Eq, PartialEq, Primitive)]
51pub enum State {
52  Disconnected         = ll::_ENetPeerState_ENET_PEER_STATE_DISCONNECTED       as isize,
53  Connecting           = ll::_ENetPeerState_ENET_PEER_STATE_CONNECTING         as isize,
54  AcknowledgingConnect = ll::_ENetPeerState_ENET_PEER_STATE_ACKNOWLEDGING_CONNECT
55    as isize,
56  ConnectionPending    = ll::_ENetPeerState_ENET_PEER_STATE_CONNECTION_PENDING as isize,
57  ConnectionSucceeded  = ll::_ENetPeerState_ENET_PEER_STATE_CONNECTION_SUCCEEDED
58    as isize,
59  Connected            = ll::_ENetPeerState_ENET_PEER_STATE_CONNECTED          as isize,
60  DisconnectLater      = ll::_ENetPeerState_ENET_PEER_STATE_DISCONNECT_LATER   as isize,
61  Disconnecting        = ll::_ENetPeerState_ENET_PEER_STATE_DISCONNECTING      as isize,
62  AcknowledgingDisconnect = ll::_ENetPeerState_ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT
63    as isize,
64  Zombie               = ll::_ENetPeerState_ENET_PEER_STATE_ZOMBIE             as isize
65}
66
67#[derive(Debug)]
68pub enum ConnectError {
69  NoPeersAvailable,
70  /// failure due to internal malloc failure of channel allocation
71  Failure
72}
73
74#[derive(Debug)]
75pub enum SendError {
76  PeerNotConnected (State),
77  PeerNoChannelID (u8),
78  PacketCreateZeroLength,
79  /// packet creation failed due to internal malloc call failing
80  PacketCreateMallocFailure,
81  /// packet size exceeds raw value of `peer.host->maximumPacketSize`
82  PacketExceedsMaximumSize (usize),
83  /// failure due to either malloc failure or internal fragment count
84  /// exceeded `ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT`
85  Failure
86}
87
88////////////////////////////////////////////////////////////////////////////////
89//  impls                                                                     //
90////////////////////////////////////////////////////////////////////////////////
91
92impl Peer {
93  pub(crate) const unsafe fn from_raw (
94    peer     : *mut ll::ENetPeer,
95    hostdrop : std::rc::Rc <host::HostDrop>
96  ) -> Self {
97    Peer {
98      raw: peer,
99      hostdrop
100    }
101  }
102
103  /// # Safety
104  ///
105  /// Unsafe: returns raw pointer.
106  #[inline]
107  pub const unsafe fn raw (&self) -> *mut ll::ENetPeer {
108    self.raw
109  }
110
111  /// The `incomingPeerID` field represents the index into the local array of peers.
112  ///
113  /// Note this is *not* the same as the `connectID` field.
114  #[inline]
115  pub fn incoming_peer_id (&self) -> u16 {
116    unsafe { (*self.raw).incomingPeerID }
117  }
118
119  #[inline]
120  pub fn state (&self) -> State {
121    use num_traits::FromPrimitive;
122    #[expect(clippy::unnecessary_cast)] // on windows ll flags are i32
123    unsafe { State::from_u32 ((*self.raw).state as u32).unwrap() }
124  }
125
126  #[inline]
127  pub fn address (&self) -> Address {
128    unsafe { Address::from_ll ((*self.raw).address) }
129  }
130
131  #[inline]
132  pub fn packet_loss_epoch (&self) -> u32 {
133    unsafe { (*self.raw).packetLossEpoch }
134  }
135
136  /// Packets sent during the current "packet loss epoch"
137  #[inline]
138  pub fn packets_sent (&self) -> u32 {
139    unsafe { (*self.raw).packetsSent }
140  }
141
142  /// Packets lost during the current "packet loss epoch"
143  #[inline]
144  pub fn packets_lost (&self) -> u32 {
145    unsafe { (*self.raw).packetsLost }
146  }
147
148  /// Mean packet loss of reliable packets as a ratio with respect to
149  /// `PACKET_LOSS_SCALE`
150  #[inline]
151  pub fn packet_loss (&self) -> u32 {
152    unsafe { (*self.raw).packetLoss }
153  }
154
155  /// Milliseconds
156  #[inline]
157  pub fn round_trip_time (&self) -> u32 {
158    unsafe { (*self.raw).roundTripTime }
159  }
160
161  /// Milliseconds
162  #[inline]
163  pub fn round_trip_time_variance (&self) -> u32 {
164    unsafe { (*self.raw).roundTripTimeVariance }
165  }
166
167  // TODO: expose the following round trip time values ?
168  /*
169  /// Milliseconds
170  #[inline]
171  pub fn lowest_round_trip_time (&self) -> u32 {
172    unsafe { (*self.raw).lowestRoundTripTime }
173  }
174
175  /// Milliseconds
176  #[inline]
177  pub fn highest_round_trip_time_variance (&self) -> u32 {
178    unsafe { (*self.raw).highestRoundTripTimeVariance }
179  }
180
181  /// Milliseconds
182  #[inline]
183  pub fn last_round_trip_time (&self) -> u32 {
184    unsafe { (*self.raw).lastRoundTripTime }
185  }
186
187  /// Milliseconds
188  #[inline]
189  pub fn last_round_trip_time_variance (&self) -> u32 {
190    unsafe {
191      (*self.raw).lastRoundTripTimeVariance
192    }
193  }
194  */
195
196  #[inline]
197  pub fn ping (&mut self) {
198    unsafe {
199      ll::enet_peer_ping (self.raw())
200    }
201  }
202
203  #[inline]
204  pub fn get_ping_interval (&mut self) -> u32 {
205    unsafe {
206      (*self.raw).pingInterval
207    }
208  }
209
210  /// Set the interval at which pings will be sent to a peer
211  #[inline]
212  pub fn ping_interval (&mut self, ping_interval : u32) {
213    unsafe {
214      ll::enet_peer_ping_interval (self.raw(), ping_interval)
215    }
216  }
217
218  /// Set the timeout parameters for a peer
219  #[inline]
220  pub fn timeout (&mut self,
221    timeout_limit : u32, timeout_minimum : u32, timeout_maximum : u32
222  ) {
223    unsafe {
224      ll::enet_peer_timeout (self.raw(),
225        timeout_limit, timeout_minimum, timeout_maximum)
226    }
227  }
228
229  /// (timeoutLimit, timeoutMinimum, timeoutMaximum)
230  #[inline]
231  pub fn get_timeout (&mut self) -> (u32, u32, u32) {
232    unsafe {
233      ( (*self.raw).timeoutLimit,
234        (*self.raw).timeoutMinimum,
235        (*self.raw).timeoutMaximum )
236    }
237  }
238
239  pub fn send (&mut self, channel_id : u8, packet : Packet) -> Result <(), SendError> {
240    use num_traits::FromPrimitive;
241    unsafe {
242      if (*self.raw).state != ll::_ENetPeerState_ENET_PEER_STATE_CONNECTED {
243        #[expect(clippy::unnecessary_cast)]  // on windows ll flags are i32
244        return Err (SendError::PeerNotConnected(
245          State::from_u32 ((*self.raw).state as u32).unwrap()
246        ))
247      }
248      if (*self.raw).channelCount as u8 <= channel_id {
249        return Err (SendError::PeerNoChannelID (channel_id))
250      }
251      let raw = match packet {
252        Packet::Allocate { bytes, flags } => {
253          if (*self.hostdrop.raw()).maximumPacketSize < bytes.len() {
254            return Err (SendError::PacketExceedsMaximumSize (bytes.len()))
255          }
256          if bytes.is_empty() {
257            return Err (SendError::PacketCreateZeroLength)
258          }
259          ll::enet_packet_create (
260            bytes.as_ptr() as *const std::os::raw::c_void, bytes.len(), flags.bits())
261        }
262        Packet::NoAllocate { bytes, flags } => {
263          if (*(*self.raw).host).maximumPacketSize < bytes.len() {
264            return Err (SendError::PacketExceedsMaximumSize(bytes.len()))
265          }
266          if bytes.is_empty() {
267            return Err (SendError::PacketCreateZeroLength)
268          }
269          #[expect(clippy::unnecessary_cast)]  // on windows ll flags are i32
270          ll::enet_packet_create (
271            bytes.as_ptr() as *const std::os::raw::c_void,
272            bytes.len(),
273            flags.bits() | ll::_ENetPacketFlag_ENET_PACKET_FLAG_NO_ALLOCATE as u32)
274        }
275      };
276      if raw.is_null() {
277        return Err (SendError::PacketCreateMallocFailure)
278      }
279      if ll::enet_peer_send (self.raw(), channel_id, raw) < 0 {
280        return Err (SendError::Failure)
281      }
282      Ok(())
283    }
284  } // end send
285
286  // TODO: expose data parameter in the following ?
287
288  /// Request a disconnection.
289  ///
290  /// Note this may be sent before queued outgoing packets; use
291  /// `disconnect_later` to ensure they are sent before disconnecting.
292  #[inline]
293  pub fn disconnect (&self) {
294    unsafe {
295      ll::enet_peer_disconnect (self.raw(), 0)
296    }
297  }
298
299  /// Force immediate disconnection
300  #[inline]
301  pub fn disconnect_now (&self) {
302    unsafe {
303      ll::enet_peer_disconnect_now (self.raw(), 0)
304    }
305  }
306
307  /// Request disconnection after all queued outgoing packets are sent
308  #[inline]
309  pub fn disconnect_later (&self) {
310    unsafe {
311      ll::enet_peer_disconnect_later (self.raw(), 0)
312    }
313  }
314
315  /// Forcibly disconnect without notifying peer.
316  ///
317  /// For the remote peer, eventually the connection will time out.
318  #[inline]
319  pub fn reset (&self) {
320    unsafe {
321      ll::enet_peer_reset (self.raw())
322    }
323  }
324
325} // end impl Peer