-
-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2026 from hannobraun/handles
Introduce `HandleSet`, `HandleIter`
- Loading branch information
Showing
13 changed files
with
167 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
use std::{collections::BTreeSet, fmt::Debug}; | ||
|
||
use crate::storage::Handle; | ||
|
||
/// An ordered set of object handles | ||
/// | ||
/// This is an internal data structure that is used within objects that | ||
/// reference multiple other objects of the same type. It does not contain any | ||
/// duplicate elements, and it maintains the insertion order of those elements. | ||
/// | ||
/// `HandleSet` implement `FromIterator`, but it must never be constructed from | ||
/// an iterator that contains duplicate handles. This will result in a panic. | ||
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] | ||
pub struct HandleSet<T> { | ||
// This is supposed to be a set data structure, so what is that `Vec` doing | ||
// here? Well, it's here because we need it to preserve insertion order, but | ||
// that doesn't explain why it is here *alone*. | ||
// | ||
// If you look closely, you'll notice that this is an immutable data | ||
// structure (since it is used in objects, and objects themselves are | ||
// immutable). We make sure there are no duplicates when this is | ||
// constructed (see the `FromIterator` implementation below), but after | ||
// that, we're fine. | ||
inner: Vec<Handle<T>>, | ||
} | ||
|
||
impl<T> HandleSet<T> { | ||
pub fn len(&self) -> usize { | ||
self.inner.len() | ||
} | ||
|
||
pub fn is_empty(&self) -> bool { | ||
self.inner.is_empty() | ||
} | ||
|
||
pub fn nth(&self, index: usize) -> Option<&Handle<T>> { | ||
self.inner.get(index) | ||
} | ||
|
||
pub fn iter(&self) -> HandleIter<T> { | ||
HandleIter { | ||
handles: &self.inner, | ||
next_index: 0, | ||
} | ||
} | ||
} | ||
|
||
impl<O> FromIterator<Handle<O>> for HandleSet<O> | ||
where | ||
O: Debug + Ord, | ||
{ | ||
fn from_iter<T: IntoIterator<Item = Handle<O>>>(handles: T) -> Self { | ||
let mut added = BTreeSet::new(); | ||
let mut inner = Vec::new(); | ||
|
||
for handle in handles { | ||
if added.contains(&handle) { | ||
panic!( | ||
"Constructing `HandleSet` with duplicate handle: {:?}", | ||
handle | ||
); | ||
} | ||
|
||
added.insert(handle.clone()); | ||
inner.push(handle); | ||
} | ||
|
||
Self { inner } | ||
} | ||
} | ||
|
||
/// An iterator over handles to objects | ||
/// | ||
/// This struct is returned by the respective methods of all objects that | ||
/// reference multiple objects of the same type. | ||
pub struct HandleIter<'r, T> { | ||
handles: &'r Vec<Handle<T>>, | ||
next_index: usize, | ||
} | ||
|
||
impl<'r, T> Iterator for HandleIter<'r, T> { | ||
// You might wonder why we're returning references to handles here, when | ||
// `Handle` already is kind of reference, and easily cloned. | ||
// | ||
// Most of the time that doesn't make a difference, but there are use cases | ||
// where dealing with owned `Handle`s is inconvenient, for example when | ||
// using iterator adapters. You can't return a reference to the argument of | ||
// an adapter's closure, if you own that argument. You can, if you just | ||
// reference the argument. | ||
type Item = &'r Handle<T>; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
let handle = self.handles.get(self.next_index); | ||
self.next_index += 1; | ||
handle | ||
} | ||
|
||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
let size = self.handles.len(); | ||
(size, Some(size)) | ||
} | ||
} | ||
|
||
impl<T> ExactSizeIterator for HandleIter<'_, T> {} | ||
|
||
// Deriving won't work, as that only derives `Clone` where `T: Clone`. But | ||
// `HandleIter` can be `Clone`d unconditionally. | ||
impl<T> Clone for HandleIter<'_, T> { | ||
fn clone(&self) -> Self { | ||
Self { | ||
handles: self.handles, | ||
next_index: self.next_index, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.