Skip to content

Support building without libstd #106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ matrix:
- rust: nightly
env:
- FEATURES='test_low_transition_point'
- rust: 1.36.0
env: TARGET=thumbv6m-none-eabi
before_script:
- rustup target add $TARGET
- set -ex
script:
- cargo build -vv --target=$TARGET
- cargo build -v -p test-nostd --target=$TARGET
- rust: stable
env: TARGET=thumbv6m-none-eabi
before_script:
- rustup target add $TARGET
- set -ex
script:
- cargo build -vv --target=$TARGET
- cargo build -v -p test-nostd --target=$TARGET
branches:
only:
- master
Expand Down
11 changes: 9 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@ This crate was initially published under the name ordermap, but it was renamed t
indexmap.
"""

keywords = ["hashmap"]
categories = ["data-structures"]
keywords = ["hashmap", "no_std"]
categories = ["data-structures", "no-std"]

build = "build.rs"

[lib]
bench = false

[build-dependencies]
autocfg = "0.1.6"
[dependencies]
serde = { version = "1.0", optional = true }
rayon = { version = "1.0", optional = true }
Expand Down Expand Up @@ -56,3 +60,6 @@ tag-name = "{{version}}"

[package.metadata.docs.rs]
features = ["serde-1", "rayon"]

[workspace]
members = ["test-nostd"]
7 changes: 7 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extern crate autocfg;

fn main() {
let ac = autocfg::new();
ac.emit_sysroot_crate("std");
autocfg::rerun_path(file!());
}
43 changes: 41 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

#![deny(unsafe_code)]
#![doc(html_root_url = "https://docs.rs/indexmap/1/")]
#![cfg_attr(not(has_std), no_std)]

//! [`IndexMap`] is a hash table where the iteration order of the key-value
//! pairs is independent of the hash values of the keys.
Expand All @@ -12,14 +12,53 @@
//! [`IndexSet`]: set/struct.IndexSet.html
//!
//!
//!
//! ## Rust Version
//!
//! This version of indexmap requires Rust 1.18 or later, or 1.30+ for
//! development builds.
//! development builds, and Rust 1.36+ for using with `alloc` (without `std`),
//! see below.
//!
//! The indexmap 1.x release series will use a carefully considered version
//! upgrade policy, where in a later 1.x version, we will raise the minimum
//! required Rust version.
//!
//! ## No Standard Library Targets
//!
//! From Rust 1.36, this crate supports being built without `std`, requiring
//! `alloc` instead. This is enabled automatically when it is detected that
//! `std` is not available. There is no crate feature to enable/disable to
//! trigger this. It can be tested by building for a std-less target.
//!
//! - Creating maps and sets using [`new`][IndexMap::new] and
//! [`with_capacity`][IndexMap::with_capacity] is unavailable without `std`.
//! Use methods [`IndexMap::default`][def],
//! [`with_hasher`][IndexMap::with_hasher],
//! [`with_capacity_and_hasher`][IndexMap::with_capacity_and_hasher] instead.
//! A no-std compatible hasher will be needed as well, for example
//! from the crate `twox-hash`.
//! - Macros [`indexmap!`] and [`indexset!`] are unavailable without `std`.
//!
//! [def]: map/struct.IndexMap.html#impl-Default

#[cfg(not(has_std))]
#[macro_use(vec)]
extern crate alloc;

#[cfg(not(has_std))]
pub(crate) mod std {
pub use core::*;
pub mod alloc {
pub use ::alloc::*;
}
pub mod collections {
pub use ::alloc::collections::*;
}
pub use ::alloc::vec as vec;
}

#[cfg(not(has_std))]
use std::vec::Vec;

#[macro_use]
mod macros;
Expand Down
2 changes: 2 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

#[cfg(has_std)]
#[macro_export(local_inner_macros)]
/// Create an `IndexMap` from a list of key-value pairs
///
Expand Down Expand Up @@ -37,6 +38,7 @@ macro_rules! indexmap {
};
}

#[cfg(has_std)]
#[macro_export(local_inner_macros)]
/// Create an `IndexSet` from a list of values
///
Expand Down
17 changes: 16 additions & 1 deletion src/map.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
//! `IndexMap` is a hash table where the iteration order of the key-value
//! pairs is independent of the hash values of the keys.

#[cfg(not(has_std))]
use alloc::boxed::Box;
#[cfg(not(has_std))]
use std::vec::Vec;

pub use mutable_keys::MutableKeys;

#[cfg(feature = "rayon")]
Expand All @@ -10,9 +15,11 @@ use std::hash::Hash;
use std::hash::BuildHasher;
use std::hash::Hasher;
use std::iter::FromIterator;
use std::collections::hash_map::RandomState;
use std::ops::RangeFull;

#[cfg(has_std)]
use std::collections::hash_map::RandomState;

use std::cmp::{max, Ordering};
use std::fmt;
use std::mem::{replace};
Expand Down Expand Up @@ -264,10 +271,17 @@ impl<Sz> ShortHashProxy<Sz>
/// assert_eq!(letters.get(&'y'), None);
/// ```
#[derive(Clone)]
#[cfg(has_std)]
pub struct IndexMap<K, V, S = RandomState> {
core: OrderMapCore<K, V>,
hash_builder: S,
}
#[derive(Clone)]
#[cfg(not(has_std))]
pub struct IndexMap<K, V, S> {
core: OrderMapCore<K, V>,
hash_builder: S,
}

// core of the map that does not depend on S
#[derive(Clone)]
Expand Down Expand Up @@ -379,6 +393,7 @@ macro_rules! probe_loop {
}
}

#[cfg(has_std)]
impl<K, V> IndexMap<K, V> {
/// Create a new map. (Does not allocate.)
pub fn new() -> Self {
Expand Down
14 changes: 13 additions & 1 deletion src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
#[cfg(feature = "rayon")]
pub use ::rayon::set as rayon;

use std::cmp::Ordering;
#[cfg(not(has_std))]
use std::vec::Vec;

#[cfg(has_std)]
use std::collections::hash_map::RandomState;

use std::cmp::Ordering;
use std::fmt;
use std::iter::{FromIterator, Chain};
use std::hash::{Hash, BuildHasher};
Expand Down Expand Up @@ -59,9 +64,15 @@ type Bucket<T> = super::Bucket<T, ()>;
/// assert!(!letters.contains(&'y'));
/// ```
#[derive(Clone)]
#[cfg(has_std)]
pub struct IndexSet<T, S = RandomState> {
map: IndexMap<T, (), S>,
}
#[cfg(not(has_std))]
#[derive(Clone)]
pub struct IndexSet<T, S> {
map: IndexMap<T, (), S>,
}

impl<T, S> Entries for IndexSet<T, S> {
type Entry = Bucket<T>;
Expand Down Expand Up @@ -99,6 +110,7 @@ impl<T, S> fmt::Debug for IndexSet<T, S>
}
}

#[cfg(has_std)]
impl<T> IndexSet<T> {
/// Create a new set. (Does not allocate.)
pub fn new() -> Self {
Expand Down
13 changes: 13 additions & 0 deletions test-nostd/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "test-nostd"
version = "0.1.0"
authors = ["bluss"]
publish = false
edition = "2018"

[dependencies]
indexmap = { path = ".." }
# no-std compatible hasher
twox-hash = { version = "1.5", default-features = false }

[dev-dependencies]
22 changes: 22 additions & 0 deletions test-nostd/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#![no_std]

use indexmap::IndexMap;
use indexmap::IndexSet;
use core::hash::BuildHasherDefault;
use twox_hash::XxHash64;
type Map<K, V> = IndexMap<K, V, BuildHasherDefault<XxHash64>>;
type Set<T> = IndexSet<T, BuildHasherDefault<XxHash64>>;

use core::iter::FromIterator;

pub fn test_compile() {
let mut map = Map::default();
map.insert(1, 1);
map.insert(2, 4);
for (_, _) in map.iter() { }

let _map2 = Map::from_iter(Some((1, 1)));

let mut set = Set::default();
set.insert("a");
}