alloc-facade 0.5.0

Facade for std-or-alloc imports
Documentation
//! # `alloc-facade`: std-or-alloc API Facade
//!
//! The `alloc` crate is often used in crates that are *almost*
//! `no_std`-compatible and only need allocation capabilities to do their thing.
//! The problem one usually faces when developing one of these "maybe std, maybe
//! alloc" crates is that for the `std` variant, everything is available either
//! in the prelude or at `std::` paths, while in `alloc`-only situations, the
//! prelude must be imported manually and everything lives under `alloc::` paths.
//!
//! To work around this, one could simply have `#[cfg(...)]` conditionals over
//! all of the imports as needed, but this quickly gets ugly and unwieldy. A
//! better approach is to use a facade which re-exports the api from either `std`
//! or `alloc`, whichever happens to be in use at the time.
//!
//! This crate provides such a facade. Simply make sure that one of either its
//! `std` or `alloc` features is enabled and it provides the same importable API
//! structure for either case. Optionally, the `futures` feature can also be
//! enabled to provide the `task` module.
//!
//! ### The `setup_imports` macro
//!
//! Rather than use this facade crate directly, one could also use the
//! [`setup_imports`] macro which will generate a similar facade in your own crate.
//! This is useful if the conditions for enabling `no_std` and `alloc` are more
//! complicated than a simple feature flag. See its documentation for more details.

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

/// Create the `alloc` api facade
///
/// This will add the `extern crate` declaration for the alloc crate and
/// set up the facade module at `crate::alloc`. It should contain an identical API
/// surface for both `std` and `alloc` uses.
///
/// # Example
///
/// ```rust,ignore
/// #![cfg_attr(not(feature = "std"), no_std)]
///
/// // Each of std, alloc, and futures should be followed by a "meta" item.
/// // This will be used for the proper #[cfg(...)] attributes.
/// // They can be in any order. futures is optional, and will default to
/// // "always disabled". You can use "all()" for "always enabled" on any of them.
/// alloc::setup_imports! {
///     std: feature = "std",
///     alloc: feature = "alloc",
///     futures: feature = "futures",
/// }
/// ```
#[macro_export]
macro_rules! setup_imports {
    (@reordered $std:meta, $alloc:meta, $futures:meta ) => {
        #[allow(unused_imports)]
        #[cfg($alloc)]
        pub extern crate alloc as alloc_crate;

        #[cfg(any($alloc, $std))]
        mod alloc {
            #[cfg(all(not($std), $alloc))]
            /// Copy of the unstable alloc prelude
            pub mod prelude {
                pub mod v1 {
                    pub use super::super::borrow::ToOwned;
                    pub use super::super::boxed::Box;
                    pub use super::super::string::String;
                    pub use super::super::string::ToString;
                    pub use super::super::vec::Vec;
                }
            }

            #[cfg(all(not($std), $alloc))]
            pub use alloc_crate::{
                alloc, borrow, boxed, collections, fmt, rc, slice, str,
                string, sync, vec, format
            };

            #[cfg(all($std, not($alloc)))]
            pub use std::{
                alloc, borrow, boxed, collections, fmt, prelude, rc, slice, str,
                string, vec, format,
            };
            #[cfg(all($std, not($alloc)))]
            pub mod sync {
                //! Thread-safe reference-counting pointers
                pub use std::sync::{Arc, Weak};
            }
            #[cfg(all($std, not($alloc), $futures))]
            pub use std::task;
        }
    };
    (@reorder
        ({}, $alloc:tt, $futures:tt)
        std: $std:meta,
        $( $tail:tt )*
    ) => {
        $crate::setup_imports!(@reorder ({$std}, $alloc, $futures) $($tail)*);
    };
    (@reorder
        ($std:tt, {}, $futures:tt)
        alloc: $alloc:meta,
        $( $tail:tt )*
    ) => {
        $crate::setup_imports!(@reorder ($std, {$alloc}, $futures) $($tail)*);
    };
    (@reorder
        ($std:tt, $alloc:tt, {})
        futures: $futures:meta,
        $( $tail:tt )*
    ) => {
        $crate::setup_imports!(@reorder ($std, $alloc, {$futures}) $($tail)*);
    };
    (@reorder
        ({$std:meta}, {$alloc:meta}, {$futures:meta})
    ) => {
        $crate::setup_imports!(@reordered $std, $alloc, $futures);
    };
    (@reorder
        ({$std:meta}, {$alloc:meta}, {})
    ) => {
        $crate::setup_imports!(@reordered $std, $alloc, any());
    };
    ($($featname:ident : $cond:meta),* $(,)* ) => {
        $crate::setup_imports!(@reorder ({}, {}, {}) $($featname : $cond,)*);
    };
}

crate::setup_imports! {
    std: feature = "std",
    alloc: feature = "alloc",
    futures: feature = "futures",
}

#[cfg(any(feature = "alloc", feature = "std"))]
pub use crate::alloc::*;