summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorInna Palant <ipalant@google.com>2023-12-11 16:45:28 -0800
committerInna Palant <ipalant@google.com>2023-12-11 16:45:28 -0800
commita2909347ec722e2b3d4dbe20a7c6ca3086981b3d (patch)
treeff176214b85e9271e57b726f443643ddc3042b27
parent21be4635b1b8eabdf7a3abed6367ada2e24be5c6 (diff)
parent46697198d609f156775a0863bbd449e3ec84be67 (diff)
downloaddowncast-a2909347ec722e2b3d4dbe20a7c6ca3086981b3d.tar.gz
Merge remote-tracking branch 'origin/upstream'platform-tools-34.0.5simpleperf-release
Import b/310600230
-rw-r--r--.cargo_vcs_info.json5
-rw-r--r--.gitattributes7
-rw-r--r--.gitignore15
-rw-r--r--Android.bp42
-rw-r--r--Cargo.toml28
l---------LICENSE1
-rw-r--r--LICENSE-MIT9
-rw-r--r--METADATA19
-rw-r--r--MODULE_LICENSE_MIT0
-rw-r--r--OWNERS2
-rw-r--r--README.md49
-rw-r--r--cargo_embargo.json3
-rw-r--r--clippy.toml1
-rw-r--r--examples/simple.rs41
-rw-r--r--examples/sync_service.rs41
-rw-r--r--examples/with_params.rs56
-rw-r--r--src/lib.rs453
-rw-r--r--tests/tests.rs78
18 files changed, 850 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..4c3ba15
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,5 @@
+{
+ "git": {
+ "sha1": "14a52c5882aff45173fd9796cde73a6037709dc6"
+ }
+} \ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..ba1e72c
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,7 @@
+[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
+
+*.rs rust
+*.md rust
+*.toml rust
+*.yaml rust
+*.json rust
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f222c7c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+# Platform
+.DS_Store
+
+# Editors
+*#
+*~
+[._]*.sw?
+
+# Cargo
+Cargo.lock
+.cargo/
+target/
+
+# Rustfmt
+*.bk
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..abd3011
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,42 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file as changes will be overridden on upgrade.
+
+rust_test {
+ name: "downcast_test_tests_tests",
+ host_supported: true,
+ crate_name: "tests",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.11.0",
+ srcs: ["tests/tests.rs"],
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ test_options: {
+ unit_test: true,
+ },
+ edition: "2018",
+ features: [
+ "default",
+ "std",
+ ],
+ rustlibs: ["libdowncast"],
+}
+
+rust_library {
+ name: "libdowncast",
+ host_supported: true,
+ crate_name: "downcast",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.11.0",
+ srcs: ["src/lib.rs"],
+ edition: "2018",
+ features: [
+ "default",
+ "std",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ product_available: true,
+ vendor_available: true,
+}
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..459d9dd
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,28 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "downcast"
+version = "0.11.0"
+authors = ["Felix Köpge <fkoep@mailbox.org>"]
+description = "Trait for downcasting trait objects back to their original types."
+documentation = "https://docs.rs/downcast"
+readme = "README.md"
+keywords = ["any"]
+categories = ["no-std", "rust-patterns"]
+license = "MIT"
+repository = "https://github.com/fkoep/downcast-rs"
+
+[features]
+default = ["std"]
+nightly = []
+std = []
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..7f9a88e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSE-MIT \ No newline at end of file
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..af002fa
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,9 @@
+MIT License (MIT)
+
+Copyright (c) 2017 Felix Köpge
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..f6625a7
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "downcast"
+description: "Trait for downcasting trait objects back to their original types."
+third_party {
+ identifier {
+ type: "crates.io"
+ value: "https://crates.io/crates/downcast"
+ }
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/downcast/downcast-0.11.0.crate"
+ }
+ version: "0.11.0"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2023
+ month: 11
+ day: 6
+ }
+}
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_MIT
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..48bea6e
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 688011
+include platform/prebuilts/rust:main:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c35fab5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,49 @@
+# downcast &emsp; ![Latest Version]
+
+[Latest Version]: https://img.shields.io/crates/v/downcast.svg
+
+A trait (& utilities) for downcasting trait objects back to their original types.
+
+## [link to API documentation](https://docs.rs/downcast)
+
+## example usage
+
+Add to your Cargo.toml:
+
+```toml
+[dependencies]
+downcast = "0.12"
+```
+
+Add to your crate root:
+
+```rust
+#[macro_use]
+extern crate downcast;
+```
+
+* [simple](examples/simple.rs) showcases the most simple usage of this library.
+* [with_params](examples/with_params.rs) showcases how to deal with traits who have type parameters.
+* [sync_service](examples/sync_service.rs) showcases how to downcast `Arc`-pointers.
+
+## build features
+
+* **std (default)** enables all functionality requiring the standard library (`Downcast::downcast()`).
+* **nightly** enables all functionality requiring rust nightly (`Any::type_name()`).
+
+## faq
+
+__Q: I'm getting `the size for values of type XXX cannot be known at compile time` errors, what am i doing wrong?__
+
+A: Make sure you use the corresponding `Any` bound along with the `Downcast` traits. So, `Any` for `Downcast` and `AnySync` for `DowncastSync`.
+
+__Q: Can i cast trait objects to trait objects?__
+
+A: No, that is currently no possible in safe rust - and unsafe solutions are very tricky, as well. If you found a solution, feel free to share it!
+
+__Q: What is the difference between this and the `downcast-rs` crate on crates.io?__
+
+A: At the moment, there isn't one, really.
+There was an unfortunate naming clash. You may consider using the other crate, as it is more actively maintained.
+This one is considered feature-complete and frozen in functionality.
+Hopefully, one day, the Rust language will make downcasting easier and we will need neither of these crates anymore!
diff --git a/cargo_embargo.json b/cargo_embargo.json
new file mode 100644
index 0000000..9a0a579
--- /dev/null
+++ b/cargo_embargo.json
@@ -0,0 +1,3 @@
+{
+ "tests": true
+}
diff --git a/clippy.toml b/clippy.toml
new file mode 100644
index 0000000..67127aa
--- /dev/null
+++ b/clippy.toml
@@ -0,0 +1 @@
+blacklisted-names = []
diff --git a/examples/simple.rs b/examples/simple.rs
new file mode 100644
index 0000000..c5841be
--- /dev/null
+++ b/examples/simple.rs
@@ -0,0 +1,41 @@
+extern crate downcast;
+
+// we need to use downcast::Any instead of std::any::Any
+use downcast::{downcast, Any};
+
+/* Trait */
+
+trait Animal: Any {
+ fn what_am_i(&self);
+}
+
+downcast!(dyn Animal);
+
+/* Impl */
+
+struct Bird;
+
+impl Animal for Bird {
+ fn what_am_i(&self){
+ println!("Im a bird!")
+ }
+}
+
+impl Bird {
+ fn wash_beak(&self) {
+ println!("Beak has been washed! What a clean beak!");
+ }
+}
+
+/* Main */
+
+fn main() {
+ let animal: Box<dyn Animal> = Box::new(Bird);
+ animal.what_am_i();
+ {
+ let bird = animal.downcast_ref::<Bird>().unwrap();
+ bird.wash_beak();
+ }
+ let bird: Box<Bird> = animal.downcast::<Bird>().ok().unwrap();
+ bird.wash_beak();
+}
diff --git a/examples/sync_service.rs b/examples/sync_service.rs
new file mode 100644
index 0000000..36f4426
--- /dev/null
+++ b/examples/sync_service.rs
@@ -0,0 +1,41 @@
+extern crate downcast;
+
+// careful: do not combine downcast_sync! with downcast::Any, you will get `size not known at compile time` errors
+use downcast::{downcast_sync, AnySync};
+use std::sync::Arc;
+
+/* Trait */
+
+trait Service: AnySync {
+ fn what_am_i(&self);
+}
+
+downcast_sync!(dyn Service);
+
+/* Impl */
+
+struct Database {}
+
+impl Service for Database {
+ fn what_am_i(&self){
+ println!("I'm a database!");
+ }
+}
+
+impl Database {
+ fn purge_data(&self) {
+ println!("Database has been purged! Goodbye, data!")
+ }
+}
+
+fn main(){
+ let service: Arc<dyn Service> = Arc::new(Database{});
+ service.what_am_i();
+ {
+ let db = service.downcast_ref::<Database>().unwrap();
+ db.purge_data();
+ }
+ let db: Arc<Database> = service.downcast_arc::<Database>().ok().unwrap();
+ db.purge_data();
+}
+
diff --git a/examples/with_params.rs b/examples/with_params.rs
new file mode 100644
index 0000000..cc71f84
--- /dev/null
+++ b/examples/with_params.rs
@@ -0,0 +1,56 @@
+extern crate downcast;
+
+use downcast::{downcast, Any};
+use std::fmt::Debug;
+
+/* Trait */
+
+trait Animal<X: Debug>: Any {
+ fn what_am_i(&self);
+ fn get_item(&self) -> Option<&X>;
+}
+
+downcast!(<X> dyn Animal<X> where X: Debug);
+
+/* Impl */
+
+struct Bird<X>{ item: Option<X> }
+
+impl<X: Debug + 'static> Animal<X> for Bird<X> {
+ fn what_am_i(&self){
+ println!("Im a bird!")
+ }
+ fn get_item(&self) -> Option<&X> {
+ match self.item {
+ Some(ref item) => println!("I'm holding a {:?}! Look, see!", item),
+ None => println!("I'm holding nothing!")
+ }
+ self.item.as_ref()
+ }
+}
+
+impl<X: Debug + 'static> Bird<X> {
+ fn eat_item(&mut self) {
+ if self.item.is_some() {
+ let item = self.item.take().unwrap();
+ println!("I ate the {:?}! I hope it was edible!", item)
+ } else {
+ println!("I don't have anything to eat!")
+ }
+ }
+}
+
+/* Main */
+
+fn main() {
+ let mut animal: Box<dyn Animal<String>> = Box::new(Bird{ item: Some("haselnut".to_owned()) });
+ animal.what_am_i();
+ {
+ let bird = animal.downcast_mut::<Bird<String>>().unwrap();
+ bird.get_item();
+ bird.eat_item();
+ }
+ let mut bird = animal.downcast::<Bird<String>>().ok().unwrap();
+ bird.get_item();
+ bird.eat_item();
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..aeab2a3
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,453 @@
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg(not(feature = "std"))]
+mod std {
+ pub use core::*;
+}
+
+use std::any::{Any as StdAny, TypeId, type_name};
+use std::fmt::{self, Debug, Display};
+
+#[cfg(feature = "std")]
+use std::{error::Error, rc::Rc, sync::Arc};
+
+// ++++++++++++++++++++ Any ++++++++++++++++++++
+
+pub trait Any: StdAny {
+ #[doc(hidden)]
+ fn as_any(&self) -> &dyn StdAny;
+
+ #[doc(hidden)]
+ fn as_any_mut(&mut self) -> &mut dyn StdAny;
+
+ #[doc(hidden)]
+ #[cfg(feature = "std")]
+ fn into_any(self: Box<Self>) -> Box<dyn StdAny>;
+
+ #[doc(hidden)]
+ #[cfg(feature = "std")]
+ fn into_any_rc(self: Rc<Self>) -> Rc<dyn StdAny>;
+
+ fn type_name(&self) -> &'static str;
+}
+
+impl<T> Any for T where T: StdAny {
+ #[doc(hidden)]
+ fn as_any(&self) -> &dyn StdAny { self }
+
+ #[doc(hidden)]
+ fn as_any_mut(&mut self) -> &mut dyn StdAny { self }
+
+ #[cfg(feature = "std")]
+ fn into_any(self: Box<Self>) -> Box<dyn StdAny> { self }
+
+ #[cfg(feature = "std")]
+ fn into_any_rc(self: Rc<Self>) -> Rc<dyn StdAny> { self }
+
+ fn type_name(&self) -> &'static str { type_name::<Self>() }
+}
+
+#[cfg(feature = "std")]
+pub trait AnySync: Any + Send + Sync {
+ fn into_any_arc(self: Arc<Self>) -> Arc<dyn StdAny + Send + Sync>;
+}
+
+#[cfg(feature = "std")]
+impl<T> AnySync for T where T: Any + Send + Sync {
+ fn into_any_arc(self: Arc<Self>) -> Arc<dyn StdAny + Send + Sync> { self }
+}
+
+// ++++++++++++++++++++ TypeMismatch ++++++++++++++++++++
+
+#[derive(Debug, Clone, Copy)]
+pub struct TypeMismatch {
+ pub expected: &'static str,
+ pub found: &'static str,
+}
+
+impl TypeMismatch {
+ pub fn new<T, O>(found_obj: &O) -> Self
+ where T: Any + ?Sized, O: Any + ?Sized
+ {
+ TypeMismatch {
+ expected: type_name::<T>(),
+ found: found_obj.type_name(),
+ }
+ }
+}
+
+impl Display for TypeMismatch {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "Type mismatch: Expected '{}', found '{}'!", self.expected, self.found)
+ }
+}
+
+#[cfg(feature = "std")]
+impl Error for TypeMismatch {}
+
+// ++++++++++++++++++++ DowncastError ++++++++++++++++++++
+
+pub struct DowncastError<O> {
+ mismatch: TypeMismatch,
+ object: O,
+}
+
+impl<O> DowncastError<O> {
+ pub fn new(mismatch: TypeMismatch, object: O) -> Self {
+ Self{ mismatch, object }
+ }
+ pub fn type_mismatch(&self) -> TypeMismatch { self.mismatch }
+ pub fn into_object(self) -> O { self.object }
+}
+
+impl<O> Debug for DowncastError<O> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("DowncastError")
+ .field("mismatch", &self.mismatch)
+ .finish()
+ }
+}
+
+impl<O> Display for DowncastError<O> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ Display::fmt(&self.mismatch, fmt)
+ }
+}
+
+#[cfg(feature = "std")]
+impl<O> Error for DowncastError<O> {}
+
+// ++++++++++++++++++++ Downcast ++++++++++++++++++++
+
+pub trait Downcast<T>: Any
+ where T: Any
+{
+ fn is_type(&self) -> bool { self.type_id() == TypeId::of::<T>() }
+
+ fn downcast_ref(&self) -> Result<&T, TypeMismatch> {
+ if self.is_type() {
+ Ok(self.as_any().downcast_ref().unwrap())
+ } else {
+ Err(TypeMismatch::new::<T, Self>(self))
+ }
+ }
+
+ fn downcast_mut(&mut self) -> Result<&mut T, TypeMismatch> {
+ if self.is_type() {
+ Ok(self.as_any_mut().downcast_mut().unwrap())
+ } else {
+ Err(TypeMismatch::new::<T, Self>(self))
+ }
+ }
+
+ #[cfg(feature = "std")]
+ fn downcast(self: Box<Self>) -> Result<Box<T>, DowncastError<Box<Self>>> {
+ if self.is_type() {
+ Ok(self.into_any().downcast().unwrap())
+ } else {
+ let mismatch = TypeMismatch::new::<T, Self>(&*self);
+ Err(DowncastError::new(mismatch, self))
+ }
+ }
+
+ #[cfg(feature = "std")]
+ fn downcast_rc(self: Rc<Self>) -> Result<Rc<T>, DowncastError<Rc<Self>>> {
+ if self.is_type() {
+ Ok(self.into_any_rc().downcast().unwrap())
+ } else {
+ let mismatch = TypeMismatch::new::<T, Self>(&*self);
+ Err(DowncastError::new(mismatch, self))
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+pub trait DowncastSync<T>: Downcast<T> + AnySync
+ where T: AnySync
+{
+ fn downcast_arc(self: Arc<Self>) -> Result<Arc<T>, DowncastError<Arc<Self>>> {
+ if self.is_type() {
+ Ok(self.into_any_arc().downcast().unwrap())
+ } else {
+ let mismatch = TypeMismatch::new::<T, Self>(&*self);
+ Err(DowncastError::new(mismatch, self))
+ }
+ }
+}
+
+// ++++++++++++++++++++ macros ++++++++++++++++++++
+
+#[doc(hidden)]
+pub mod _std {
+ #[cfg(feature = "std")]
+ pub use std::*;
+ #[cfg(not(feature = "std"))]
+ pub use core::*;
+}
+
+/// Implements [`Downcast`](trait.Downcast.html) for your trait-object-type.
+///
+/// ```ignore
+/// impl_downcast!(Foo);
+/// impl_downcast!(<B> Foo<B> where B: Bar);
+/// impl_downcast!(<B> Foo<Bar = B>);
+/// ```
+///
+/// expands to
+///
+/// ```ignore
+/// impl<T> Downcast<T> for Foo
+/// where T: Any
+/// {}
+///
+/// impl<T, B> Downcast<T> for Foo<B>
+/// where T: Any, B: Bar
+/// {}
+///
+/// impl<T, B> Downcast<T> for Foo<Bar = B>
+/// where T: Any
+/// {}
+/// ```
+#[macro_export]
+macro_rules! impl_downcast {
+ (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
+ impl<_T, $($params),+> $crate::Downcast<_T> for $base
+ where _T: $crate::Any, $($params: 'static,)* $($($bounds)+)*
+ {}
+ };
+ ($base:ty) => {
+ impl<_T> $crate::Downcast<_T> for $base
+ where _T: $crate::Any
+ {}
+ };
+}
+
+/// Implements [`Downcast`](trait.Downcast.html) and [`DowncastSync`](trait.DowncastSync.html) for your trait-object-type.
+#[cfg(feature = "std")]
+#[macro_export]
+macro_rules! impl_downcast_sync {
+ (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
+ impl<_T, $($params),+> $crate::Downcast<_T> for $base
+ where _T: $crate::Any, $($params: 'static,)* $($($bounds)+)*
+ {}
+
+ impl<_T, $($params),+> $crate::DowncastSync<_T> for $base
+ where _T: $crate::AnySync, $($params: 'static,)* $($($bounds)+)*
+ {}
+ };
+ ($base:ty) => {
+ impl<_T> $crate::Downcast<_T> for $base
+ where _T: $crate::Any
+ {}
+
+ impl<_T> $crate::DowncastSync<_T> for $base
+ where _T: $crate::AnySync
+ {}
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! downcast_methods_core {
+ (@items) => {
+ #[allow(unused, missing_docs)]
+ pub fn is<_T>(&self) -> bool
+ where _T: $crate::Any, Self: $crate::Downcast<_T>
+ {
+ $crate::Downcast::<_T>::is_type(self)
+ }
+
+ #[allow(unused, missing_docs)]
+ pub fn downcast_ref<_T>(&self) -> $crate::_std::result::Result<&_T, $crate::TypeMismatch>
+ where _T: $crate::Any, Self: $crate::Downcast<_T>
+ {
+ $crate::Downcast::<_T>::downcast_ref(self)
+ }
+
+ #[allow(unused, missing_docs)]
+ pub fn downcast_mut<_T>(&mut self) -> $crate::_std::result::Result<&mut _T, $crate::TypeMismatch>
+ where _T: $crate::Any, Self: $crate::Downcast<_T>
+ {
+ $crate::Downcast::<_T>::downcast_mut(self)
+ }
+ };
+ (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
+ impl<$($params),+> $base
+ where $($params: 'static,)* $($($bounds)+)*
+ {
+ $crate::downcast_methods_core!(@items);
+ }
+ };
+ ($base:ty) => {
+ impl $base {
+ $crate::downcast_methods_core!(@items);
+ }
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! downcast_methods_std {
+ (@items) => {
+ $crate::downcast_methods_core!(@items);
+
+ #[allow(unused, missing_docs)]
+ pub fn downcast<_T>(self: $crate::_std::boxed::Box<Self>) -> $crate::_std::result::Result<$crate::_std::boxed::Box<_T>, $crate::DowncastError<$crate::_std::boxed::Box<Self>>>
+ where _T: $crate::Any, Self: $crate::Downcast<_T>
+ {
+ $crate::Downcast::<_T>::downcast(self)
+ }
+
+ #[allow(unused, missing_docs)]
+ pub fn downcast_rc<_T>(self: $crate::_std::rc::Rc<Self>) -> $crate::_std::result::Result<$crate::_std::rc::Rc<_T>, $crate::DowncastError<$crate::_std::rc::Rc<Self>>>
+ where _T: $crate::Any, Self: $crate::Downcast<_T>
+ {
+ $crate::Downcast::<_T>::downcast_rc(self)
+ }
+ };
+ (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
+ impl<$($params),+> $base
+ $(where $($bounds)+)*
+ {
+ $crate::downcast_methods_std!(@items);
+ }
+ };
+ ($base:ty) => {
+ impl $base {
+ $crate::downcast_methods_std!(@items);
+ }
+ };
+}
+
+#[doc(hidden)]
+#[cfg(feature = "std")]
+#[macro_export]
+macro_rules! downcast_sync_methods {
+ (@items) => {
+ $crate::downcast_methods_std!(@items);
+
+ #[allow(unused, missing_docs)]
+ pub fn downcast_arc<_T>(self: $crate::_std::sync::Arc<Self>) -> $crate::_std::result::Result<$crate::_std::sync::Arc<_T>, $crate::DowncastError<$crate::_std::sync::Arc<Self>>>
+ where _T: $crate::AnySync, Self: $crate::DowncastSync<_T>
+ {
+ $crate::DowncastSync::<_T>::downcast_arc(self)
+ }
+ };
+ (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => {
+ impl<$($params),+> $base
+ $(where $($bounds)+)*
+ {
+ $crate::downcast_sync_methods!(@items);
+ }
+ };
+ ($base:ty) => {
+ impl $base {
+ $crate::downcast_sync_methods!(@items);
+ }
+ };
+}
+
+
+/// Generate `downcast`-methods for your trait-object-type.
+///
+/// ```ignore
+/// downcast_methods!(Foo);
+/// downcast_methods!(<B> Foo<B> where B: Bar);
+/// downcast_methods!(<B> Foo<Bar = B>);
+/// ```
+///
+/// ```ignore
+/// impl dyn Foo {
+/// /* impl<B> dyn Foo<B> where B: Bar { */
+/// /* impl<B> dyn Foo<Bar = B> { */
+///
+/// pub fn is<T>(&self) -> bool
+/// where T: Any, Self: Downcast<T>
+/// { ... }
+///
+/// pub fn downcast_ref<T>(&self) -> Result<&T, TypeMismatch>
+/// where T: Any, Self: Downcast<T>
+/// { ... }
+///
+/// pub fn downcast_mut<T>(&mut self) -> Result<&mut T, TypeMismatch>
+/// where T: Any, Self: Downcast<T>
+/// { ... }
+/// }
+/// ```
+#[cfg(not(feature = "std"))]
+#[macro_export]
+macro_rules! downcast_methods {
+ ($($tt:tt)+) => { $crate::downcast_methods_core!($($tt)+); }
+}
+
+/// Generate `downcast`-methods for your trait-object-type.
+///
+/// ```ignore
+/// downcast_methods!(Foo);
+/// downcast_methods!(<B> Foo<B> where B: Bar);
+/// downcast_methods!(<B> Foo<Bar = B>);
+/// ```
+///
+/// ```ignore
+/// impl dyn Foo {
+/// /* impl<B> dyn Foo<B> where B: Bar { */
+/// /* impl<B> dyn Foo<Bar = B> { */
+///
+/// pub fn is<T>(&self) -> bool
+/// where T: Any, Self: Downcast<T>
+/// { ... }
+///
+/// pub fn downcast_ref<T>(&self) -> Result<&T, TypeMismatch>
+/// where T: Any, Self: Downcast<T>
+/// { ... }
+///
+/// pub fn downcast_mut<T>(&mut self) -> Result<&mut T, TypeMismatch>
+/// where T: Any, Self: Downcast<T>
+/// { ... }
+///
+/// pub fn downcast<T>(self: Box<Self>) -> Result<Box<T>, DowncastError<Box<T>>>
+/// where T: Any, Self: Downcast<T>
+/// { ... }
+/// }
+/// ```
+#[cfg(feature = "std")]
+#[macro_export]
+macro_rules! downcast_methods {
+ ($($tt:tt)+) => { $crate::downcast_methods_std!($($tt)+); }
+}
+
+/// Implements [`Downcast`](trait.Downcast.html) and generates
+/// `downcast`-methods for your trait-object-type.
+///
+/// See [`impl_downcast`](macro.impl_downcast.html),
+/// [`downcast_methods`](macro.downcast_methods.html).
+#[macro_export]
+macro_rules! downcast {
+ ($($tt:tt)+) => {
+ $crate::impl_downcast!($($tt)+);
+ $crate::downcast_methods!($($tt)+);
+ }
+}
+
+/// Implements [`DowncastSync`](trait.DowncastSync.html) and generates
+/// `downcast`-methods for your trait-object-type.
+///
+/// See [`impl_downcast_sync`](macro.impl_downcast.html),
+/// [`downcast_sync_methods`](macro.downcast_methods.html).
+#[cfg(feature = "std")]
+#[macro_export]
+macro_rules! downcast_sync {
+ ($($tt:tt)+) => {
+ $crate::impl_downcast_sync!($($tt)+);
+ $crate::downcast_sync_methods!($($tt)+);
+ }
+}
+
+// NOTE: We only implement the trait, because implementing the methods won't
+// be possible when we replace downcast::Any by std::any::Any.
+downcast!(dyn Any);
+downcast!((dyn Any + Send));
+downcast!((dyn Any + Sync));
+#[cfg(feature = "std")]
+downcast_sync!(dyn AnySync);
+
diff --git a/tests/tests.rs b/tests/tests.rs
new file mode 100644
index 0000000..39a0746
--- /dev/null
+++ b/tests/tests.rs
@@ -0,0 +1,78 @@
+extern crate downcast;
+use downcast::{downcast, downcast_sync, Any, AnySync};
+use std::sync::Arc;
+
+trait Simple: Any {}
+downcast!(dyn Simple);
+
+trait WithParams<T, U>: Any {}
+downcast!(<T, U> dyn WithParams<T, U>);
+struct Param1;
+struct Param2;
+
+struct ImplA {
+ data: String
+}
+impl Simple for ImplA {}
+impl WithParams<Param1, Param2> for ImplA {}
+
+struct ImplB;
+impl Simple for ImplB {}
+impl WithParams<Param1, Param2> for ImplB {}
+
+#[test]
+fn simple(){
+ let mut a: Box<dyn Simple> = Box::new(ImplA{ data: "data".into() });
+
+ assert_eq!(a.downcast_ref::<ImplA>().unwrap().data, "data");
+ assert!(a.downcast_ref::<ImplB>().is_err());
+
+ assert_eq!(a.downcast_mut::<ImplA>().unwrap().data, "data");
+ assert!(a.downcast_mut::<ImplB>().is_err());
+
+ assert_eq!(a.downcast::<ImplA>().unwrap().data, "data");
+}
+
+#[test]
+fn with_params(){
+ let mut a: Box<dyn WithParams<Param1, Param2>> = Box::new(ImplA{ data: "data".into() });
+
+ assert_eq!(a.downcast_ref::<ImplA>().unwrap().data, "data");
+ assert!(a.downcast_ref::<ImplB>().is_err());
+
+ assert_eq!(a.downcast_mut::<ImplA>().unwrap().data, "data");
+ assert!(a.downcast_mut::<ImplB>().is_err());
+
+ assert_eq!(a.downcast::<ImplA>().unwrap().data, "data");
+}
+
+trait SimpleSync: AnySync {}
+downcast_sync!(dyn SimpleSync);
+
+impl SimpleSync for ImplA {}
+impl SimpleSync for ImplB {}
+
+#[test]
+fn simple_sync(){
+ let a: Arc<dyn SimpleSync> = Arc::new(ImplA{ data: "data".into() });
+
+ assert_eq!(a.downcast_ref::<ImplA>().unwrap().data, "data");
+ assert!(a.downcast_ref::<ImplB>().is_err());
+
+ assert_eq!(a.downcast_arc::<ImplA>().unwrap().data, "data");
+}
+
+trait WithParamsSync<T, U>: AnySync {}
+downcast_sync!(<T, U> dyn WithParamsSync<T, U>);
+impl WithParamsSync<Param1, Param2> for ImplA {}
+impl WithParamsSync<Param1, Param2> for ImplB {}
+
+#[test]
+fn with_params_sync() {
+ let a: Arc<dyn WithParamsSync<Param1, Param2>> = Arc::new(ImplA{ data: "data".into() });
+
+ assert_eq!(a.downcast_ref::<ImplA>().unwrap().data, "data");
+ assert!(a.downcast_ref::<ImplB>().is_err());
+
+ assert_eq!(a.downcast_arc::<ImplA>().unwrap().data, "data");
+}