Skip to main content

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