1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! # `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::*;