summary refs log blame commit diff stats
path: root/src/lib.rs
blob: 88e5c90c4a5b996a472c64d6fc912f7ec7d2657b (plain) (tree)



































































































                                                                              
// Anycast - Any upcasting
// Copyright (C) 2022  Soni L.
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
// 
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

//! Anycast is a library for casting to `::core::any::Any`.

#![cfg_attr(not(feature="std"), no_std)]

use ::core::any::Any;

#[cfg(feature="alloc")]
extern crate alloc;

#[cfg(feature="alloc")]
use ::alloc::boxed::Box;

mod sealed {
    pub trait Sealed {
    }
}

use sealed::Sealed;

/// Trait for casting to [`::core::any::Any`].
///
/// This is useful to add to your own traits, when you want to expose `Any`
/// upcasting (and downcasting!) ability to your users, on your object-safe
/// traits.
///
/// # Examples
///
/// ```rust
/// use ::anycast::Anycast;
///
/// trait Foo: Anycast {
///     fn foo(&mut self);
/// }
///
/// impl Foo for i32 {
///     fn foo(&mut self) {
///         *self += 1;
///     }
/// }
///
/// let mut x = 10;
/// let x: &mut dyn Foo = &mut x;
/// x.foo();
/// // it's recommended to use Anycast::* due to weird implicit (de)ref.
/// assert_eq!(Anycast::any_ref(x).downcast_ref::<i32>().unwrap(), &11);
/// ```
pub trait Anycast: Any + Sealed {
    /// Casts `&Self` to `&dyn Any`.
    fn any_ref(&self) -> &dyn Any;
    /// Casts `&mut Self` to `&mut dyn Any`.
    fn any_mut(&mut self) -> &mut dyn Any;
    #[cfg(feature="alloc")]
    /// Casts `Box<Self>` to `Box<dyn Any>`.
    fn into_any(self: Box<Self>) -> Box<dyn Any>;
}

impl<T> Sealed for T where T: Any {
}
impl<T> Anycast for T where T: Any {
    fn any_ref(&self) -> &dyn Any {
        self
    }
    fn any_mut(&mut self) -> &mut dyn Any {
        self
    }
    #[cfg(feature="alloc")]
    fn into_any(self: Box<Self>) -> Box<dyn Any> {
        self
    }
}

#[cfg(test)]
mod test {
    use super::Anycast;

    #[test]
    fn test_anycast() {
        let string = "foo";
        let anycast: &dyn Anycast = &string;
        let any = anycast.any_ref();
        let string_ref = any.downcast_ref::<&'static str>().unwrap();
        assert!(::core::ptr::eq(string, *string_ref));
    }
}