From a8523c266e9934864fe5d14348122187395a2770 Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Tue, 8 Dec 2020 18:15:06 +0100 Subject: buffered-reader: Assert that all types are Send and Sync. - See #615. --- buffered-reader/src/adapter.rs | 5 +++ buffered-reader/src/decompress_bzip2.rs | 4 +++ buffered-reader/src/decompress_deflate.rs | 8 +++++ buffered-reader/src/dup.rs | 4 +++ buffered-reader/src/eof.rs | 3 ++ buffered-reader/src/file_generic.rs | 3 ++ buffered-reader/src/file_unix.rs | 3 ++ buffered-reader/src/generic.rs | 4 +++ buffered-reader/src/lib.rs | 3 ++ buffered-reader/src/limitor.rs | 4 +++ buffered-reader/src/macros.rs | 52 +++++++++++++++++++++++++++++++ buffered-reader/src/memory.rs | 3 ++ buffered-reader/src/reserve.rs | 4 +++ 13 files changed, 100 insertions(+) create mode 100644 buffered-reader/src/macros.rs diff --git a/buffered-reader/src/adapter.rs b/buffered-reader/src/adapter.rs index 7b620a2b..65c7a8aa 100644 --- a/buffered-reader/src/adapter.rs +++ b/buffered-reader/src/adapter.rs @@ -16,6 +16,11 @@ pub struct Adapter, B: fmt::Debug, C: fmt::Debug> { cookie: C, } +assert_send_and_sync!(Adapter + where T: BufferedReader, + B: fmt::Debug, + C: fmt::Debug); + impl, B: fmt::Debug, C: fmt::Debug> fmt::Display for Adapter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Adapter").finish() diff --git a/buffered-reader/src/decompress_bzip2.rs b/buffered-reader/src/decompress_bzip2.rs index c0c60653..8902c2af 100644 --- a/buffered-reader/src/decompress_bzip2.rs +++ b/buffered-reader/src/decompress_bzip2.rs @@ -13,6 +13,10 @@ pub struct Bzip, C: fmt::Debug> { reader: Generic, C>, } +assert_send_and_sync!(Bzip + where R: BufferedReader, + C: fmt::Debug); + impl > Bzip { /// Instantiates a new bzip decompression reader. /// diff --git a/buffered-reader/src/decompress_deflate.rs b/buffered-reader/src/decompress_deflate.rs index 6d8af629..43084a5f 100644 --- a/buffered-reader/src/decompress_deflate.rs +++ b/buffered-reader/src/decompress_deflate.rs @@ -13,6 +13,10 @@ pub struct Deflate, C: fmt::Debug> { reader: Generic, C>, } +assert_send_and_sync!(Deflate + where R: BufferedReader, + C: fmt::Debug); + impl > Deflate { /// Instantiates a new deflate decompression reader. /// @@ -127,6 +131,10 @@ pub struct Zlib, C: fmt::Debug> { reader: Generic, C>, } +assert_send_and_sync!(Zlib + where R: BufferedReader, + C: fmt::Debug); + impl > Zlib { /// Instantiates a new zlib decompression reader. /// diff --git a/buffered-reader/src/dup.rs b/buffered-reader/src/dup.rs index afca4296..50a9aa26 100644 --- a/buffered-reader/src/dup.rs +++ b/buffered-reader/src/dup.rs @@ -21,6 +21,10 @@ pub struct Dup, C: fmt::Debug> { cookie: C, } +assert_send_and_sync!(Dup + where T: BufferedReader, + C: fmt::Debug); + impl, C: fmt::Debug> fmt::Display for Dup { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Dup") diff --git a/buffered-reader/src/eof.rs b/buffered-reader/src/eof.rs index 7f36e074..c21ecde9 100644 --- a/buffered-reader/src/eof.rs +++ b/buffered-reader/src/eof.rs @@ -10,6 +10,9 @@ pub struct EOF { cookie: C, } +assert_send_and_sync!(EOF + where C: fmt::Debug); + impl fmt::Display for EOF { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("EOF") diff --git a/buffered-reader/src/file_generic.rs b/buffered-reader/src/file_generic.rs index 4a1cb830..cc9f1367 100644 --- a/buffered-reader/src/file_generic.rs +++ b/buffered-reader/src/file_generic.rs @@ -12,6 +12,9 @@ use crate::file_error::FileError; /// platform-specific versions. pub struct File(Generic, PathBuf); +assert_send_and_sync!(File + where C: fmt::Debug); + impl fmt::Display for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "File {:?}", self.1.display()) diff --git a/buffered-reader/src/file_unix.rs b/buffered-reader/src/file_unix.rs index 8adca1e6..9502021f 100644 --- a/buffered-reader/src/file_unix.rs +++ b/buffered-reader/src/file_unix.rs @@ -27,6 +27,9 @@ const MMAP_THRESHOLD: u64 = 16 * 4096; /// just using a generic reader. pub struct File<'a, C: fmt::Debug>(Imp<'a, C>, PathBuf); +assert_send_and_sync!(File<'_, C> + where C: fmt::Debug); + impl<'a, C: fmt::Debug> fmt::Display for File<'a, C> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} {:?}", self.0, self.1.display()) diff --git a/buffered-reader/src/generic.rs b/buffered-reader/src/generic.rs index 2332950e..25c56272 100644 --- a/buffered-reader/src/generic.rs +++ b/buffered-reader/src/generic.rs @@ -28,6 +28,10 @@ pub struct Generic { cookie: C, } +assert_send_and_sync!(Generic + where T: io::Read, + C: fmt::Debug); + impl fmt::Display for Generic { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Generic") diff --git a/buffered-reader/src/lib.rs b/buffered-reader/src/lib.rs index 83f6da1c..45c12726 100644 --- a/buffered-reader/src/lib.rs +++ b/buffered-reader/src/lib.rs @@ -231,6 +231,9 @@ use std::cmp; use std::fmt; use std::convert::TryInto; +#[macro_use] +mod macros; + mod generic; mod memory; mod limitor; diff --git a/buffered-reader/src/limitor.rs b/buffered-reader/src/limitor.rs index 369c9f11..de75ee5e 100644 --- a/buffered-reader/src/limitor.rs +++ b/buffered-reader/src/limitor.rs @@ -13,6 +13,10 @@ pub struct Limitor, C: fmt::Debug> { cookie: C, } +assert_send_and_sync!(Limitor + where T: BufferedReader, + C: fmt::Debug); + impl, C: fmt::Debug> fmt::Display for Limitor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Limitor") diff --git a/buffered-reader/src/macros.rs b/buffered-reader/src/macros.rs new file mode 100644 index 00000000..ff30d6fb --- /dev/null +++ b/buffered-reader/src/macros.rs @@ -0,0 +1,52 @@ +/// A simple shortcut for ensuring a type is send and sync. +/// +/// For most types just call it after defining the type: +/// +/// ``` +/// pub struct MyStruct {} +/// assert_send_and_sync!(MyStruct); +/// ``` +/// +/// For types with lifetimes, use the anonymous lifetime: +/// +/// ``` +/// pub struct WithLifetime<'a> {} +/// assert_send_and_sync!(MyStruct<'_>); +/// ``` +/// +/// For a type generic over another type `W`, +/// pass the type `W` as a second argument +/// including a trait bound when needed: +/// +/// ``` +/// pub struct MyWriter {} +/// assert_send_and_sync!(MyWriterStruct, W: io::Write); +/// ``` +/// +/// This will assert that `MyWriterStruct` is `Send` and `Sync` +/// if `W` is `Send` and `Sync`. +/// +/// You can also combine the two and be generic over multiple types: +/// +/// ``` +/// pub struct MyWriterWithLifetime {} +/// assert_send_and_sync!(MyWriterStruct<'_, C, W>, C, W: io::Write); +/// ``` +/// +macro_rules! assert_send_and_sync { + ( $x:ty where $( $g:ident$( : $b:path )? $(,)?)*) => { + impl<$( $g ),*> crate::macros::Sendable for $x + where $( $g: Send + Sync $(+ $b)? ),* + {} + impl<$( $g ),*> crate::macros::Syncable for $x + where $( $g: Send + Sync $(+ $b)? ),* + {} + }; + ( $x:ty ) => { + impl crate::macros::Sendable for $x {} + impl crate::macros::Syncable for $x {} + }; +} + +pub(crate) trait Sendable : Send {} +pub(crate) trait Syncable : Sync {} diff --git a/buffered-reader/src/memory.rs b/buffered-reader/src/memory.rs index de2f61bb..d13dd018 100644 --- a/buffered-reader/src/memory.rs +++ b/buffered-reader/src/memory.rs @@ -21,6 +21,9 @@ pub struct Memory<'a, C: fmt::Debug> { cookie: C, } +assert_send_and_sync!(Memory<'_, C> + where C: fmt::Debug); + impl<'a, C: fmt::Debug> fmt::Display for Memory<'a, C> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Memory ({} of {} bytes read)", diff --git a/buffered-reader/src/reserve.rs b/buffered-reader/src/reserve.rs index 9d3d755f..b9c59b69 100644 --- a/buffered-reader/src/reserve.rs +++ b/buffered-reader/src/reserve.rs @@ -17,6 +17,10 @@ pub struct Reserve, C: fmt::Debug> { cookie: C, } +assert_send_and_sync!(Reserve + where T: BufferedReader, + C: fmt::Debug); + impl, C: fmt::Debug> fmt::Display for Reserve { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Reserve") -- cgit v1.2.3