diff --git a/channels/src/protocol.rs b/channels/src/protocol.rs index d11b716..319151d 100644 --- a/channels/src/protocol.rs +++ b/channels/src/protocol.rs @@ -1,5 +1,3 @@ -use core::num::NonZeroUsize; - use channels_packet::{ Flags, Header, IdGenerator, PacketLength, PayloadLength, }; @@ -8,18 +6,10 @@ use crate::error::VerifyError; use crate::io::{ AsyncRead, AsyncWrite, Buf, Contiguous, Cursor, Read, Write, }; +use crate::receiver::Config as RecvConfig; +use crate::sender::Config as SendConfig; use crate::util::StatIO; -#[derive(Clone)] -pub struct SendConfig { - pub flush_on_send: bool, -} - -#[derive(Clone)] -pub struct RecvConfig { - pub size_estimate: Option, -} - #[derive(Clone)] pub struct Pcb { id_gen: IdGenerator, diff --git a/channels/src/receiver.rs b/channels/src/receiver.rs index 8729cbd..3033023 100644 --- a/channels/src/receiver.rs +++ b/channels/src/receiver.rs @@ -6,7 +6,7 @@ use core::num::NonZeroUsize; use crate::error::RecvError; use crate::io::{AsyncRead, IntoReader, Read, Reader}; -use crate::protocol::{Pcb, RecvConfig}; +use crate::protocol::Pcb; use crate::serdes::Deserializer; use crate::util::StatIO; @@ -19,7 +19,7 @@ pub struct Receiver { reader: StatIO, deserializer: D, pcb: Pcb, - config: RecvConfig, + config: Config, } impl Receiver { @@ -327,7 +327,7 @@ pub struct Builder { _marker: PhantomData, reader: R, deserializer: D, - config: RecvConfig, + config: Option, } impl Builder { @@ -350,7 +350,7 @@ impl Builder { _marker: PhantomData, reader: (), deserializer: (), - config: RecvConfig { size_estimate: None }, + config: None, } } } @@ -419,20 +419,24 @@ impl Builder { } impl Builder { - /// Set the expected size for each received type. + /// Set the [`Config`] for this receiver. /// - /// This options exists purely to avoid reallocations when receiving types - /// that span multiple packets. + /// # Example + /// + /// ```no_run + /// use core::num::NonZeroUsize; /// - /// # Panics + /// use channels::receiver::{Config, Receiver}; /// - /// If `size_estimate` is 0. + /// let config = Config::default() + /// .size_estimate(NonZeroUsize::new(42).unwrap()); + /// + /// let rx = Receiver::::builder() + /// .config(config); + /// ``` #[must_use] - pub fn size_estimate(mut self, size_estimate: usize) -> Self { - self.config.size_estimate = Some( - NonZeroUsize::new(size_estimate) - .expect("size_estimate cannot be zero"), - ); + pub fn config(mut self, config: Config) -> Self { + self.config = Some(config); self } @@ -452,20 +456,53 @@ impl Builder { reader: StatIO::new(self.reader), deserializer: self.deserializer, pcb: Pcb::new(), - config: self.config, + config: self.config.unwrap_or_default(), } } } -impl fmt::Debug for RecvConfig { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut debug = f.debug_struct("Config"); +/// Configuration for [`Receiver`]. +/// +/// [`Receiver`]: crate::Receiver +#[derive(Clone, Default)] +pub struct Config { + pub(crate) size_estimate: Option, +} - if let Some(x) = self.size_estimate { - debug.field("size_estimate", &x.get()); - } +impl Config { + /// Size estimate for incoming data. + /// + /// Inform the receiving code to preallocate a buffer of this size when + /// receiving. Setting this field correctly can help avoid reallocations + /// when receiving data that is split up into multiple packets. For most + /// cases, when data fits inside a single packet, this field has _no_ effect + /// and can simply be left as the default. + /// + /// When setting this field, if you don't know the exact size of your data, + /// it is best to overestimate it. Setting a value even one byte less than + /// what the actual size of the data is will still lead to a reallocation + /// and more copying. However if the data fits inside one packet, as is with + /// most cases, setting this field incorrectly can still have a minor impact + /// on performance. + /// + /// In general, this field should probably be left alone unless you can + /// prove that the processing time for received packets far exceeds the + /// transmission time of the medium used. + /// + /// + /// **Default:** `None` + #[must_use] + pub fn size_estimate(mut self, estimate: NonZeroUsize) -> Self { + self.size_estimate = Some(estimate); + self + } +} - debug.finish() +impl fmt::Debug for Config { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Config") + .field("size_estimate", &self.size_estimate) + .finish() } } @@ -485,7 +522,7 @@ where impl fmt::Debug for Receiver where - StatIO: fmt::Debug, + R: fmt::Debug, D: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/channels/src/sender.rs b/channels/src/sender.rs index e7ed574..110da06 100644 --- a/channels/src/sender.rs +++ b/channels/src/sender.rs @@ -6,7 +6,7 @@ use core::marker::PhantomData; use crate::error::SendError; use crate::io::{AsyncWrite, IntoWriter, Write, Writer}; -use crate::protocol::{Pcb, SendConfig}; +use crate::protocol::Pcb; use crate::serdes::Serializer; use crate::util::StatIO; @@ -19,7 +19,7 @@ pub struct Sender { writer: StatIO, serializer: S, pcb: Pcb, - config: SendConfig, + config: Config, } impl Sender { @@ -273,7 +273,7 @@ pub struct Builder { _marker: PhantomData, writer: W, serializer: S, - config: SendConfig, + config: Option, } impl Builder { @@ -296,7 +296,7 @@ impl Builder { _marker: PhantomData, serializer: (), writer: (), - config: SendConfig { flush_on_send: true }, + config: None, } } } @@ -362,17 +362,22 @@ impl Builder { } impl Builder { - /// Flush the writer after every [`Sender::send()`] and - /// [`Sender::send_blocking()`] call. + /// Set the [`Config`] for this sender. /// - /// **Default value**: `true`. + /// # Example + /// + /// ```no_run + /// use channels::sender::{Config, Sender}; /// - /// If this option is disabled, then flushing the writer (if needed) must be - /// done manually through the provided references given by [`Sender::get()`] - /// and [`Sender::get_mut()`]. + /// let config = Config::default() + /// .flush_on_send(false); + /// + /// let tx = Sender::::builder() + /// .config(config); + /// ``` #[must_use] - pub fn flush_on_send(mut self, yes: bool) -> Self { - self.config.flush_on_send = yes; + pub fn config(mut self, config: Config) -> Self { + self.config = Some(config); self } @@ -392,16 +397,42 @@ impl Builder { writer: StatIO::new(self.writer), serializer: self.serializer, pcb: Pcb::new(), - config: self.config, + config: self.config.unwrap_or_default(), } } } -impl fmt::Debug for SendConfig { +/// Configuration for [`Sender`]. +#[derive(Clone)] +pub struct Config { + pub(crate) flush_on_send: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { flush_on_send: true } + } +} + +impl Config { + /// Flush the underlying writer after every [`send()`] or [`send_blocking()`]. + /// + /// **Default:** `true` + /// + /// [`send()`]: Sender::send() + /// [`send_blocking()`]: Sender::send_blocking() + #[must_use] + pub fn flush_on_send(mut self, yes: bool) -> Self { + self.flush_on_send = yes; + self + } +} + +impl fmt::Debug for Config { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut debug = f.debug_struct("Config"); - debug.field("flush_on_send", &self.flush_on_send); - debug.finish() + f.debug_struct("Config") + .field("flush_on_send", &self.flush_on_send) + .finish() } }