take-some

Crates.iotake-some
lib.rstake-some
version0.1.2
sourcesrc
created_at2018-07-16 21:40:23.607776
updated_at2018-07-17 17:00:39.263749
descriptionA simple library that provides a way to obtain *some* value from various collections
homepage
repositoryhttps://gitlab.com/mexus/take-some-rs
max_upload_size
id74567
size31,835
Denis (mexus)

documentation

https://docs.rs/take-some/

README

take-some

A simple library that provides a way to obtain some value from various collections.

pipeline status crates.io docs.rs

[Release docs]

[Master docs]

Sometimes one simply needs to "take" an element from a collection, no matter which element will it be. If you are that one, please feel free to use the crate that aims to make your (yes, yours!) life a tiny bit easier.

Now let's see how it works. Let's say you want to implement a hash map that is statically guaranteed by the rust's type system to be non-empy at all the times. The most straightforward way to do so is to declare it as a pair of an item and the rest of the items, like struct NonEmptyHashMap<K, V, S> (((K, V), ::std::collections::HashMap<K, V,S>)).

So far, so good. You will obviously want to create some nice user API for it, and that will include an instantiation of you type with a normal HashMap from the standard library. And here shines the take-some crate!

extern crate take_some;

use std::collections::HashMap;
use std::hash::{BuildHasher, Hash};
use take_some::TakeSome;

struct NonEmptyHashMap<K, V, S> {
    first: (K, V),
    rest: HashMap<K, V, S>,
}

impl<K, V, S> NonEmptyHashMap<K, V, S>
where
    K: Eq + Hash,
    S: BuildHasher,
{
    fn from_std_hashmap(mut map: HashMap<K, V, S>) -> Option<Self> {
        map.take_some()
            .map(|first| NonEmptyHashMap { first, rest: map })
    }

    // An alternative implementation that takes advantage of the `TakeSome::split_at_some`
    // method.
    fn from_std_hashmap2(map: HashMap<K, V, S>) -> Option<Self> {
        map.split_at_some()
            .map(|(first, rest)| NonEmptyHashMap { first, rest })
            .ok()
    }
}

fn main() {
    let map: HashMap<String, String> = vec![
        ("first".into(), "lol".into()),
        ("second".into(), "lul".into()),
    ].into_iter()
        .collect();
    let non_empty_map = NonEmptyHashMap::from_std_hashmap(map);
    assert!(non_empty_map.is_some());

    let empty_map: HashMap<String, String> = HashMap::new();
    let non_empty_map = NonEmptyHashMap::from_std_hashmap(empty_map);
    // It is entirely impossible (hail to the type system!) to create an instance of the
    // `NonEmptyHashMap` with an empty map!
    assert!(non_empty_map.is_none());
}

And that's it! Yes, it is that simple.

If you'd like to implement the trait for your custom collections, have a look at the source code of the crate (btree_map.rs, hash_set.rs, vec.rs and so forth), or take a look at an example in the examples directory where we implement the trait for a "foreign" type.

License: MIT/Apache-2.0

Commit count: 6

cargo fmt