use std::convert::Infallible; use std::fmt; use std::marker::PhantomData; use std::ops;
/// Storage for streams #[derive(Debug)] pub(super) struct Store {
slab: slab::Slab<Stream>,
ids: IndexMap<StreamId, SlabIndex>,
}
/// "Pointer" to an entry in the store pub(super) struct Ptr<'a> {
key: Key,
store: &'a mut Store,
}
/// References an entry in the store. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) struct Key {
index: SlabIndex, /// Keep the stream ID in the key as an ABA guard, since slab indices /// could be re-used with a new stream.
stream_id: StreamId,
}
// We can never have more than `StreamId::MAX` streams in the store, // so we can save a smaller index (u32 vs usize). #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct SlabIndex(u32);
pubfn try_for_each<F, E>(&mutself, mut f: F) -> Result<(), E> where
F: FnMut(Ptr) -> Result<(), E>,
{ letmut len = self.ids.len(); letmut i = 0;
while i < len { // Get the key by index, this makes the borrow checker happy let (stream_id, index) = { let entry = self.ids.get_index(i).unwrap();
(*entry.0, *entry.1)
};
// While running h2 unit/integration tests, enable this debug assertion. // // In practice, we don't need to ensure this. But the integration tests // help to make sure we've cleaned up in cases where we could (like, the // runtime isn't suddenly dropping the task for unknown reasons). #[cfg(feature = "unstable")] impl Drop for Store { fn drop(&mutself) { use std::thread;
if !thread::panicking() {
debug_assert!(self.slab.is_empty());
}
}
}
/// Queue the stream. /// /// If the stream is already contained by the list, return `false`. pubfn push(&mutself, stream: &mut store::Ptr) -> bool {
tracing::trace!("Queue::push_back");
if N::is_queued(stream) {
tracing::trace!(" -> already queued"); returnfalse;
}
N::set_queued(stream, true);
// The next pointer shouldn't be set
debug_assert!(N::next(stream).is_none());
/// Queue the stream /// /// If the stream is already contained by the list, return `false`. pubfn push_front(&mutself, stream: &mutstore::Ptr) -> bool {
tracing::trace!("Queue::push_front");
if N::is_queued(stream) {
tracing::trace!(" -> already queued"); returnfalse;
}
N::set_queued(stream, true);
// The next pointer shouldn't be set
debug_assert!(N::next(stream).is_none());
impl<'a> Ptr<'a> { /// Returns the Key associated with the stream pubfn key(&self) -> Key { self.key
}
pubfn store_mut(&mutself) -> &mut Store { self.store
}
/// Remove the stream from the store pubfn remove(self) -> StreamId { // The stream must have been unlinked before this point
debug_assert!(!self.store.ids.contains_key(&self.key.stream_id));
// Remove the stream state let stream = self.store.slab.remove(self.key.index.0as usize);
assert_eq!(stream.id, self.key.stream_id);
stream.id
}
/// Remove the StreamId -> stream state association. /// /// This will effectively remove the stream as far as the H2 protocol is /// concerned. pubfn unlink(&mutself) { let id = self.key.stream_id; self.store.ids.swap_remove(&id);
}
}
impl<'a> OccupiedEntry<'a> { pubfn key(&self) -> Key { let stream_id = *self.ids.key(); let index = *self.ids.get();
Key { index, stream_id }
}
}
// ===== impl VacantEntry =====
impl<'a> VacantEntry<'a> { pubfn insert(self, value: Stream) -> Key { // Insert the value in the slab let stream_id = value.id; let index = SlabIndex(self.slab.insert(value) as u32);
// Insert the handle in the ID map self.ids.insert(index);
Key { index, stream_id }
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.