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. //! //! [](https://gitlab.com/mexus/take-some-rs/commits/master) //! [](https://crates.io/crates/take-some) //! [](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), } } }