Skip to content

Commit

Permalink
Fix panic in FromIterator impl (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e authored Jun 7, 2021
1 parent eb0ad4e commit 5bc6f62
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,7 @@ impl<T> FromIterator<(usize, T)> for Slab<T> {
let mut slab = Self::with_capacity(iterator.size_hint().0);

let mut vacant_list_broken = false;
let mut first_vacant_index = None;
for (key, value) in iterator {
if key < slab.entries.len() {
// iterator is not sorted, might need to recreate vacant list
Expand All @@ -1214,6 +1215,9 @@ impl<T> FromIterator<(usize, T)> for Slab<T> {
// This is consistent with HashMap and BtreeMap
slab.entries[key] = Entry::Occupied(value);
} else {
if first_vacant_index.is_none() && slab.entries.len() < key {
first_vacant_index = Some(slab.entries.len());
}
// insert holes as necessary
while slab.entries.len() < key {
// add the entry to the start of the vacant list
Expand All @@ -1230,7 +1234,16 @@ impl<T> FromIterator<(usize, T)> for Slab<T> {
slab.next = slab.entries.len();
} else if vacant_list_broken {
slab.recreate_vacant_list();
} else if let Some(first_vacant_index) = first_vacant_index {
let next = slab.entries.len();
match &mut slab.entries[first_vacant_index] {
Entry::Vacant(n) => *n = next,
_ => unreachable!(),
}
} else {
unreachable!()
}

slab
}
}
Expand Down
12 changes: 12 additions & 0 deletions src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ where

// same as FromIterator impl
let mut vacant_list_broken = false;
let mut first_vacant_index = None;
while let Some((key, value)) = map.next_entry()? {
if key < slab.entries.len() {
// iterator is not sorted, might need to recreate vacant list
Expand All @@ -54,6 +55,9 @@ where
// This is consistent with HashMap and BtreeMap
slab.entries[key] = Entry::Occupied(value);
} else {
if first_vacant_index.is_none() && slab.entries.len() < key {
first_vacant_index = Some(slab.entries.len());
}
// insert holes as necessary
while slab.entries.len() < key {
// add the entry to the start of the vacant list
Expand All @@ -70,6 +74,14 @@ where
slab.next = slab.entries.len();
} else if vacant_list_broken {
slab.recreate_vacant_list();
} else if let Some(first_vacant_index) = first_vacant_index {
let next = slab.entries.len();
match &mut slab.entries[first_vacant_index] {
Entry::Vacant(n) => *n = next,
_ => unreachable!(),
}
} else {
unreachable!()
}

Ok(slab)
Expand Down
30 changes: 30 additions & 0 deletions tests/slab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,36 @@ fn from_iterator_unordered() {
assert_eq!(iter.next(), None);
}

// https://github.com/tokio-rs/slab/issues/100
#[test]
fn from_iterator_issue_100() {
let mut slab: slab::Slab<()> = vec![(1, ())].into_iter().collect();
assert_eq!(slab.len(), 1);
assert_eq!(slab.insert(()), 0);
assert_eq!(slab.insert(()), 2);
assert_eq!(slab.insert(()), 3);

let mut slab: slab::Slab<()> = vec![(1, ()), (2, ())].into_iter().collect();
assert_eq!(slab.len(), 2);
assert_eq!(slab.insert(()), 0);
assert_eq!(slab.insert(()), 3);
assert_eq!(slab.insert(()), 4);

let mut slab: slab::Slab<()> = vec![(1, ()), (3, ())].into_iter().collect();
assert_eq!(slab.len(), 2);
assert_eq!(slab.insert(()), 2);
assert_eq!(slab.insert(()), 0);
assert_eq!(slab.insert(()), 4);

let mut slab: slab::Slab<()> = vec![(0, ()), (2, ()), (3, ()), (5, ())]
.into_iter()
.collect();
assert_eq!(slab.len(), 4);
assert_eq!(slab.insert(()), 4);
assert_eq!(slab.insert(()), 1);
assert_eq!(slab.insert(()), 6);
}

#[test]
fn clear() {
let mut slab = Slab::new();
Expand Down

0 comments on commit 5bc6f62

Please sign in to comment.