diff --git a/Cargo.toml b/Cargo.toml index bf22563..a4a9f21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,8 @@ keywords = ["trait", "cast", "any"] include = ["src/**/*", "Cargo.toml", "LICENSE-*", "README.md"] [dependencies] -once_cell = "1.4" +hashbrown = { version = "0.17", default-features = false } +spin = { version = "0.10", default-features = false, features = ["lazy"] } linkme = "0.2" intertrait-macros = { version = "=0.2.2", path = "macros" } diff --git a/README.md b/README.md index f304f44..2a1da61 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,9 @@ This library provides direct casting among trait objects implemented by a type. +`intertrait` supports both `std` and `no_std + alloc` environments. The runtime crate itself is +`#![no_std]`, but it requires `alloc` because it uses `Box`, `Rc`, `Arc`, and a heap-backed registry. + In Rust, a trait object for a sub-trait of [`std::any::Any`] can be downcast to a concrete type at runtime if the type is known. But no direct casting between two trait objects (i.e. without involving the concrete type of the backing value) is possible (even no coercion from a trait object for a trait to that for its super-trait yet). @@ -25,6 +28,27 @@ linkme = "0.2" The `linkme` dependency is required due to the use of `linkme` macro in the output of `intertrait` macros. +## `no_std` Support +`intertrait` can be used in `no_std` targets as long as `alloc` is available. No feature toggle is needed. + +This means: + +* `intertrait` works directly in `std` environments. +* `intertrait` also works in `no_std` environments with `extern crate alloc`. +* This is not a pure-`core` crate, because casting support relies on allocation-backed types such as `Box`, + `Rc`, and `Arc`. + +Minimal `no_std` usage looks like this: + +```rust,ignore +#![no_std] + +extern crate alloc; + +use intertrait::*; +use intertrait::cast::*; +``` + # Usage ```rust @@ -116,7 +140,7 @@ fn main() {} ``` ## `Arc` Support -`std::sync::Arc` is unique in that it implements `downcast` method only on `dyn Any + Send + Sync + 'static'. +`Arc` is unique in that it implements `downcast` method only on `dyn Any + Send + Sync + 'static`. To use with `Arc`, the following steps should be taken: * Mark source traits with [`CastFromSync`] instead of [`CastFrom`] @@ -164,4 +188,4 @@ dual licensed as above, without any additional terms or conditions. [`std::any::Any`]: https://doc.rust-lang.org/std/any/trait.Any.html [`TypeId`]: https://doc.rust-lang.org/std/any/struct.TypeId.html [`CastFrom`]: https://docs.rs/intertrait/*/intertrait/trait.CastFrom.html -[`CastFromSync`]: https://docs.rs/intertrait/*/intertrait/trait.CastFromSync.html \ No newline at end of file +[`CastFromSync`]: https://docs.rs/intertrait/*/intertrait/trait.CastFromSync.html diff --git a/macros/src/gen_caster.rs b/macros/src/gen_caster.rs index 7ef02ff..651696d 100644 --- a/macros/src/gen_caster.rs +++ b/macros/src/gen_caster.rs @@ -33,9 +33,9 @@ pub fn generate_caster(ty: &impl ToTokens, trait_: &impl ToTokens, sync: bool) - }; quote! { - #[::linkme::distributed_slice(::intertrait::CASTERS)] - fn #fn_ident() -> (::std::any::TypeId, ::intertrait::BoxedCaster) { - (::std::any::TypeId::of::<#ty>(), Box::new(#new_caster)) + #[::intertrait::__private::linkme::distributed_slice(::intertrait::CASTERS)] + fn #fn_ident() -> (::core::any::TypeId, ::intertrait::BoxedCaster) { + (::core::any::TypeId::of::<#ty>(), ::intertrait::__private::Box::new(#new_caster)) } } } diff --git a/src/cast/cast_arc.rs b/src/cast/cast_arc.rs index ab26e2d..4c27912 100644 --- a/src/cast/cast_arc.rs +++ b/src/cast/cast_arc.rs @@ -1,5 +1,6 @@ +use alloc::sync::Arc; + use crate::{caster, CastFromSync}; -use std::sync::Arc; /// A trait that is blanket-implemented for traits extending `CastFrom` to allow for casting /// of a trait object for it behind an `Rc` to a trait object for another trait diff --git a/src/cast/cast_box.rs b/src/cast/cast_box.rs index 953d600..1cc16f6 100644 --- a/src/cast/cast_box.rs +++ b/src/cast/cast_box.rs @@ -1,3 +1,5 @@ +use alloc::boxed::Box; + use crate::{caster, CastFrom}; /// A trait that is blanket-implemented for traits extending `CastFrom` to allow for casting diff --git a/src/cast/cast_rc.rs b/src/cast/cast_rc.rs index 161aa05..e3ca456 100644 --- a/src/cast/cast_rc.rs +++ b/src/cast/cast_rc.rs @@ -1,5 +1,6 @@ +use alloc::rc::Rc; + use crate::{caster, CastFrom}; -use std::rc::Rc; /// A trait that is blanket-implemented for traits extending `CastFrom` to allow for casting /// of a trait object for it behind an `Rc` to a trait object for another trait diff --git a/src/cast/cast_ref.rs b/src/cast/cast_ref.rs index 1b47d4e..210febe 100644 --- a/src/cast/cast_ref.rs +++ b/src/cast/cast_ref.rs @@ -1,4 +1,4 @@ -use std::any::TypeId; +use core::any::TypeId; use crate::{caster, CastFrom, Caster, CASTER_MAP}; diff --git a/src/hasher.rs b/src/hasher.rs index ed67553..ac54c64 100644 --- a/src/hasher.rs +++ b/src/hasher.rs @@ -1,6 +1,6 @@ -use std::convert::TryInto; -use std::hash::{BuildHasherDefault, Hasher}; -use std::mem::size_of; +use core::convert::TryInto; +use core::hash::{BuildHasherDefault, Hasher}; +use core::mem::size_of; /// A simple `Hasher` implementation tuned for performance. #[derive(Default)] diff --git a/src/lib.rs b/src/lib.rs index 932608c..30b0aa5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![no_std] //! A library providing direct casting among trait objects implemented by a type. //! //! In Rust, an object of a sub-trait of [`Any`] can be downcast to a concrete type @@ -54,15 +55,18 @@ //! [`CastFrom`]: ./trait.CastFrom.html //! [`CastFromSync`]: ./trait.CastFromSync.html //! [`cast`]: ./cast/index.html -//! [`Any`]: https://doc.rust-lang.org/std/any/trait.Any.html -//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html -use std::any::{Any, TypeId}; -use std::collections::HashMap; -use std::rc::Rc; -use std::sync::Arc; +//! [`Any`]: https://doc.rust-lang.org/core/any/trait.Any.html +//! [`Arc`]: https://doc.rust-lang.org/alloc/sync/struct.Arc.html +extern crate alloc; +use alloc::boxed::Box; +use alloc::rc::Rc; +use alloc::sync::Arc; +use core::any::{Any, TypeId}; + +use hashbrown::HashMap; use linkme::distributed_slice; -use once_cell::sync::Lazy; +use spin::Lazy; pub use intertrait_macros::*; @@ -74,6 +78,12 @@ mod hasher; #[doc(hidden)] pub type BoxedCaster = Box; +#[doc(hidden)] +pub mod __private { + pub use alloc::boxed::Box; + pub use linkme; +} + #[cfg(doctest)] doc_comment::doctest!("../README.md"); @@ -282,6 +292,9 @@ impl CastFromSync for dyn Any + Sync + Send + 'static { } } +#[cfg(test)] +extern crate std; + #[cfg(test)] mod tests { use std::any::{Any, TypeId};