use alloc::vec::Vec;
use crate::{acquirable::Acquirable, id::LockId};
pub struct LockSet<L> {
group: L,
sorted_indices: Vec<usize>,
}
impl<L: core::fmt::Debug> core::fmt::Debug for LockSet<L> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LockSet")
.field("sorted_indices", &self.sorted_indices)
.finish_non_exhaustive()
}
}
#[allow(clippy::indexing_slicing)] pub(crate) fn build_sorted<'a, L: Acquirable<'a>>(group: &L) -> (Vec<usize>, bool) {
let mut ids: Vec<LockId> = Vec::new();
group.collect_ids(&mut ids);
let mut indices: Vec<usize> = (0..ids.len()).collect();
indices.sort_by_key(|&i| ids[i]);
let has_duplicates = indices.windows(2).any(|w| ids[w[0]] == ids[w[1]]);
(indices, has_duplicates)
}
impl<L> LockSet<L> {
#[must_use]
pub fn new<'a>(group: L) -> Self
where
L: Acquirable<'a>,
{
let (sorted_indices, has_duplicates) = build_sorted(&group);
assert!(!has_duplicates, "LockSet contains duplicate locks");
Self {
group,
sorted_indices,
}
}
#[must_use]
pub fn try_new<'a>(group: L) -> Option<Self>
where
L: Acquirable<'a>,
{
let (sorted_indices, has_duplicates) = build_sorted(&group);
if has_duplicates {
return None;
}
Some(Self {
group,
sorted_indices,
})
}
pub(crate) fn lock_sorted<'a>(&'a self) -> <L as Acquirable<'a>>::Guard
where
L: Acquirable<'a>,
{
self.group.lock_sorted(&self.sorted_indices)
}
}