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
//! # `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)]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(feature = "futures", feature(futures_api))]

/// 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
/// #![cfg_attr(not(feature = "std"), no_std)]
/// #![cfg_attr(feature = "alloc", feature(alloc))]
/// #![cfg_attr(feature = "futures", feature(futures_api))]
///
/// // 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.
/// crate::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)]
        #[macro_use]
        #[cfg($alloc)]
        extern crate alloc as alloc_crate;

        #[cfg(any($alloc, $std))]
        mod alloc {
            #[cfg(all(not($std), $alloc))]
            pub use alloc_crate::*;

            #[cfg(all($std, not($alloc)))]
            pub use std::{
                alloc, borrow, boxed, collections, fmt, prelude::v1 as 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::*;