1use core::hash::{Hash, Hasher};
2
3use crate::{
4    binding_model::{self},
5    FastIndexMap,
6};
7
8#[derive(Debug, Copy, Clone, PartialEq, Eq)]
10pub enum Origin {
11    Pool,
13    Derived,
15}
16
17#[derive(Debug, Default, Clone, Eq)]
21pub struct EntryMap {
22    inner: FastIndexMap<u32, wgt::BindGroupLayoutEntry>,
25    sorted: bool,
31}
32
33impl PartialEq for EntryMap {
34    fn eq(&self, other: &Self) -> bool {
35        self.assert_sorted();
36        other.assert_sorted();
37
38        self.inner == other.inner
39    }
40}
41
42impl Hash for EntryMap {
43    fn hash<H: Hasher>(&self, state: &mut H) {
44        self.assert_sorted();
45
46        for entry in self.inner.values() {
51            entry.hash(state);
52        }
53    }
54}
55
56impl EntryMap {
57    fn assert_sorted(&self) {
58        assert!(self.sorted);
59    }
60
61    pub fn from_entries(
66        device_limits: &wgt::Limits,
67        entries: &[wgt::BindGroupLayoutEntry],
68    ) -> Result<Self, binding_model::CreateBindGroupLayoutError> {
69        let mut inner = FastIndexMap::with_capacity_and_hasher(entries.len(), Default::default());
70        for entry in entries {
71            if entry.binding >= device_limits.max_bindings_per_bind_group {
72                return Err(
73                    binding_model::CreateBindGroupLayoutError::InvalidBindingIndex {
74                        binding: entry.binding,
75                        maximum: device_limits.max_bindings_per_bind_group,
76                    },
77                );
78            }
79            if inner.insert(entry.binding, *entry).is_some() {
80                return Err(binding_model::CreateBindGroupLayoutError::ConflictBinding(
81                    entry.binding,
82                ));
83            }
84        }
85        inner.sort_unstable_keys();
86
87        Ok(Self {
88            inner,
89            sorted: true,
90        })
91    }
92
93    pub fn len(&self) -> usize {
95        self.inner.len()
96    }
97
98    pub fn get(&self, binding: u32) -> Option<&wgt::BindGroupLayoutEntry> {
100        self.inner.get(&binding)
101    }
102
103    pub fn indices(&self) -> impl ExactSizeIterator<Item = u32> + '_ {
105        self.inner.keys().copied()
106    }
107
108    pub fn values(&self) -> impl ExactSizeIterator<Item = &wgt::BindGroupLayoutEntry> + '_ {
110        self.inner.values()
111    }
112
113    pub fn iter(&self) -> impl ExactSizeIterator<Item = (&u32, &wgt::BindGroupLayoutEntry)> + '_ {
114        self.inner.iter()
115    }
116
117    pub fn is_empty(&self) -> bool {
118        self.inner.is_empty()
119    }
120
121    pub fn contains_key(&self, key: u32) -> bool {
122        self.inner.contains_key(&key)
123    }
124
125    pub fn entry(&mut self, key: u32) -> indexmap::map::Entry<'_, u32, wgt::BindGroupLayoutEntry> {
126        self.sorted = false;
127        self.inner.entry(key)
128    }
129
130    pub fn sort(&mut self) {
131        self.inner.sort_unstable_keys();
132        self.sorted = true;
133    }
134}