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::*;