enet/
lib.rs

1//! Rust interface for the [ENet reliable UDP library](http://enet.bespin.org/)
2
3extern crate enet_sys as ll;
4
5use std::sync::atomic;
6
7pub mod address;
8pub mod event;
9pub mod host;
10pub mod packet;
11pub mod peer;
12pub mod version;
13
14pub use self::address::Address;
15pub use self::event::Event;
16pub use self::host::Host;
17pub use self::packet::Packet;
18pub use self::peer::Peer;
19pub use self::version::Version;
20
21/// (4096)
22#[expect(clippy::unnecessary_cast)]  // on windows ll flags are i32
23pub const MAX_PEERS         : u32 = ll::ENET_PROTOCOL_MAXIMUM_PEER_ID as u32;
24/// (255)
25#[expect(clippy::unnecessary_cast)]  // on windows ll flags are i32
26pub const MAX_CHANNEL_COUNT : u32 = ll::ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT as u32;
27
28static ENET_CONTEXT_ALIVE : atomic::AtomicBool = atomic::AtomicBool::new (false);
29
30/// The initialized ENet context.
31///
32/// This can be sent accross threads and used to create thread-local `Host`s.
33///
34/// The context will be kept alive as long as any `Host`s still exist.
35#[derive(Clone)]
36pub struct Enet {
37  enetdrop : std::sync::Arc <EnetDrop>
38}
39
40#[derive(Clone, Debug, PartialEq)]
41struct EnetDrop;
42
43/// ENet context errors
44#[derive(Clone, Debug)]
45pub enum Error {
46  Initialize   (String),
47  ServerCreate (host::CreateError),
48  ClientCreate (host::CreateError)
49}
50
51/// Initialize the ENet context.
52///
53/// An error is returned if ENet is already initialized.
54#[inline]
55pub fn initialize() -> Result <Enet, Error> {
56  Enet::new()
57}
58
59/// Safe to call regardless of ENet initialization
60pub fn linked_version() -> Version {
61  unsafe {
62    Version::from_ll (ll::enet_linked_version())
63  }
64}
65
66impl Enet {
67  /// Create a host that is intended to only request new connections and not to
68  /// listen for incoming connections.
69  ///
70  /// The peer count given when creating a host defines the number of
71  /// "connections" to other peers that host may have.
72  ///
73  /// Bandwidth parameters determine the "window size" of a connection which
74  /// limits the number of reliable packets that may be in transit at any given
75  /// time.
76  pub fn client_host_create (&self,
77    peer_count         : u32,
78    incoming_bandwidth : Option <u32>,
79    outgoing_bandwidth : Option <u32>
80  ) -> Result <Host, Error> {
81    Host::new (
82      None,
83      peer_count,
84      None,
85      incoming_bandwidth,
86      outgoing_bandwidth,
87      self.enetdrop.clone()
88    ).map_err (Error::ClientCreate)
89  }
90
91  /// Create a host that is intended to listen for incoming connections (and may
92  /// also request new connections with remote hosts).
93  ///
94  /// The peer count given when creating a host defines the number of
95  /// "connections" to other peers that host may have.
96  ///
97  /// Bandwidth parameters determine the "window size" of a connection which
98  /// limits the number of reliable packets that may be in transit at any given
99  /// time.
100  pub fn server_host_create (&self,
101    address            : Address,
102    peer_count         : u32,
103    channel_limit      : Option <u32>,
104    incoming_bandwidth : Option <u32>,
105    outgoing_bandwidth : Option <u32>
106  ) -> Result <Host, Error> {
107    Host::new (
108      Some (address),
109      peer_count,
110      channel_limit,
111      incoming_bandwidth,
112      outgoing_bandwidth,
113      self.enetdrop.clone()
114    ).map_err (Error::ServerCreate)
115  }
116
117  fn new() -> Result <Self, Error> {
118    unsafe {
119      let was_alive =
120        ENET_CONTEXT_ALIVE.swap (true, atomic::Ordering::Relaxed);
121      if was_alive {
122        return Err (Error::Initialize (
123          "`Enet` cannot be initialized more than once".to_owned()))
124      }
125      if ll::enet_initialize() < 0 {
126        return Err (Error::Initialize(
127          "`enet_initialize` returned an error".to_owned()))
128      }
129      Ok (Enet { enetdrop: std::sync::Arc::new (EnetDrop) })
130    }
131  }
132}
133
134impl Drop for EnetDrop {
135  #[inline]
136  fn drop (&mut self) {
137    let was_alive = ENET_CONTEXT_ALIVE.swap (false, atomic::Ordering::Relaxed);
138    debug_assert!(was_alive);
139    if was_alive {
140      unsafe { ll::enet_deinitialize() }
141    }
142  }
143}
144
145////////////////////////////////////////////////////////////////////////////////
146//  tests                                                                     //
147////////////////////////////////////////////////////////////////////////////////
148
149/*
150#[cfg (test)]
151mod tests {
152  #[test]
153  fn it_works() {}
154}
155*/