1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! A simple library that provides a way to obtain *some* value from various collections.
//!
//! [![pipeline status](https://gitlab.com/mexus/take-some-rs/badges/master/pipeline.svg)](https://gitlab.com/mexus/take-some-rs/commits/master)
//! [![crates.io](https://img.shields.io/crates/v/take-some.svg)](https://crates.io/crates/take-some)
//! [![docs.rs](https://docs.rs/take-some/badge.svg)](https://docs.rs/take-some)
//!
//! [[Release docs]](https://docs.rs/take-some/)
//!
//! [[Master docs]](https://mexus.gitlab.io/take-some-rs/take_some/)
//!
//! 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!
//!
//! ```rust
//! 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.

#![deny(missing_docs)]

mod btree_map;
mod btree_set;
mod hash_map;
mod hash_set;
mod vec;

/// A helper trait that allows to take *some* value out of a collection, i.e. remove a single
/// element and return it, while preserving all others.
pub trait TakeSome {
    /// An item of the collection.
    type Item;

    /// Takes "some" element from a collection while preserving all others.
    ///
    /// In general case it could not be defined which exactly element will be returned (first,
    /// last, greatest, least, ...), so, I repeat, in general case it is better to make no
    /// assumptions on the ordering or anything else.
    ///
    /// There are several assumptions that trait implementors should take care of:
    ///
    /// * [`None`] should be returned if and only if the collection is empty.
    /// * If the collection is NOT empty, exactly ONE element should be taken out from it, i.e.
    ///   all the rest items should remains there.
    /// * In case the collection IS empty, this call should NOT modify the collection.
    /// * The implementors are encouraged to implement the method in a way that it will cause the
    ///   least overhead possible.
    fn take_some(&mut self) -> Option<Self::Item>;

    /// Splits a given collection at "some" element, and returns a pair of that element and the
    /// remaining collection, if "some" element was found, or returns the original collection if
    /// "some" element could not be found. The latter happens if the collection is empty.
    fn split_at_some(mut self) -> Result<(Self::Item, Self), Self>
    where
        Self: Sized,
    {
        match self.take_some() {
            Some(x) => Ok((x, self)),
            None => Err(self),
        }
    }
}