Implement stuff for concurrency.
authorChris Morgan <me@chrismorgan.info>
committerChris Morgan <me@chrismorgan.info>
This took some refactoring too for best effect.
.travis.yml
Cargo.toml
README.md
src/lib.rs
src/raw/any.rs [new file with mode: 0644]
src/raw/mod.rs [moved from src/raw.rs with 99% similarity]
src/with_clone.rs [deleted file]

index 2248e9bcc3b31d0ac7afc07d64f7f6b9d1e4e0de..64c99e0e49994ec95b42dbc9e513ed769516f073 100644 (file)
@@ -3,9 +3,13 @@ env:
   global:
     - secure: nR+DJRUQ9v03nNZMpMu1tGKLKBAqdQsTIAr8ffdl+DUEh3b2jvQ+vLLNFLPjsloqhoOXo7cWO7qVpiE4ZOq2lNDURQjdiZGFjh/Y5+xKy2BqFdV7qQ1JoBzsMyx28tQTYz0mtBsACiCYKKb+ddNX5hpwrsjp8cS7htZktA5kbiU=
 script:
-  - [[ "$(rustc --version)" =~ -dev ]] && cargo test --features nightly || ! cargo test --features nightly
-  - [[ "$(rustc --version)" =~ -dev ]] && cargo test --features 'clone nightly' || ! cargo test --features 'clone nightly'
+  - if [[ "$(rustc --version)" =~ -(dev|nightly) ]]; then cargo test --features nightly; else ! cargo test --features nightly; fi
+  - if [[ "$(rustc --version)" =~ -(dev|nightly) ]]; then cargo test --features 'clone nightly'; else ! cargo test --features 'clone nightly'; fi
+  - if [[ "$(rustc --version)" =~ -(dev|nightly) ]]; then cargo test --features 'concurrent nightly'; else ! cargo test --features 'concurrent nightly'; fi
+  - if [[ "$(rustc --version)" =~ -(dev|nightly) ]]; then cargo test --features 'clone concurrent nightly'; else ! cargo test --features 'clone concurrent nightly'; fi
   - cargo test --features clone
+  - cargo test --features concurrent
+  - cargo test --features 'clone concurrent'
   - cargo test
   - cargo doc
 after_script:
index 5ffe51017629792844cf59c6b25f8f60e19aeaf5..85f18cbcbcb25b5beb2e888e288bfa013a1960e8 100644 (file)
@@ -12,4 +12,5 @@ license = "MIT/Apache-2.0"
 
 [features]
 clone = []
+concurrent = []
 nightly = []
index a815caf7c19ff8405bd3176c191bbd466c4ec46a..a498edd50367a2e7fcaf0de00a2f953fc4ca849d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -18,7 +18,13 @@ Instructions
 
 Cargo all the way: it is `anymap` on crates.io.
 
-There is an optional `clone` feature on the `anymap` crate; if enabled, your `AnyMap` will require contained types to implement `Clone` and will itself satisfy `Clone`.
+There are a couple of optional features on the `anymap` crate:
+
+- `clone`: if enabled, your `AnyMap` will require contained types to implement `Clone` and will itself satisfy `Clone`.
+
+- `concurrent`: if enabled, your `AnyMap` will require contained types to satisfy `Send` and `Sync` and will itself satisfy `Send` and `Sync`.
+
+These can be combined if desired.
 
 For users of the nightly instead of the beta of rustc there are a couple of things behind the `nightly` feature like a `drain` method on the `RawAnyMap` and a more efficient hashing technique which makes lookup in the map a tad faster.
 
index 9c0ff303f438a11ad0805c31b7d7f97ca8e501bb..d32af5f2aa4327826844727c183a09f47c247fb7 100644 (file)
@@ -85,8 +85,6 @@ macro_rules! impl_common_methods {
 
 mod unchecked_any;
 pub mod raw;
-#[cfg(feature = "clone")]
-mod with_clone;
 
 /// A collection containing zero or one values for any given type and allowing convenient,
 /// type-safe access to those values.
@@ -402,4 +400,11 @@ mod tests {
         assert_eq!(map2.get::<F>(), Some(&F(5)));
         assert_eq!(map2.get::<J>(), Some(&J(6)));
     }
+
+    #[cfg(feature = "concurrent")]
+    #[test]
+    fn test_concurrent() {
+        fn assert_concurrent<T: Send + Sync>() { }
+        assert_concurrent::<AnyMap>();
+    }
 }
diff --git a/src/raw/any.rs b/src/raw/any.rs
new file mode 100644 (file)
index 0000000..d908040
--- /dev/null
@@ -0,0 +1,105 @@
+use std::fmt;
+use std::any::Any as StdAny;
+
+#[cfg(feature = "clone")]
+#[doc(hidden)]
+pub trait CloneToAny {
+    /// Clone `self` into a new `Box<Any>` object.
+    fn clone_to_any(&self) -> Box<Any>;
+}
+
+#[cfg(feature = "clone")]
+impl<T: Any + Clone> CloneToAny for T {
+    fn clone_to_any(&self) -> Box<Any> {
+        Box::new(self.clone())
+    }
+}
+
+macro_rules! define_any {
+    (#[$m:meta] $t:item $i:item) => {
+        /// A type to emulate dynamic typing.
+        ///
+        /// Every suitable type with no non-`'static` references implements `Any`. See the
+        /// [`std::any` documentation](https://doc.rust-lang.org/std/any/index.html) for more
+        /// details on `Any` in general.
+        ///
+        /// This trait is not `std::any::Any` but rather a type extending that for this library’s
+        /// purposes; most specifically, there are a couple of Cargo features that can be enabled
+        /// which will alter the constraints of what comprises a suitable type:
+        ///
+        /// <table>
+        ///     <thead>
+        ///         <tr>
+        ///             <th title="The name of the Cargo feature to enable">Feature name</th>
+        ///             <th title="If a type doesn’t satisfy these bounds, it won’t implement Any">Additional bounds</th>
+        ///             <th title="Were these docs built with this feature enabled?">Enabled in these docs?</th>
+        ///         </tr>
+        ///     </thead>
+        ///     <tbody>
+        ///         <tr>
+        ///             <th><code>clone</code></th>
+        ///             <td><code><a class=trait title=core::clone::Clone
+        ///             href=http://doc.rust-lang.org/std/clone/trait.Clone.html
+        ///             >Clone</a></code></td>
+        #[cfg_attr(feature = "clone", doc = "             <td>Yes</td>")]
+        #[cfg_attr(not(feature = "clone"), doc = "             <td>No</td>")]
+        ///         </tr>
+        ///         <tr>
+        ///             <th><code>concurrent</code></th>
+        ///             <td><code><a class=trait title=core::marker::Send
+        ///             href=http://doc.rust-lang.org/std/marker/trait.Send.html
+        ///             >Send</a> + <a class=trait title=core::marker::Sync
+        ///             href=http://doc.rust-lang.org/std/marker/trait.Sync.html
+        ///             >Sync</a></code></td>
+        #[cfg_attr(feature = "concurrent", doc = "             <td>Yes</td>")]
+        #[cfg_attr(not(feature = "concurrent"), doc = "             <td>No</td>")]
+        ///         </tr>
+        ///     </tbody>
+        /// </table>
+        #[$m] $t
+        #[$m] $i
+    }
+}
+
+define_any! {
+    #[cfg(all(not(feature = "clone"), not(feature = "concurrent")))]
+    pub trait Any: StdAny { }
+    impl<T: StdAny> Any for T { }
+}
+
+define_any! {
+    #[cfg(all(feature = "clone", not(feature = "concurrent")))]
+    pub trait Any: StdAny + CloneToAny { }
+    impl<T: StdAny + Clone> Any for T { }
+}
+
+define_any! {
+    #[cfg(all(not(feature = "clone"), feature = "concurrent"))]
+    pub trait Any: StdAny + Send + Sync { }
+    impl<T: StdAny + Send + Sync> Any for T { }
+}
+
+define_any! {
+    #[cfg(all(feature = "clone", feature = "concurrent"))]
+    pub trait Any: StdAny + CloneToAny + Send + Sync { }
+    impl<T: StdAny + Clone + Send + Sync> Any for T { }
+}
+
+#[cfg(feature = "clone")]
+impl Clone for Box<Any> {
+    fn clone(&self) -> Box<Any> {
+        (**self).clone_to_any()
+    }
+}
+
+impl<'a> fmt::Debug for &'a Any {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("&Any")
+    }
+}
+
+impl<'a> fmt::Debug for Box<Any> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Box<Any>")
+    }
+}
similarity index 99%
rename from src/raw.rs
rename to src/raw/mod.rs
index 0ed88864bdcda21ee22fce8529a86c550cb938a6..1ae1a6c09d6e7b53bd6e60876cccaec3a83cb37e 100644 (file)
@@ -18,10 +18,9 @@ use std::ops::{Index, IndexMut};
 #[cfg(feature = "nightly")]
 use std::ptr;
 
-#[cfg(not(feature = "clone"))]
-pub use std::any::Any;
-#[cfg(feature = "clone")]
-pub use with_clone::Any;
+pub use self::any::Any;
+
+mod any;
 
 #[cfg(feature = "nightly")]
 struct TypeIdHasher {
diff --git a/src/with_clone.rs b/src/with_clone.rs
deleted file mode 100644 (file)
index 7bdb5b0..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-use std::fmt;
-
-#[doc(hidden)]
-pub trait CloneToAny {
-    /// Clone `self` into a new `Box<Any>` object.
-    fn clone_to_any(&self) -> Box<Any>;
-}
-
-impl<T: Any + Clone> CloneToAny for T {
-    fn clone_to_any(&self) -> Box<Any> {
-        Box::new(self.clone())
-    }
-}
-
-#[doc(hidden)]
-/// Pretty much just `std::any::Any + Clone`.
-pub trait Any: ::std::any::Any + CloneToAny { }
-
-impl<T: ::std::any::Any + Clone> Any for T { }
-
-impl Clone for Box<Any> {
-    fn clone(&self) -> Box<Any> {
-        (**self).clone_to_any()
-    }
-}
-
-impl<'a> fmt::Debug for &'a Any {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.pad("&Any")
-    }
-}
-
-impl<'a> fmt::Debug for Box<Any> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.pad("Box<Any>")
-    }
-}