Skip to content

Commit aef602a

Browse files
authored
Merge pull request #106 from bluss/auto-nostd
Support building without libstd
2 parents c7d07f1 + 6bd5fb6 commit aef602a

File tree

9 files changed

+139
-6
lines changed

9 files changed

+139
-6
lines changed

.travis.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,22 @@ matrix:
2020
- rust: nightly
2121
env:
2222
- FEATURES='test_low_transition_point'
23+
- rust: 1.36.0
24+
env: TARGET=thumbv6m-none-eabi
25+
before_script:
26+
- rustup target add $TARGET
27+
- set -ex
28+
script:
29+
- cargo build -vv --target=$TARGET
30+
- cargo build -v -p test-nostd --target=$TARGET
31+
- rust: stable
32+
env: TARGET=thumbv6m-none-eabi
33+
before_script:
34+
- rustup target add $TARGET
35+
- set -ex
36+
script:
37+
- cargo build -vv --target=$TARGET
38+
- cargo build -v -p test-nostd --target=$TARGET
2339
branches:
2440
only:
2541
- master

Cargo.toml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@ This crate was initially published under the name ordermap, but it was renamed t
2121
indexmap.
2222
"""
2323

24-
keywords = ["hashmap"]
25-
categories = ["data-structures"]
24+
keywords = ["hashmap", "no_std"]
25+
categories = ["data-structures", "no-std"]
26+
27+
build = "build.rs"
2628

2729
[lib]
2830
bench = false
2931

32+
[build-dependencies]
33+
autocfg = "0.1.6"
3034
[dependencies]
3135
serde = { version = "1.0", optional = true }
3236
rayon = { version = "1.0", optional = true }
@@ -56,3 +60,6 @@ tag-name = "{{version}}"
5660

5761
[package.metadata.docs.rs]
5862
features = ["serde-1", "rayon"]
63+
64+
[workspace]
65+
members = ["test-nostd"]

build.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
extern crate autocfg;
2+
3+
fn main() {
4+
let ac = autocfg::new();
5+
ac.emit_sysroot_crate("std");
6+
autocfg::rerun_path(file!());
7+
}

src/lib.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
21
#![deny(unsafe_code)]
32
#![doc(html_root_url = "https://docs.rs/indexmap/1/")]
3+
#![cfg_attr(not(has_std), no_std)]
44

55
//! [`IndexMap`] is a hash table where the iteration order of the key-value
66
//! pairs is independent of the hash values of the keys.
@@ -12,14 +12,53 @@
1212
//! [`IndexSet`]: set/struct.IndexSet.html
1313
//!
1414
//!
15+
//!
1516
//! ## Rust Version
1617
//!
1718
//! This version of indexmap requires Rust 1.18 or later, or 1.30+ for
18-
//! development builds.
19+
//! development builds, and Rust 1.36+ for using with `alloc` (without `std`),
20+
//! see below.
1921
//!
2022
//! The indexmap 1.x release series will use a carefully considered version
2123
//! upgrade policy, where in a later 1.x version, we will raise the minimum
2224
//! required Rust version.
25+
//!
26+
//! ## No Standard Library Targets
27+
//!
28+
//! From Rust 1.36, this crate supports being built without `std`, requiring
29+
//! `alloc` instead. This is enabled automatically when it is detected that
30+
//! `std` is not available. There is no crate feature to enable/disable to
31+
//! trigger this. It can be tested by building for a std-less target.
32+
//!
33+
//! - Creating maps and sets using [`new`][IndexMap::new] and
34+
//! [`with_capacity`][IndexMap::with_capacity] is unavailable without `std`.
35+
//! Use methods [`IndexMap::default`][def],
36+
//! [`with_hasher`][IndexMap::with_hasher],
37+
//! [`with_capacity_and_hasher`][IndexMap::with_capacity_and_hasher] instead.
38+
//! A no-std compatible hasher will be needed as well, for example
39+
//! from the crate `twox-hash`.
40+
//! - Macros [`indexmap!`] and [`indexset!`] are unavailable without `std`.
41+
//!
42+
//! [def]: map/struct.IndexMap.html#impl-Default
43+
44+
#[cfg(not(has_std))]
45+
#[macro_use(vec)]
46+
extern crate alloc;
47+
48+
#[cfg(not(has_std))]
49+
pub(crate) mod std {
50+
pub use core::*;
51+
pub mod alloc {
52+
pub use ::alloc::*;
53+
}
54+
pub mod collections {
55+
pub use ::alloc::collections::*;
56+
}
57+
pub use ::alloc::vec as vec;
58+
}
59+
60+
#[cfg(not(has_std))]
61+
use std::vec::Vec;
2362

2463
#[macro_use]
2564
mod macros;

src/macros.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11

2+
#[cfg(has_std)]
23
#[macro_export(local_inner_macros)]
34
/// Create an `IndexMap` from a list of key-value pairs
45
///
@@ -37,6 +38,7 @@ macro_rules! indexmap {
3738
};
3839
}
3940

41+
#[cfg(has_std)]
4042
#[macro_export(local_inner_macros)]
4143
/// Create an `IndexSet` from a list of values
4244
///

src/map.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
//! `IndexMap` is a hash table where the iteration order of the key-value
22
//! pairs is independent of the hash values of the keys.
33
4+
#[cfg(not(has_std))]
5+
use alloc::boxed::Box;
6+
#[cfg(not(has_std))]
7+
use std::vec::Vec;
8+
49
pub use mutable_keys::MutableKeys;
510

611
#[cfg(feature = "rayon")]
@@ -10,9 +15,11 @@ use std::hash::Hash;
1015
use std::hash::BuildHasher;
1116
use std::hash::Hasher;
1217
use std::iter::FromIterator;
13-
use std::collections::hash_map::RandomState;
1418
use std::ops::RangeFull;
1519

20+
#[cfg(has_std)]
21+
use std::collections::hash_map::RandomState;
22+
1623
use std::cmp::{max, Ordering};
1724
use std::fmt;
1825
use std::mem::{replace};
@@ -264,10 +271,17 @@ impl<Sz> ShortHashProxy<Sz>
264271
/// assert_eq!(letters.get(&'y'), None);
265272
/// ```
266273
#[derive(Clone)]
274+
#[cfg(has_std)]
267275
pub struct IndexMap<K, V, S = RandomState> {
268276
core: OrderMapCore<K, V>,
269277
hash_builder: S,
270278
}
279+
#[derive(Clone)]
280+
#[cfg(not(has_std))]
281+
pub struct IndexMap<K, V, S> {
282+
core: OrderMapCore<K, V>,
283+
hash_builder: S,
284+
}
271285

272286
// core of the map that does not depend on S
273287
#[derive(Clone)]
@@ -379,6 +393,7 @@ macro_rules! probe_loop {
379393
}
380394
}
381395

396+
#[cfg(has_std)]
382397
impl<K, V> IndexMap<K, V> {
383398
/// Create a new map. (Does not allocate.)
384399
pub fn new() -> Self {

src/set.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@
33
#[cfg(feature = "rayon")]
44
pub use ::rayon::set as rayon;
55

6-
use std::cmp::Ordering;
6+
#[cfg(not(has_std))]
7+
use std::vec::Vec;
8+
9+
#[cfg(has_std)]
710
use std::collections::hash_map::RandomState;
11+
12+
use std::cmp::Ordering;
813
use std::fmt;
914
use std::iter::{FromIterator, Chain};
1015
use std::hash::{Hash, BuildHasher};
@@ -59,9 +64,15 @@ type Bucket<T> = super::Bucket<T, ()>;
5964
/// assert!(!letters.contains(&'y'));
6065
/// ```
6166
#[derive(Clone)]
67+
#[cfg(has_std)]
6268
pub struct IndexSet<T, S = RandomState> {
6369
map: IndexMap<T, (), S>,
6470
}
71+
#[cfg(not(has_std))]
72+
#[derive(Clone)]
73+
pub struct IndexSet<T, S> {
74+
map: IndexMap<T, (), S>,
75+
}
6576

6677
impl<T, S> Entries for IndexSet<T, S> {
6778
type Entry = Bucket<T>;
@@ -99,6 +110,7 @@ impl<T, S> fmt::Debug for IndexSet<T, S>
99110
}
100111
}
101112

113+
#[cfg(has_std)]
102114
impl<T> IndexSet<T> {
103115
/// Create a new set. (Does not allocate.)
104116
pub fn new() -> Self {

test-nostd/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "test-nostd"
3+
version = "0.1.0"
4+
authors = ["bluss"]
5+
publish = false
6+
edition = "2018"
7+
8+
[dependencies]
9+
indexmap = { path = ".." }
10+
# no-std compatible hasher
11+
twox-hash = { version = "1.5", default-features = false }
12+
13+
[dev-dependencies]

test-nostd/src/lib.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#![no_std]
2+
3+
use indexmap::IndexMap;
4+
use indexmap::IndexSet;
5+
use core::hash::BuildHasherDefault;
6+
use twox_hash::XxHash64;
7+
type Map<K, V> = IndexMap<K, V, BuildHasherDefault<XxHash64>>;
8+
type Set<T> = IndexSet<T, BuildHasherDefault<XxHash64>>;
9+
10+
use core::iter::FromIterator;
11+
12+
pub fn test_compile() {
13+
let mut map = Map::default();
14+
map.insert(1, 1);
15+
map.insert(2, 4);
16+
for (_, _) in map.iter() { }
17+
18+
let _map2 = Map::from_iter(Some((1, 1)));
19+
20+
let mut set = Set::default();
21+
set.insert("a");
22+
}

0 commit comments

Comments
 (0)