allocator_fallback/lib.rs
1/*
2 * Copyright 2022, 2026 taylor.fish <contact@taylor.fish>
3 *
4 * This file is part of allocator-fallback.
5 *
6 * allocator-fallback is licensed under the Apache License, Version 2.0
7 * (the "License"); you may not use allocator-fallback except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#![cfg_attr(not(any(feature = "std", doc)), no_std)]
20#![cfg_attr(has_allocator_api, feature(allocator_api))]
21#![deny(unsafe_op_in_unsafe_fn)]
22#![allow(clippy::needless_doctest_main)]
23
24//! This crate provides a minimal fallback for the standard library’s allocator
25//! API, which is currently unstable.
26//!
27//! Usage
28//! -----
29//!
30//! Because allocator-fallback can be configured to re-export the real
31//! unstable allocator API via the [`allocator_api` crate feature][features],
32//! your crate must conditionally enable `#![feature(allocator_api)]` in
33//! preparation for this occurrence; otherwise, compilation errors may occur.
34//! This is true even if your crate never directly enables the `allocator_api`
35//! feature, because a different crate that also depends on allocator-fallback
36//! could enable it.
37//!
38//! [features]: #crate-features
39//!
40//! To accomplish this, in `Cargo.toml`, add allocator-fallback as both a
41//! regular dependency and a build dependency:
42//!
43//! ```toml
44//! [dependencies]
45//! allocator-fallback = "0.1.10"
46//!
47//! [build-dependencies]
48//! allocator-fallback = "0.1.10"
49//! ```
50//!
51//! **Note:** It is very important that the two dependencies are identical. Do
52//! not enable a feature in one without enabling it in the other.
53//!
54//! Then add a [build script][build] (`build.rs`) with the following
55//! contents:[^1]
56//!
57//! [build]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
58//!
59//! ```rust
60//! fn main() {
61//! if allocator_fallback::HAS_ALLOCATOR_API {
62//! println!("cargo:rustc-cfg=has_allocator_api");
63//! }
64//! println!("cargo:rerun-if-changed=build.rs");
65//! }
66//! ```
67//!
68//! Finally, at the top of your crate root (likely `lib.rs` or `main.rs`), add
69//! the following:
70//!
71//! ```rust
72//! #![cfg_attr(has_allocator_api, feature(allocator_api))]
73//! ```
74//!
75//! Rust may show a warning about an “unexpected `cfg` condition name”; you can
76//! silence it by adding the following to Cargo.toml:
77//!
78//! ```toml
79//! [lints.rust.unexpected_cfgs]
80//! level = "warn"
81//! check-cfg = ["cfg(has_allocator_api)"]
82//! ```
83//!
84//! ### Use as an optional dependency
85//!
86//! If you’d like allocator-fallback to be an optional dependency, first add
87//! `optional = true` to both of its declarations as a dependency:
88//!
89//! ```toml
90//! [dependencies.allocator-fallback]
91//! version = "0.1.10"
92//! optional = true
93//!
94//! [build-dependencies.allocator-fallback]
95//! version = "0.1.10"
96//! optional = true
97//! ```
98//!
99//! Then adjust `build.rs` as follows:[^1]
100//!
101//! ```rust
102//! fn main() {
103//! #[cfg(feature = "allocator-fallback")]
104//! if allocator_fallback::HAS_ALLOCATOR_API {
105//! println!("cargo:rustc-cfg=has_allocator_api");
106//! }
107//! println!("cargo:rerun-if-changed=build.rs");
108//! }
109//! ```
110//!
111//! Finally, make sure you still have the following in your crate root:
112//!
113//! ```rust
114//! #![cfg_attr(has_allocator_api, feature(allocator_api))]
115//! ```
116//!
117//! [^1]: These build script code snippets have been released to the public
118//! domain using the [CC0 1.0 Universal Public Domain Dedication][CC0].
119//!
120//! [CC0]: https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt
121//!
122//! ### Exposing an `allocator_api` feature in your crate
123//!
124//! If you want your crate to directly provide an `allocator_api` feature that
125//! enables the real allocator API, add the following to your Cargo.toml:
126//!
127//! ```toml
128//! [features]
129//! allocator_api = ["allocator-fallback/allocator_api"]
130//! ```
131//!
132//! If you declared allocator-fallback as an optional dependency, add the
133//! following instead:
134//!
135//! ```toml
136//! [features]
137//! allocator_api = ["allocator-fallback?/allocator_api"]
138//! ```
139//!
140//! Crate features
141//! --------------
142//!
143//! If the crate feature `allocator_api` is enabled, this crate will simply
144//! re-export the real allocator API in the standard library. Of course, this
145//! requires Rust nightly.
146//!
147//! If the crate feature `std` is enabled (the default), the crate will use
148//! [`std`]; otherwise, it will be `no_std`. Using [`std`] allows
149//! [`AllocError`] to implement [`std::error::Error`].
150
151extern crate alloc;
152
153#[cfg(not(has_allocator_api))]
154mod fallback;
155
156#[cfg(not(has_allocator_api))]
157pub use fallback::{AllocError, Allocator, Global};
158
159#[cfg(has_allocator_api)]
160pub use alloc::alloc::{AllocError, Allocator, Global};
161
162/// For use in build scripts. See [Usage](crate#usage).
163pub const HAS_ALLOCATOR_API: bool = cfg!(has_allocator_api);
164
165#[test]
166fn test() {
167 use alloc::alloc::Layout;
168 let _: &dyn Allocator = &Global;
169 let ptr = Global.allocate(Layout::new::<u64>()).unwrap();
170 unsafe {
171 ptr.cast::<u64>().as_ptr().write(0x123456789abcdef);
172 (&&&Global).deallocate(ptr.cast(), Layout::new::<u64>());
173 }
174}