Skip to content

Commit 9abec11

Browse files
authored
Merge pull request #468 from leonzchang/add-entry-methods
Add std `Entry` methods to indexmap `Entry`
2 parents d67ebda + d63205d commit 9abec11

File tree

2 files changed

+256
-0
lines changed

2 files changed

+256
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2424
- Added `Vec::drain`.
2525
- Added `String::drain`.
2626
- Implemented `DoubleEndedIterator` for `OldestOrdered`.
27+
- Added std `Entry` methods to indexmap `Entry`.
2728

2829
### Changed
2930

src/indexmap.rs

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,182 @@ pub enum Entry<'a, K, V, const N: usize> {
386386
Vacant(VacantEntry<'a, K, V, N>),
387387
}
388388

389+
impl<'a, K, V, const N: usize> Entry<'a, K, V, N>
390+
where
391+
K: Eq + Hash,
392+
{
393+
/// Ensures a value is in the entry by inserting the default if empty, and
394+
/// returns a mutable reference to the value in the entry.
395+
///
396+
/// # Examples
397+
///
398+
/// ```
399+
/// use heapless::FnvIndexMap;
400+
///
401+
/// // A hash map with a capacity of 16 key-value pairs allocated on the stack
402+
/// let mut book_reviews = FnvIndexMap::<_, _, 16>::new();
403+
/// let result = book_reviews
404+
/// .entry("Adventures of Huckleberry Finn")
405+
/// .or_insert("My favorite book.");
406+
///
407+
/// assert_eq!(result, Ok(&mut "My favorite book."));
408+
/// assert_eq!(
409+
/// book_reviews["Adventures of Huckleberry Finn"],
410+
/// "My favorite book."
411+
/// );
412+
/// ```
413+
pub fn or_insert(self, default: V) -> Result<&'a mut V, V> {
414+
match self {
415+
Self::Occupied(entry) => Ok(entry.into_mut()),
416+
Self::Vacant(entry) => entry.insert(default),
417+
}
418+
}
419+
420+
/// Ensures a value is in the entry by inserting the result of the default
421+
/// function if empty, and returns a mutable reference to the value in the
422+
/// entry.
423+
///
424+
/// # Examples
425+
///
426+
/// ```
427+
/// use heapless::FnvIndexMap;
428+
///
429+
/// // A hash map with a capacity of 16 key-value pairs allocated on the stack
430+
/// let mut book_reviews = FnvIndexMap::<_, _, 16>::new();
431+
/// let s = "Masterpiece.".to_string();
432+
///
433+
/// book_reviews
434+
/// .entry("Grimms' Fairy Tales")
435+
/// .or_insert_with(|| s);
436+
///
437+
/// assert_eq!(
438+
/// book_reviews["Grimms' Fairy Tales"],
439+
/// "Masterpiece.".to_string()
440+
/// );
441+
/// ```
442+
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> Result<&'a mut V, V> {
443+
match self {
444+
Self::Occupied(entry) => Ok(entry.into_mut()),
445+
Self::Vacant(entry) => entry.insert(default()),
446+
}
447+
}
448+
449+
/// Ensures a value is in the entry by inserting, if empty, the result of
450+
/// the default function. This method allows for generating key-derived
451+
/// values for insertion by providing the default function a reference to
452+
/// the key that was moved during the `.entry(key)` method call.
453+
///
454+
/// The reference to the moved key is provided so that cloning or copying
455+
/// the key is unnecessary, unlike with `.or_insert_with(|| ... )`.
456+
///
457+
/// # Examples
458+
///
459+
/// ```
460+
/// use heapless::FnvIndexMap;
461+
///
462+
/// // A hash map with a capacity of 16 key-value pairs allocated on the stack
463+
/// let mut book_reviews = FnvIndexMap::<_, _, 16>::new();
464+
///
465+
/// book_reviews
466+
/// .entry("Pride and Prejudice")
467+
/// .or_insert_with_key(|key| key.chars().count());
468+
///
469+
/// assert_eq!(book_reviews["Pride and Prejudice"], 19);
470+
/// ```
471+
pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> Result<&'a mut V, V> {
472+
match self {
473+
Self::Occupied(entry) => Ok(entry.into_mut()),
474+
Self::Vacant(entry) => {
475+
let value = default(entry.key());
476+
entry.insert(value)
477+
}
478+
}
479+
}
480+
481+
/// Returns a reference to this entry's key.
482+
///
483+
/// # Examples
484+
///
485+
/// ```
486+
/// use heapless::FnvIndexMap;
487+
///
488+
/// // A hash map with a capacity of 16 key-value pairs allocated on the stack
489+
/// let mut book_reviews = FnvIndexMap::<&str, &str, 16>::new();
490+
/// assert_eq!(
491+
/// book_reviews
492+
/// .entry("The Adventures of Sherlock Holmes")
493+
/// .key(),
494+
/// &"The Adventures of Sherlock Holmes"
495+
/// );
496+
/// ```
497+
pub fn key(&self) -> &K {
498+
match *self {
499+
Self::Occupied(ref entry) => entry.key(),
500+
Self::Vacant(ref entry) => entry.key(),
501+
}
502+
}
503+
504+
/// Provides in-place mutable access to an occupied entry before any
505+
/// potential inserts into the map.
506+
///
507+
/// # Examples
508+
///
509+
/// ```
510+
/// use heapless::FnvIndexMap;
511+
///
512+
/// // A hash map with a capacity of 16 key-value pairs allocated on the stack
513+
/// let mut book_reviews = FnvIndexMap::<_, _, 16>::new();
514+
///
515+
/// book_reviews
516+
/// .entry("Grimms' Fairy Tales")
517+
/// .and_modify(|e| *e = "Masterpiece.")
518+
/// .or_insert("Very enjoyable.");
519+
/// assert_eq!(book_reviews["Grimms' Fairy Tales"], "Very enjoyable.");
520+
/// ```
521+
pub fn and_modify<F>(self, f: F) -> Self
522+
where
523+
F: FnOnce(&mut V),
524+
{
525+
match self {
526+
Self::Occupied(mut entry) => {
527+
f(entry.get_mut());
528+
Self::Occupied(entry)
529+
}
530+
Self::Vacant(entry) => Self::Vacant(entry),
531+
}
532+
}
533+
}
534+
535+
impl<'a, K, V, const N: usize> Entry<'a, K, V, N>
536+
where
537+
K: Eq + Hash,
538+
V: Default,
539+
{
540+
/// Ensures a value is in the entry by inserting the default value if empty,
541+
/// and returns a mutable reference to the value in the entry.
542+
///
543+
/// # Examples
544+
///
545+
/// ```
546+
/// # fn main() {
547+
/// use heapless::FnvIndexMap;
548+
///
549+
/// let mut book_reviews = FnvIndexMap::<&str, Option<&str>, 16>::new();
550+
///
551+
/// book_reviews.entry("Pride and Prejudice").or_default();
552+
///
553+
/// assert_eq!(book_reviews["Pride and Prejudice"], None);
554+
/// # }
555+
/// ```
556+
#[inline]
557+
pub fn or_default(self) -> Result<&'a mut V, V> {
558+
match self {
559+
Self::Occupied(entry) => Ok(entry.into_mut()),
560+
Self::Vacant(entry) => entry.insert(Default::default()),
561+
}
562+
}
563+
}
564+
389565
/// An occupied entry which can be manipulated
390566
pub struct OccupiedEntry<'a, K, V, const N: usize> {
391567
key: K,
@@ -1316,6 +1492,85 @@ mod tests {
13161492
}
13171493
}
13181494

1495+
#[test]
1496+
fn entry_or_insert() {
1497+
let mut a: FnvIndexMap<_, _, 2> = FnvIndexMap::new();
1498+
a.entry("k1").or_insert("v1").unwrap();
1499+
assert_eq!(a["k1"], "v1");
1500+
1501+
a.entry("k2").or_insert("v2").unwrap();
1502+
assert_eq!(a["k2"], "v2");
1503+
1504+
let result = a.entry("k3").or_insert("v3");
1505+
assert_eq!(result, Err("v3"));
1506+
}
1507+
1508+
#[test]
1509+
fn entry_or_insert_with() {
1510+
let mut a: FnvIndexMap<_, _, 2> = FnvIndexMap::new();
1511+
a.entry("k1").or_insert_with(|| "v1").unwrap();
1512+
assert_eq!(a["k1"], "v1");
1513+
1514+
a.entry("k2").or_insert_with(|| "v2").unwrap();
1515+
assert_eq!(a["k2"], "v2");
1516+
1517+
let result = a.entry("k3").or_insert_with(|| "v3");
1518+
assert_eq!(result, Err("v3"));
1519+
}
1520+
1521+
#[test]
1522+
fn entry_or_insert_with_key() {
1523+
let mut a: FnvIndexMap<_, _, 2> = FnvIndexMap::new();
1524+
a.entry("k1")
1525+
.or_insert_with_key(|key| key.chars().count())
1526+
.unwrap();
1527+
assert_eq!(a["k1"], 2);
1528+
1529+
a.entry("k22")
1530+
.or_insert_with_key(|key| key.chars().count())
1531+
.unwrap();
1532+
assert_eq!(a["k22"], 3);
1533+
1534+
let result = a.entry("k3").or_insert_with_key(|key| key.chars().count());
1535+
assert_eq!(result, Err(2));
1536+
}
1537+
1538+
#[test]
1539+
fn entry_key() {
1540+
let mut a: FnvIndexMap<&str, &str, 2> = FnvIndexMap::new();
1541+
1542+
assert_eq!(a.entry("k1").key(), &"k1");
1543+
}
1544+
1545+
#[test]
1546+
fn entry_and_modify() {
1547+
let mut a: FnvIndexMap<_, _, 2> = FnvIndexMap::new();
1548+
a.insert("k1", "v1").unwrap();
1549+
a.entry("k1").and_modify(|e| *e = "modified v1");
1550+
1551+
assert_eq!(a["k1"], "modified v1");
1552+
1553+
a.entry("k2")
1554+
.and_modify(|e| *e = "v2")
1555+
.or_insert("default v2")
1556+
.unwrap();
1557+
1558+
assert_eq!(a["k2"], "default v2");
1559+
}
1560+
1561+
#[test]
1562+
fn entry_or_default() {
1563+
let mut a: FnvIndexMap<&str, Option<u32>, 2> = FnvIndexMap::new();
1564+
a.entry("k1").or_default().unwrap();
1565+
1566+
assert_eq!(a["k1"], None);
1567+
1568+
let mut b: FnvIndexMap<&str, u8, 2> = FnvIndexMap::new();
1569+
b.entry("k2").or_default().unwrap();
1570+
1571+
assert_eq!(b["k2"], 0);
1572+
}
1573+
13191574
#[test]
13201575
fn into_iter() {
13211576
let mut src: FnvIndexMap<_, _, 4> = FnvIndexMap::new();

0 commit comments

Comments
 (0)