unsafe-any-ors-1.0.0/.cargo_vcs_info.json0000644000000001360000000000100137010ustar { "git": { "sha1": "13db2671e7bf0e3ecc519cc1b33941a473e80ce7" }, "path_in_vcs": "" }unsafe-any-ors-1.0.0/.github/workflows/general.yaml000075500000000000000000000023040072674642500204210ustar 00000000000000name: CI on: pull_request: push: schedule: - cron: '0 0 * * 0' # 00:00 Sunday env: CARGO_TERM_COLOR: always jobs: test: name: Test runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - uses: actions-rs/cargo@v1 with: command: test args: -- --test-threads=1 fmt: name: Rustfmt runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable override: true components: rustfmt - uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check clippy: name: Clippy runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable override: true components: clippy - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} args: -- -D warnings unsafe-any-ors-1.0.0/.gitignore000075500000000000000000000002070072674642500145130ustar 00000000000000.DS_Store *~ *# *.o *.so *.swp *.dylib *.dSYM *.dll *.rlib *.dummy *.exe *-test /doc/ /target/ /examples/* !/examples/*.rs Cargo.lock unsafe-any-ors-1.0.0/Cargo.toml0000644000000014570000000000100117060ustar # 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] name = "unsafe-any-ors" version = "1.0.0" authors = ["Jonathan Reem ", "anton whalley anton@venshare.com"] description = "Traits and implementations for unchecked downcasting." license = "MIT" repository = "https://github.com/orphanage-rs/rust-unsafe-any" [dependencies.destructure_traitobject] version = "0.2.0" unsafe-any-ors-1.0.0/Cargo.toml.orig000075500000000000000000000005260072674642500154160ustar 00000000000000[package] name = "unsafe-any-ors" version = "1.0.0" authors = ["Jonathan Reem ", "anton whalley anton@venshare.com"] description = "Traits and implementations for unchecked downcasting." repository = "https://github.com/orphanage-rs/rust-unsafe-any" license = "MIT" [dependencies] destructure_traitobject = "0.2.0" unsafe-any-ors-1.0.0/README.md000075500000000000000000000014230072674642500140030ustar 00000000000000# unsafe-any-ors [![CI](https://github.com/orphanage-rs/rust-unsafe-any/actions/workflows/general.yaml/badge.svg)](https://github.com/orphanage-rs/rust-unsafe-any/actions/workflows/general.yaml) > Convenience traits for unsafe downcasting from trait objects to concrete types. ## Overview This crate defines two new traits `UncheckedAnyDowncast` and `UncheckedAnyMutDowncast`, which define methods for downcasting to any type that implements `Any` from implemented trait objects. It also defines two convenience implementations of these traits for `&'a Any` and `&'a mut Any`, which are the most common trait objects that you might downcast from. ## Example: ```rust let a = box 7u as Box; unsafe { assert_eq!(*a.downcast_ref_unchecked::(), 7u); } ``` ## License MIT unsafe-any-ors-1.0.0/src/lib.rs000075500000000000000000000127120072674642500144320ustar 00000000000000#![deny(missing_docs, warnings)] //! Traits for unsafe downcasting from trait objects to & or &mut references of //! concrete types. These should only be used if you are absolutely certain of the //! type of the data in said trait object - there be dragons etc. //! //! Originally inspired by https://github.com/chris-morgan/anymap //! and the implementation of `std::any::Any`. extern crate destructure_traitobject; use std::any::Any; use std::mem; /// A trait providing unchecked downcasting to its contents when stored /// in a trait object. pub trait UnsafeAny: Any {} impl UnsafeAny for T {} impl dyn UnsafeAny { /// Returns a reference to the contained value, assuming that it is of type `T`. /// /// # Safety /// /// If you are not _absolutely certain_ of `T` you should _not_ call this! pub unsafe fn downcast_ref_unchecked(&self) -> &T { &*(destructure_traitobject::data(self) as *const T) } /// Returns a mutable reference to the contained value, assuming that it is of type `T`. /// /// # Safety /// /// If you are not _absolutely certain_ of `T` you should _not_ call this! pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { &mut *(destructure_traitobject::data_mut(self) as *mut T) } /// Returns a the contained value, assuming that it is of type `T`. /// /// # Safety /// /// If you are not _absolutely certain_ of `T` you should _not_ call this! pub unsafe fn downcast_unchecked(self: Box) -> Box { let raw: *mut dyn UnsafeAny = mem::transmute(self); mem::transmute(destructure_traitobject::data_mut(raw)) } } /// An extension trait for unchecked downcasting of trait objects. /// # Safety /// /// See specific funtion calls for areas to be aware of. pub unsafe trait UnsafeAnyExt { /// Returns a reference to the contained value, assuming that it is of type `T`. /// /// # Safety /// /// If you are not _absolutely certain_ of `T` you should _not_ call this! unsafe fn downcast_ref_unchecked(&self) -> &T { &*(destructure_traitobject::data(self) as *const T) } /// Returns a mutable reference to the contained value, assuming that it is of type `T`. /// /// # Safety /// /// If you are not _absolutely certain_ of `T` you should _not_ call this! unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { &mut *(destructure_traitobject::data_mut(self) as *mut T) } /// Returns a the contained value, assuming that it is of type `T`. /// /// # Safety /// /// If you are not _absolutely certain_ of `T` you should _not_ call this! unsafe fn downcast_unchecked(self: Box) -> Box { let raw: *mut Self = mem::transmute(self); mem::transmute(destructure_traitobject::data_mut(raw)) } } unsafe impl UnsafeAnyExt for dyn Any {} unsafe impl UnsafeAnyExt for dyn UnsafeAny {} unsafe impl UnsafeAnyExt for dyn Any + Send {} unsafe impl UnsafeAnyExt for dyn Any + Sync {} unsafe impl UnsafeAnyExt for dyn Any + Send + Sync {} unsafe impl UnsafeAnyExt for dyn UnsafeAny + Send {} unsafe impl UnsafeAnyExt for dyn UnsafeAny + Sync {} unsafe impl UnsafeAnyExt for dyn UnsafeAny + Send + Sync {} #[cfg(test)] mod test { use super::{UnsafeAny, UnsafeAnyExt}; use std::any::Any; #[allow(unstable_name_collisions)] #[test] fn test_simple_downcast_ext() { let a = Box::new(7usize) as Box; unsafe { assert_eq!(*a.downcast_ref_unchecked::(), 7); } let mut a = Box::new(7usize) as Box; unsafe { assert_eq!(*a.downcast_mut_unchecked::(), 7); } let mut a = Box::new(7usize) as Box; unsafe { *a.downcast_mut_unchecked::() = 8; assert_eq!(*a.downcast_mut_unchecked::(), 8); } } #[allow(unstable_name_collisions)] #[test] fn test_simple_downcast_inherent() { let a = Box::new(7usize) as Box; unsafe { assert_eq!(*a.downcast_ref_unchecked::(), 7); } let mut a = Box::new(7usize) as Box; unsafe { assert_eq!(*a.downcast_mut_unchecked::(), 7); } let mut a = Box::new(7usize) as Box; unsafe { *a.downcast_mut_unchecked::() = 8; assert_eq!(*a.downcast_mut_unchecked::(), 8); } } #[allow(unstable_name_collisions)] #[test] fn test_box_downcast_no_double_free() { use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; struct Dropper { x: Arc, } impl Drop for Dropper { fn drop(&mut self) { self.x.fetch_add(1, Ordering::SeqCst); } } let x = Arc::new(AtomicUsize::new(0)); let a = Box::new(Dropper { x: x.clone() }) as Box; let dropper = unsafe { a.downcast_unchecked::() }; drop(dropper); assert_eq!(x.load(Ordering::SeqCst), 1); // Test the UnsafeAnyExt implementation. let x = Arc::new(AtomicUsize::new(0)); let a = Box::new(Dropper { x: x.clone() }) as Box; let dropper = unsafe { a.downcast_unchecked::() }; drop(dropper); assert_eq!(x.load(Ordering::SeqCst), 1); } }