downcast-0.11.0/.cargo_vcs_info.json0000644000000001110000000000100127260ustar { "git": { "sha1": "14a52c5882aff45173fd9796cde73a6037709dc6" } }downcast-0.11.0/.gitattributes000064400000000000000000000002030072674642500144430ustar 00000000000000[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4 *.rs rust *.md rust *.toml rust *.yaml rust *.json rust downcast-0.11.0/.gitignore000064400000000000000000000001440072674642500135440ustar 00000000000000# Platform .DS_Store # Editors *# *~ [._]*.sw? # Cargo Cargo.lock .cargo/ target/ # Rustfmt *.bk downcast-0.11.0/Cargo.lock0000644000000002310000000000100107040ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "downcast" version = "0.11.0" downcast-0.11.0/Cargo.toml0000644000000016100000000000100107310ustar # 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 "] 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 = [] downcast-0.11.0/Cargo.toml.orig000064400000000000000000000006660072674642500144540ustar 00000000000000[package] name = "downcast" version = "0.11.0" authors = ["Felix Köpge "] license = "MIT" edition = "2018" description = "Trait for downcasting trait objects back to their original types." documentation = "https://docs.rs/downcast" repository = "https://github.com/fkoep/downcast-rs" readme = "README.md" keywords = ["any"] categories = ["no-std", "rust-patterns"] [features] default = ["std"] std = [] nightly = [] downcast-0.11.0/LICENSE-MIT000064400000000000000000000020630072674642500132120ustar 00000000000000MIT 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. downcast-0.11.0/README.md000064400000000000000000000033650072674642500130430ustar 00000000000000# downcast   ![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! downcast-0.11.0/clippy.toml000064400000000000000000000000270072674642500137510ustar 00000000000000blacklisted-names = [] downcast-0.11.0/examples/simple.rs000064400000000000000000000013030072674642500152270ustar 00000000000000extern 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 = Box::new(Bird); animal.what_am_i(); { let bird = animal.downcast_ref::().unwrap(); bird.wash_beak(); } let bird: Box = animal.downcast::().ok().unwrap(); bird.wash_beak(); } downcast-0.11.0/examples/sync_service.rs000064400000000000000000000015030072674642500164340ustar 00000000000000extern 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 = Arc::new(Database{}); service.what_am_i(); { let db = service.downcast_ref::().unwrap(); db.purge_data(); } let db: Arc = service.downcast_arc::().ok().unwrap(); db.purge_data(); } downcast-0.11.0/examples/with_params.rs000064400000000000000000000024570072674642500162670ustar 00000000000000extern crate downcast; use downcast::{downcast, Any}; use std::fmt::Debug; /* Trait */ trait Animal: Any { fn what_am_i(&self); fn get_item(&self) -> Option<&X>; } downcast!( dyn Animal where X: Debug); /* Impl */ struct Bird{ item: Option } impl Animal for Bird { 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 Bird { 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> = Box::new(Bird{ item: Some("haselnut".to_owned()) }); animal.what_am_i(); { let bird = animal.downcast_mut::>().unwrap(); bird.get_item(); bird.eat_item(); } let mut bird = animal.downcast::>().ok().unwrap(); bird.get_item(); bird.eat_item(); } downcast-0.11.0/src/lib.rs000064400000000000000000000306750072674642500134730ustar 00000000000000#![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) -> Box; #[doc(hidden)] #[cfg(feature = "std")] fn into_any_rc(self: Rc) -> Rc; fn type_name(&self) -> &'static str; } impl 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) -> Box { self } #[cfg(feature = "std")] fn into_any_rc(self: Rc) -> Rc { self } fn type_name(&self) -> &'static str { type_name::() } } #[cfg(feature = "std")] pub trait AnySync: Any + Send + Sync { fn into_any_arc(self: Arc) -> Arc; } #[cfg(feature = "std")] impl AnySync for T where T: Any + Send + Sync { fn into_any_arc(self: Arc) -> Arc { self } } // ++++++++++++++++++++ TypeMismatch ++++++++++++++++++++ #[derive(Debug, Clone, Copy)] pub struct TypeMismatch { pub expected: &'static str, pub found: &'static str, } impl TypeMismatch { pub fn new(found_obj: &O) -> Self where T: Any + ?Sized, O: Any + ?Sized { TypeMismatch { expected: type_name::(), 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 { mismatch: TypeMismatch, object: O, } impl DowncastError { 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 Debug for DowncastError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("DowncastError") .field("mismatch", &self.mismatch) .finish() } } impl Display for DowncastError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { Display::fmt(&self.mismatch, fmt) } } #[cfg(feature = "std")] impl Error for DowncastError {} // ++++++++++++++++++++ Downcast ++++++++++++++++++++ pub trait Downcast: Any where T: Any { fn is_type(&self) -> bool { self.type_id() == TypeId::of::() } fn downcast_ref(&self) -> Result<&T, TypeMismatch> { if self.is_type() { Ok(self.as_any().downcast_ref().unwrap()) } else { Err(TypeMismatch::new::(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::(self)) } } #[cfg(feature = "std")] fn downcast(self: Box) -> Result, DowncastError>> { if self.is_type() { Ok(self.into_any().downcast().unwrap()) } else { let mismatch = TypeMismatch::new::(&*self); Err(DowncastError::new(mismatch, self)) } } #[cfg(feature = "std")] fn downcast_rc(self: Rc) -> Result, DowncastError>> { if self.is_type() { Ok(self.into_any_rc().downcast().unwrap()) } else { let mismatch = TypeMismatch::new::(&*self); Err(DowncastError::new(mismatch, self)) } } } #[cfg(feature = "std")] pub trait DowncastSync: Downcast + AnySync where T: AnySync { fn downcast_arc(self: Arc) -> Result, DowncastError>> { if self.is_type() { Ok(self.into_any_arc().downcast().unwrap()) } else { let mismatch = TypeMismatch::new::(&*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!( Foo where B: Bar); /// impl_downcast!( Foo); /// ``` /// /// expands to /// /// ```ignore /// impl Downcast for Foo /// where T: Any /// {} /// /// impl Downcast for Foo /// where T: Any, B: Bar /// {} /// /// impl Downcast for Foo /// 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) -> $crate::_std::result::Result<$crate::_std::boxed::Box<_T>, $crate::DowncastError<$crate::_std::boxed::Box>> 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) -> $crate::_std::result::Result<$crate::_std::rc::Rc<_T>, $crate::DowncastError<$crate::_std::rc::Rc>> 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) -> $crate::_std::result::Result<$crate::_std::sync::Arc<_T>, $crate::DowncastError<$crate::_std::sync::Arc>> 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!( Foo where B: Bar); /// downcast_methods!( Foo); /// ``` /// /// ```ignore /// impl dyn Foo { /// /* impl dyn Foo where B: Bar { */ /// /* impl dyn Foo { */ /// /// pub fn is(&self) -> bool /// where T: Any, Self: Downcast /// { ... } /// /// pub fn downcast_ref(&self) -> Result<&T, TypeMismatch> /// where T: Any, Self: Downcast /// { ... } /// /// pub fn downcast_mut(&mut self) -> Result<&mut T, TypeMismatch> /// where T: Any, Self: Downcast /// { ... } /// } /// ``` #[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!( Foo where B: Bar); /// downcast_methods!( Foo); /// ``` /// /// ```ignore /// impl dyn Foo { /// /* impl dyn Foo where B: Bar { */ /// /* impl dyn Foo { */ /// /// pub fn is(&self) -> bool /// where T: Any, Self: Downcast /// { ... } /// /// pub fn downcast_ref(&self) -> Result<&T, TypeMismatch> /// where T: Any, Self: Downcast /// { ... } /// /// pub fn downcast_mut(&mut self) -> Result<&mut T, TypeMismatch> /// where T: Any, Self: Downcast /// { ... } /// /// pub fn downcast(self: Box) -> Result, DowncastError>> /// where T: Any, Self: Downcast /// { ... } /// } /// ``` #[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); downcast-0.11.0/tests/tests.rs000064400000000000000000000041320072674642500144270ustar 00000000000000extern crate downcast; use downcast::{downcast, downcast_sync, Any, AnySync}; use std::sync::Arc; trait Simple: Any {} downcast!(dyn Simple); trait WithParams: Any {} downcast!( dyn WithParams); struct Param1; struct Param2; struct ImplA { data: String } impl Simple for ImplA {} impl WithParams for ImplA {} struct ImplB; impl Simple for ImplB {} impl WithParams for ImplB {} #[test] fn simple(){ let mut a: Box = Box::new(ImplA{ data: "data".into() }); assert_eq!(a.downcast_ref::().unwrap().data, "data"); assert!(a.downcast_ref::().is_err()); assert_eq!(a.downcast_mut::().unwrap().data, "data"); assert!(a.downcast_mut::().is_err()); assert_eq!(a.downcast::().unwrap().data, "data"); } #[test] fn with_params(){ let mut a: Box> = Box::new(ImplA{ data: "data".into() }); assert_eq!(a.downcast_ref::().unwrap().data, "data"); assert!(a.downcast_ref::().is_err()); assert_eq!(a.downcast_mut::().unwrap().data, "data"); assert!(a.downcast_mut::().is_err()); assert_eq!(a.downcast::().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 = Arc::new(ImplA{ data: "data".into() }); assert_eq!(a.downcast_ref::().unwrap().data, "data"); assert!(a.downcast_ref::().is_err()); assert_eq!(a.downcast_arc::().unwrap().data, "data"); } trait WithParamsSync: AnySync {} downcast_sync!( dyn WithParamsSync); impl WithParamsSync for ImplA {} impl WithParamsSync for ImplB {} #[test] fn with_params_sync() { let a: Arc> = Arc::new(ImplA{ data: "data".into() }); assert_eq!(a.downcast_ref::().unwrap().data, "data"); assert!(a.downcast_ref::().is_err()); assert_eq!(a.downcast_arc::().unwrap().data, "data"); }