Skip to content

Commit

Permalink
Merge pull request #1257 from YBoy-git/use_alloc_feature
Browse files Browse the repository at this point in the history
READY :  (collection_tools): Implement `use_alloc` feature, cover it with tests
  • Loading branch information
Wandalen authored Mar 27, 2024
2 parents fd0d816 + e3a9b1f commit 2ba784c
Show file tree
Hide file tree
Showing 12 changed files with 1,109 additions and 107 deletions.
3 changes: 1 addition & 2 deletions module/core/collection_tools/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,14 @@ full = [
enabled = []

# Collection constructors, like `hmap!{ "key" => "val" }`
collection_constructors = [ "literally" ]
collection_constructors = []
# STD collection for no_std.
collection_std = []


[dependencies]

## external
literally = { version = "~0.1.3", optional = true, default-features = false }
hashbrown = { version = "~0.14.3", optional = true, default-features = false, features = [ "default" ] }

[dev-dependencies]
Expand Down
75 changes: 55 additions & 20 deletions module/core/collection_tools/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,50 @@ This module encompasses a suite of meta-tools designed to enhance Rust's collect

Consider the following example, which demonstrates the use of the `hmap!` macro to effortlessly create a `HashMap`:

<!-- // zzz : qqq : rid off `#[ cfg( not( feature = "use_alloc" ) ) ]` -->
```rust
# #[ cfg( not( feature = "use_alloc" ) ) ]
# #[ cfg( all( feature = "enabled", feature = "collection_constructors" ) ) ]
# #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ]
# {

use collection_tools::*;

let meta_map = hmap! { 3 => 13 };
let mut std_map = std::collections::HashMap::new();
let mut std_map = collection_tools::HashMap::new();
std_map.insert( 3, 13 );
assert_eq!( meta_map, std_map );
# }
```

Note: Do not be afraid of `collection_tools::HashMap`. It is basically a reexport of `std`'s `HashMap`, unless you have enabled `use_alloc` feature.

Another example, this time, `bset!`, providing you a `BTreeSet`:

```rust
# #[ cfg( all( feature = "enabled", feature = "collection_constructors" ) ) ]
# #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ]
# {
use collection_tools::*;

let meta_set = bset! { 3, 13 };
let mut std_set = collection_tools::BTreeSet::new();
std_set.insert( 13 );
std_set.insert( 3 );
assert_eq!( meta_set, std_set );
# }
```

Another example with `list!`:

```rust
# #[ cfg( all( feature = "enabled", feature = "collection_constructors" ) ) ]
# #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ]
# {
use collection_tools::*;

let meta_list : LinkedList< i32 > = list! { 3, 13 };
let mut meta_list = collection_tools::LinkedList::new();
meta_list.push_front( 13 );
meta_list.push_front( 3 );
assert_eq!( meta_list, meta_list );
# }
```

Expand All @@ -37,42 +67,47 @@ When implementing a `no_std` environment with the `use_alloc` feature in your Ru

You can do

<!-- // zzz : qqq : rid off `#[ cfg( not( feature = "use_alloc" ) ) ]` -->
<!-- // zzz : aaa : rid off `#[ cfg( not( feature = "use_alloc" ) ) ]` -- Rid of by not relying on std -->
```rust
# #[ cfg( not( feature = "use_alloc" ) ) ]
# #[ cfg( all( feature = "enabled", feature = "collection_std" ) ) ]
# #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ]
# {
use collection_tools::HashSet;

use collection_tools::Vec;

let mut map : Vec< i32 > = Vec::new();
map.push( 1 );
assert_eq!( map.first().unwrap().clone(), 1 );

let mut vec : HashSet< i32 > = HashSet::new();
vec.insert( 1 );
assert_eq!( vec.contains( &1 ), true );
# }
```

Instead of

<details>
<summary>The code above will be expanded to this</summary>
<summary>Click to see</summary>

```rust
#[ cfg( feature = "use_alloc" ) ]
extern crate alloc;
#[ cfg( feature = "use_alloc" ) ]
use alloc::vec::Vec;
use hashbrown::HashSet; // a `no_std` replacement for `HashSet`
#[ cfg( not( feature = "no_std" ) ) ]
use std::vec::Vec;
use std::collections::HashSet;

let mut collection : Vec< i32 > = Vec::new();
collection.push( 1 );
assert_eq!( collection.first().unwrap().clone(), 1 );
let mut vec : HashSet< i32 > = HashSet::new();
vec.insert( 1 );
assert_eq!( vec.contains( &1 ), true );
```

</details>

### Collections being used

To support `no_std` environment as much as possible, we aim at using collections from `alloc` whenever its possible.

If `use_alloc` feature is on, collections available only in `std` are replaced with their `no_std` counterparts. For now, the only replaced collections are `HashMap` and `HashSet` , taken from `hashbrown`.

### MORE Examples

If you are feeling confused about the syntax you should use for a macro, you can visit its documentation. It is saturated with different examples, so hopefully you'll not be stuck.

### To add to your project

```sh
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,21 @@
#[ cfg( not( all
(
not( feature = "use_alloc" ),
// not( feature = "use_alloc" ) ) ],
all( feature = "enabled", feature = "collection_constructors" ),
any( not( feature = "no_std" ), feature = "use_alloc" )
)))]
fn main(){}

// zzz : qqq : rid off `#[ cfg( not( feature = "use_alloc" ) ) ]`
#[ cfg( not( feature = "use_alloc" ) ) ]
// zzz : aaa : rid off `#[ cfg( not( feature = "use_alloc" ) ) ]` -- Rid of by not relying on std
// #[ cfg( not( feature = "use_alloc" ) ) ]
#[ cfg( all( feature = "enabled", feature = "collection_constructors" ) ) ]
#[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ]
fn main()
{
use collection_tools::*;
let map = hmap! { 3 => 13 };
let mut expected = std::collections::HashMap::new();
let mut expected = collection_tools::HashMap::new();
expected.insert( 3, 13 );
assert_eq!( map, expected );
}
Loading

0 comments on commit 2ba784c

Please sign in to comment.