Skip to content

Commit fb5dacd

Browse files
Copilotkennykerr
andauthored
Add mutable IMap<K, V> stock implementation to windows-collections (#4323)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kennykerr <9845234+kennykerr@users.noreply.github.com>
1 parent 99435fb commit fb5dacd

5 files changed

Lines changed: 402 additions & 30 deletions

File tree

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use super::*;
2+
use windows_core::*;
3+
4+
#[implement(IKeyValuePair<K, V>)]
5+
pub(super) struct StockKeyValuePair<K, V>
6+
where
7+
K: RuntimeType + 'static,
8+
V: RuntimeType + 'static,
9+
K::Default: Clone,
10+
V::Default: Clone,
11+
{
12+
pub(super) key: K::Default,
13+
pub(super) value: V::Default,
14+
}
15+
16+
impl<K, V> IKeyValuePair_Impl<K, V> for StockKeyValuePair_Impl<K, V>
17+
where
18+
K: RuntimeType,
19+
V: RuntimeType,
20+
K::Default: Clone,
21+
V::Default: Clone,
22+
{
23+
fn Key(&self) -> Result<K> {
24+
K::from_default(&self.key)
25+
}
26+
27+
fn Value(&self) -> Result<V> {
28+
V::from_default(&self.value)
29+
}
30+
}

crates/libs/collections/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ const E_BOUNDS: windows_core::HRESULT = windows_core::HRESULT(0x8000000B_u32 as
1616
#[cfg(feature = "std")]
1717
mod iterable;
1818
#[cfg(feature = "std")]
19+
mod key_value_pair;
20+
#[cfg(feature = "std")]
21+
mod map;
22+
#[cfg(feature = "std")]
1923
mod map_view;
2024
#[cfg(feature = "std")]
2125
mod vector;

crates/libs/collections/src/map.rs

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
use super::*;
2+
use windows_core::*;
3+
4+
#[implement(IMap<K, V>, IIterable<IKeyValuePair<K, V>>)]
5+
struct StockMap<K, V>
6+
where
7+
K: RuntimeType + 'static,
8+
V: RuntimeType + 'static,
9+
K::Default: Clone + Ord,
10+
V::Default: Clone,
11+
{
12+
map: std::sync::RwLock<std::collections::BTreeMap<K::Default, V::Default>>,
13+
}
14+
15+
impl<K, V> IIterable_Impl<IKeyValuePair<K, V>> for StockMap_Impl<K, V>
16+
where
17+
K: RuntimeType,
18+
V: RuntimeType,
19+
K::Default: Clone + Ord,
20+
V::Default: Clone,
21+
{
22+
fn First(&self) -> Result<IIterator<IKeyValuePair<K, V>>> {
23+
Ok(ComObject::new(StockMapIterator::<K, V> {
24+
owner: self.to_object(),
25+
current: 0.into(),
26+
})
27+
.into_interface())
28+
}
29+
}
30+
31+
impl<K, V> IMap_Impl<K, V> for StockMap_Impl<K, V>
32+
where
33+
K: RuntimeType,
34+
V: RuntimeType,
35+
K::Default: Clone + Ord,
36+
V::Default: Clone,
37+
{
38+
fn Lookup(&self, key: Ref<K>) -> Result<V> {
39+
let map = self.map.read().unwrap();
40+
let value = map.get(&*key).ok_or_else(|| Error::from(E_BOUNDS))?;
41+
V::from_default(value)
42+
}
43+
44+
fn Size(&self) -> Result<u32> {
45+
Ok(self.map.read().unwrap().len().try_into()?)
46+
}
47+
48+
fn HasKey(&self, key: Ref<K>) -> Result<bool> {
49+
Ok(self.map.read().unwrap().contains_key(&*key))
50+
}
51+
52+
fn GetView(&self) -> Result<IMapView<K, V>> {
53+
let snapshot = self.map.read().unwrap().clone();
54+
Ok(IMapView::<K, V>::from(snapshot))
55+
}
56+
57+
fn Insert(&self, key: Ref<K>, value: Ref<V>) -> Result<bool> {
58+
let mut map = self.map.write().unwrap();
59+
let replaced = map.contains_key(&*key);
60+
map.insert((*key).clone(), (*value).clone());
61+
Ok(replaced)
62+
}
63+
64+
fn Remove(&self, key: Ref<K>) -> Result<()> {
65+
let mut map = self.map.write().unwrap();
66+
if map.remove(&*key).is_none() {
67+
return Err(Error::from(E_BOUNDS));
68+
}
69+
Ok(())
70+
}
71+
72+
fn Clear(&self) -> Result<()> {
73+
self.map.write().unwrap().clear();
74+
Ok(())
75+
}
76+
}
77+
78+
#[implement(IIterator<IKeyValuePair<K, V>>)]
79+
struct StockMapIterator<K, V>
80+
where
81+
K: RuntimeType + 'static,
82+
V: RuntimeType + 'static,
83+
K::Default: Clone + Ord,
84+
V::Default: Clone,
85+
{
86+
owner: ComObject<StockMap<K, V>>,
87+
current: std::sync::atomic::AtomicUsize,
88+
}
89+
90+
impl<K, V> IIterator_Impl<IKeyValuePair<K, V>> for StockMapIterator_Impl<K, V>
91+
where
92+
K: RuntimeType,
93+
V: RuntimeType,
94+
K::Default: Clone + Ord,
95+
V::Default: Clone,
96+
{
97+
fn Current(&self) -> Result<IKeyValuePair<K, V>> {
98+
let current = self.current.load(std::sync::atomic::Ordering::Relaxed);
99+
let map = self.owner.map.read().unwrap();
100+
if let Some((key, value)) = map.iter().nth(current) {
101+
Ok(ComObject::new(super::key_value_pair::StockKeyValuePair {
102+
key: key.clone(),
103+
value: value.clone(),
104+
})
105+
.into_interface())
106+
} else {
107+
Err(Error::from(E_BOUNDS))
108+
}
109+
}
110+
111+
fn HasCurrent(&self) -> Result<bool> {
112+
let current = self.current.load(std::sync::atomic::Ordering::Relaxed);
113+
let map = self.owner.map.read().unwrap();
114+
Ok(map.len() > current)
115+
}
116+
117+
fn MoveNext(&self) -> Result<bool> {
118+
let current = self.current.load(std::sync::atomic::Ordering::Relaxed);
119+
let map = self.owner.map.read().unwrap();
120+
let len = map.len();
121+
drop(map);
122+
123+
if current < len {
124+
self.current
125+
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
126+
}
127+
128+
Ok(len > current + 1)
129+
}
130+
131+
fn GetMany(&self, items: &mut [Option<IKeyValuePair<K, V>>]) -> Result<u32> {
132+
let current = self.current.load(std::sync::atomic::Ordering::Relaxed);
133+
let map = self.owner.map.read().unwrap();
134+
135+
if current >= map.len() {
136+
return Ok(0);
137+
}
138+
139+
let actual = std::cmp::min(map.len() - current, items.len());
140+
let (items, _) = items.split_at_mut(actual);
141+
142+
for (item, (key, value)) in items.iter_mut().zip(map.iter().skip(current)) {
143+
*item = Some(
144+
ComObject::new(super::key_value_pair::StockKeyValuePair {
145+
key: key.clone(),
146+
value: value.clone(),
147+
})
148+
.into_interface(),
149+
);
150+
}
151+
152+
self.current
153+
.fetch_add(actual, std::sync::atomic::Ordering::Relaxed);
154+
155+
Ok(actual as u32)
156+
}
157+
}
158+
159+
impl<K, V> From<std::collections::BTreeMap<K::Default, V::Default>> for IMap<K, V>
160+
where
161+
K: RuntimeType,
162+
V: RuntimeType,
163+
K::Default: Clone + Ord,
164+
V::Default: Clone,
165+
{
166+
fn from(map: std::collections::BTreeMap<K::Default, V::Default>) -> Self {
167+
ComObject::new(StockMap {
168+
map: std::sync::RwLock::new(map),
169+
})
170+
.into_interface()
171+
}
172+
}

crates/libs/collections/src/map_view.rs

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ where
7979
let mut current = self.current.read().unwrap().clone().peekable();
8080

8181
if let Some((key, value)) = current.peek() {
82-
Ok(ComObject::new(StockKeyValuePair {
82+
Ok(ComObject::new(super::key_value_pair::StockKeyValuePair {
8383
key: (*key).clone(),
8484
value: (*value).clone(),
8585
})
@@ -107,7 +107,7 @@ where
107107
for pair in pairs {
108108
if let Some((key, value)) = current.next() {
109109
*pair = Some(
110-
ComObject::new(StockKeyValuePair {
110+
ComObject::new(super::key_value_pair::StockKeyValuePair {
111111
key: (*key).clone(),
112112
value: (*value).clone(),
113113
})
@@ -123,34 +123,6 @@ where
123123
}
124124
}
125125

126-
#[implement(IKeyValuePair<K, V>)]
127-
struct StockKeyValuePair<K, V>
128-
where
129-
K: RuntimeType + 'static,
130-
V: RuntimeType + 'static,
131-
K::Default: Clone,
132-
V::Default: Clone,
133-
{
134-
key: K::Default,
135-
value: V::Default,
136-
}
137-
138-
impl<K, V> IKeyValuePair_Impl<K, V> for StockKeyValuePair_Impl<K, V>
139-
where
140-
K: RuntimeType,
141-
V: RuntimeType,
142-
K::Default: Clone,
143-
V::Default: Clone,
144-
{
145-
fn Key(&self) -> Result<K> {
146-
K::from_default(&self.key)
147-
}
148-
149-
fn Value(&self) -> Result<V> {
150-
V::from_default(&self.value)
151-
}
152-
}
153-
154126
impl<K, V> From<std::collections::BTreeMap<K::Default, V::Default>> for IMapView<K, V>
155127
where
156128
K: RuntimeType,

0 commit comments

Comments
 (0)