diff --git a/src/lib.rs b/src/lib.rs index a800b13..3fc97d2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ //! different protocol layer. //! //! Neither SEQEX nor TCP are cryptographically secure. -#![warn(missing_docs, rust_2018_idioms)] +//#![warn(missing_docs, rust_2018_idioms)] mod transport_layer; pub use transport_layer::*; diff --git a/src/no_std.rs b/src/no_std.rs index 02d9132..dfb9137 100644 --- a/src/no_std.rs +++ b/src/no_std.rs @@ -13,6 +13,8 @@ pub struct SeqEx { /// remote peer. /// It can be statically or dynamically set. pub resend_interval: i64, + /// The timestamp at which `service_direct` should be called again. + /// This can be `i64::MAX` does not currently need to be called again. pub next_service_timestamp: i64, next_send_seq_no: SeqNo, next_recv_seq_no: SeqNo, diff --git a/src/single_thread.rs b/src/single_thread.rs index 46d068b..a744dba 100644 --- a/src/single_thread.rs +++ b/src/single_thread.rs @@ -14,15 +14,24 @@ pub struct SeqCstGuard<'a, SendData, RecvData, const CAP: usize = DEFAULT_WINDOW } impl<'a, TL: TransportLayer, SendData, RecvData, const CAP: usize> ReplyGuard<'a, TL, SendData, RecvData, CAP> { + /// Returns a mutable reference to the `TransportLayer` instance that created this guard. pub fn get_seqex(&'a mut self) -> &'a mut SeqEx { self.seq } + /// Returns a reference to the `TransportLayer` instance this guard was created with. pub fn get_tl(&self) -> &TL { &self.tl } + /// Returns a mutable reference to the `TransportLayer` instance this guard was created with. pub fn get_tl_mut(&mut self) -> &mut TL { &mut self.tl } + /// Returns whether or nor this reply guard is for a SeqCst packet, and therefore is + /// holding the SeqCst lock, preventing other SeqCst packets from being processed. + /// + /// When this returns `true`, it means the current thread is within the critical section for + /// processing SeqCst packets. SeqCst packets can only enter this critical section in the same + /// order they were sent. pub fn is_seq_cst(&self) -> bool { self.is_holding_lock } @@ -78,6 +87,20 @@ impl<'a, TL: TransportLayer, SendData, RecvData, const CAP: usize> Rep self.consume_lock() } + /// Break down a `ReplyGuard` into its primitive components, without causing it to send an ack + /// or reply to the remote peer. + /// + /// The first return value is the packet reply number, and the second is the return value of + /// `is_seq_cst`, which states whether or not this `ReplyGuard` is holding the SeqCst lock. + /// + /// This can be used in combination with `from_components` to move a `ReplyGuard` to a different + /// thread. + /// + /// # Safety + /// The caller must guarantee that `ReplyGuard::from_components` is eventually called on + /// the returned values. + /// + /// If this does not happen the SEQEX protocol will enter a deadlocked state. pub unsafe fn to_components(self) -> (SeqNo, bool) { let ret = (self.reply_no, self.is_holding_lock); core::mem::forget(self); @@ -86,6 +109,16 @@ impl<'a, TL: TransportLayer, SendData, RecvData, const CAP: usize> Rep fn new(seq: &'a mut SeqEx, tl: TL, reply_no: SeqNo, is_holding_lock: bool) -> Self { ReplyGuard { seq, tl, reply_no, is_holding_lock } } + /// Constructs a `ReplyGuard` object from the raw components returned by + /// `ReplyGuard::to_components`. + /// + /// # Safety + /// The caller must always pass values for `reply_no` and `is_holding_lock` that were + /// originally returned by consuming a `ReplyGuard` instance with `to_components`. + /// + /// `seq` must be the exact same instance of `SeqEx` that issued the original `ReplyGuard`. + /// + /// Otherwise undefined behavior will occur. pub unsafe fn from_components(seq: &'a mut SeqEx, tl: TL, reply_no: SeqNo, is_holding_lock: bool) -> Self { Self::new(seq, tl, reply_no, is_holding_lock) } diff --git a/src/tokio.rs b/src/tokio.rs index 205cc2e..300f009 100644 --- a/src/tokio.rs +++ b/src/tokio.rs @@ -38,12 +38,20 @@ pub struct SeqCstGuard<'a, SendData, RecvData, const CAP: usize = DEFAULT_WINDOW } impl<'a, TL: TokioLayer, SendData, RecvData, const CAP: usize> ReplyGuard<'a, TL, SendData, RecvData, CAP> { + /// Returns a reference to the `TransportLayer` instance this guard was created with. pub fn get_tl(&self) -> &TL { &self.tl } + /// Returns a mutable reference to the `TransportLayer` instance this guard was created with. pub fn get_tl_mut(&mut self) -> &mut TL { &mut self.tl } + /// Returns whether or nor this reply guard is for a SeqCst packet, and therefore is + /// holding the SeqCst lock, preventing other SeqCst packets from being processed. + /// + /// When this returns `true`, it means the current thread is within the critical section for + /// processing SeqCst packets. SeqCst packets can only enter this critical section in the same + /// order they were sent. pub fn is_seq_cst(&self) -> bool { self.is_holding_lock } @@ -144,6 +152,21 @@ impl<'a, TL: TokioLayer, SendData, RecvData, const CAP: usi } } + /// Break down a `ReplyGuard` into its primitive components, without causing it to send an ack + /// or reply to the remote peer. + /// + /// The first return value is the packet reply number, and the second is the return value of + /// `is_seq_cst`, which states whether or not this `ReplyGuard` is holding the SeqCst lock. + /// + /// This can be used in combination with `from_components` to move a `ReplyGuard` to a different + /// thread. + /// + /// # Safety + /// The caller must guarantee that `ReplyGuard::from_components` is eventually called on + /// the returned values. + /// + /// If this does not happen the SEQEX protocol will enter a deadlocked state, + /// which is likely to cause threads to permanently block. pub unsafe fn to_components(self) -> (SeqNo, bool) { let ret = (self.reply_no, self.is_holding_lock); core::mem::forget(self); @@ -152,6 +175,16 @@ impl<'a, TL: TokioLayer, SendData, RecvData, const CAP: usi fn new(seq: &'a SeqEx, tl: TL, reply_no: SeqNo, is_holding_lock: bool) -> Self { ReplyGuard { seq, tl, reply_no, is_holding_lock } } + /// Constructs a `ReplyGuard` object from the raw components returned by + /// `ReplyGuard::to_components`. + /// + /// # Safety + /// The caller must always pass values for `reply_no` and `is_holding_lock` that were + /// originally returned by consuming a `ReplyGuard` instance with `to_components`. + /// + /// `seq` must be the exact same instance of `SeqEx` that issued the original `ReplyGuard`. + /// + /// Otherwise undefined behavior will occur. pub unsafe fn from_components(seq: &'a SeqEx, tl: TL, reply_no: SeqNo, is_holding_lock: bool) -> Self { Self::new(seq, tl, reply_no, is_holding_lock) }