summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-12-08 18:15:06 +0100
committerJustus Winter <justus@sequoia-pgp.org>2020-12-09 09:47:36 +0100
commita8523c266e9934864fe5d14348122187395a2770 (patch)
treec13927eaf8df09ee91a054fc73bdcaee889d51a6
parentffda43c082b79f7698152287b8236b6c0c9918ec (diff)
buffered-reader: Assert that all types are Send and Sync.
- See #615.
-rw-r--r--buffered-reader/src/adapter.rs5
-rw-r--r--buffered-reader/src/decompress_bzip2.rs4
-rw-r--r--buffered-reader/src/decompress_deflate.rs8
-rw-r--r--buffered-reader/src/dup.rs4
-rw-r--r--buffered-reader/src/eof.rs3
-rw-r--r--buffered-reader/src/file_generic.rs3
-rw-r--r--buffered-reader/src/file_unix.rs3
-rw-r--r--buffered-reader/src/generic.rs4
-rw-r--r--buffered-reader/src/lib.rs3
-rw-r--r--buffered-reader/src/limitor.rs4
-rw-r--r--buffered-reader/src/macros.rs52
-rw-r--r--buffered-reader/src/memory.rs3
-rw-r--r--buffered-reader/src/reserve.rs4
13 files changed, 100 insertions, 0 deletions
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<T: BufferedReader<B>, B: fmt::Debug, C: fmt::Debug> {
cookie: C,
}
+assert_send_and_sync!(Adapter<T, B, C>
+ where T: BufferedReader<B>,
+ B: fmt::Debug,
+ C: fmt::Debug);
+
impl<T: BufferedReader<B>, B: fmt::Debug, C: fmt::Debug> fmt::Display for Adapter<T, B, C> {
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<R: BufferedReader<C>, C: fmt::Debug> {
reader: Generic<BzDecoder<R>, C>,
}
+assert_send_and_sync!(Bzip<R, C>
+ where R: BufferedReader<C>,
+ C: fmt::Debug);
+
impl <R: BufferedReader<()>> Bzip<R, ()> {
/// 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<R: BufferedReader<C>, C: fmt::Debug> {
reader: Generic<DeflateDecoder<R>, C>,
}
+assert_send_and_sync!(Deflate<R, C>
+ where R: BufferedReader<C>,
+ C: fmt::Debug);
+
impl <R: BufferedReader<()>> Deflate<R, ()> {
/// Instantiates a new deflate decompression reader.
///
@@ -127,6 +131,10 @@ pub struct Zlib<R: BufferedReader<C>, C: fmt::Debug> {
reader: Generic<ZlibDecoder<R>, C>,
}
+assert_send_and_sync!(Zlib<R, C>
+ where R: BufferedReader<C>,
+ C: fmt::Debug);
+
impl <R: BufferedReader<()>> Zlib<R, ()> {
/// 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<T: BufferedReader<C>, C: fmt::Debug> {
cookie: C,
}
+assert_send_and_sync!(Dup<T, C>
+ where T: BufferedReader<C>,
+ C: fmt::Debug);
+
impl<T: BufferedReader<C>, C: fmt::Debug> fmt::Display for Dup<T, C> {
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<C> {
cookie: C,
}
+assert_send_and_sync!(EOF<C>
+ where C: fmt::Debug);
+
impl<C> fmt::Display for EOF<C> {
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<C: fmt::Debug>(Generic<fs::File, C>, PathBuf);
+assert_send_and_sync!(File<C>
+ where C: fmt::Debug);
+
impl<C: fmt::Debug> fmt::Display for File<C> {
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<T: io::Read, C: fmt::Debug> {
cookie: C,
}
+assert_send_and_sync!(Generic<T, C>
+ where T: io::Read,
+ C: fmt::Debug);
+
impl<T: io::Read, C: fmt::Debug> fmt::Display for Generic<T, C> {
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<T: BufferedReader<C>, C: fmt::Debug> {
cookie: C,
}
+assert_send_and_sync!(Limitor<T, C>
+ where T: BufferedReader<C>,
+ C: fmt::Debug);
+
impl<T: BufferedReader<C>, C: fmt::Debug> fmt::Display for Limitor<T, C> {
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<W: io::Write> {}
+/// assert_send_and_sync!(MyWriterStruct<W>, W: io::Write);
+/// ```
+///
+/// This will assert that `MyWriterStruct<W>` 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<a', C, W: io::Write> {}
+/// 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<T: BufferedReader<C>, C: fmt::Debug> {
cookie: C,
}
+assert_send_and_sync!(Reserve<T, C>
+ where T: BufferedReader<C>,
+ C: fmt::Debug);
+
impl<T: BufferedReader<C>, C: fmt::Debug> fmt::Display for Reserve<T, C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Reserve")