1use malloc_size_of_derive::MallocSizeOf;
6use rustc_hash::FxHashMap;
7use servo_base::id::{BrowsingContextId, PipelineId, WebViewId};
8
9#[derive(Debug, Default, MallocSizeOf)]
10pub(crate) struct IdMap {
11 browser_ids: FxHashMap<WebViewId, u32>,
12 browsing_context_ids: FxHashMap<BrowsingContextId, u32>,
13 outer_window_ids: FxHashMap<PipelineId, u32>,
14}
15
16impl IdMap {
17 pub(crate) fn browser_id(&mut self, webview_id: WebViewId) -> DevtoolsBrowserId {
18 let len = self
19 .browser_ids
20 .len()
21 .checked_add(1)
22 .expect("WebViewId count overflow")
23 .try_into()
24 .expect("DevtoolsBrowserId overflow");
25 DevtoolsBrowserId(*self.browser_ids.entry(webview_id).or_insert(len))
26 }
27 pub(crate) fn browsing_context_id(
28 &mut self,
29 browsing_context_id: BrowsingContextId,
30 ) -> DevtoolsBrowsingContextId {
31 let len = self
32 .browsing_context_ids
33 .len()
34 .checked_add(1)
35 .expect("BrowsingContextId count overflow")
36 .try_into()
37 .expect("DevtoolsBrowsingContextId overflow");
38 DevtoolsBrowsingContextId(
39 *self
40 .browsing_context_ids
41 .entry(browsing_context_id)
42 .or_insert(len),
43 )
44 }
45 pub(crate) fn outer_window_id(&mut self, pipeline_id: PipelineId) -> DevtoolsOuterWindowId {
46 let len = self
47 .outer_window_ids
48 .len()
49 .checked_add(1)
50 .expect("PipelineId count overflow")
51 .try_into()
52 .expect("DevtoolsOuterWindowId overflow");
53 DevtoolsOuterWindowId(*self.outer_window_ids.entry(pipeline_id).or_insert(len))
54 }
55}
56
57#[derive(Clone, Copy, Debug, PartialEq, MallocSizeOf)]
58pub(crate) struct DevtoolsBrowserId(u32);
59
60#[derive(Clone, Copy, Debug, PartialEq, MallocSizeOf)]
61pub(crate) struct DevtoolsBrowsingContextId(u32);
62
63#[derive(Clone, Copy, Debug, PartialEq, MallocSizeOf)]
64pub(crate) struct DevtoolsOuterWindowId(u32);
65
66impl DevtoolsBrowserId {
67 pub(crate) fn value(&self) -> u32 {
68 self.0
69 }
70}
71
72impl DevtoolsBrowsingContextId {
73 pub(crate) fn value(&self) -> u32 {
74 self.0
75 }
76}
77
78impl DevtoolsOuterWindowId {
79 pub(crate) fn value(&self) -> u32 {
80 self.0
81 }
82}
83
84#[cfg(test)]
85mod test {
86 use super::*;
87
88 #[test]
89 pub(crate) fn test_id_map() {
90 use std::thread;
91
92 use crossbeam_channel::unbounded;
93 use servo_base::id::{PipelineNamespace, PipelineNamespaceId};
94
95 macro_rules! test_sequential_id_assignment {
96 ($id_type:ident, $new_id_function:expr, $map_id_function:expr) => {
97 let (sender, receiver) = unbounded();
98 let sender1 = sender.clone();
99 let sender2 = sender.clone();
100 let sender3 = sender.clone();
101 let threads = [
102 thread::spawn(move || {
103 PipelineNamespace::install(PipelineNamespaceId(1));
104 sender1.send($new_id_function()).expect("Send failed");
105 sender1.send($new_id_function()).expect("Send failed");
106 sender1.send($new_id_function()).expect("Send failed");
107 }),
108 thread::spawn(move || {
109 PipelineNamespace::install(PipelineNamespaceId(2));
110 sender2.send($new_id_function()).expect("Send failed");
111 sender2.send($new_id_function()).expect("Send failed");
112 sender2.send($new_id_function()).expect("Send failed");
113 }),
114 thread::spawn(move || {
115 PipelineNamespace::install(PipelineNamespaceId(3));
116 sender3.send($new_id_function()).expect("Send failed");
117 sender3.send($new_id_function()).expect("Send failed");
118 sender3.send($new_id_function()).expect("Send failed");
119 }),
120 ];
121 for thread in threads {
122 thread.join().expect("Thread join failed");
123 }
124 let mut id_map = IdMap::default();
125 assert_eq!(
126 $map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
127 $id_type(1)
128 );
129 assert_eq!(
130 $map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
131 $id_type(2)
132 );
133 assert_eq!(
134 $map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
135 $id_type(3)
136 );
137 assert_eq!(
138 $map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
139 $id_type(4)
140 );
141 assert_eq!(
142 $map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
143 $id_type(5)
144 );
145 assert_eq!(
146 $map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
147 $id_type(6)
148 );
149 assert_eq!(
150 $map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
151 $id_type(7)
152 );
153 assert_eq!(
154 $map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
155 $id_type(8)
156 );
157 assert_eq!(
158 $map_id_function(&mut id_map, receiver.recv().expect("Recv failed")),
159 $id_type(9)
160 );
161 };
162 }
163
164 test_sequential_id_assignment!(
165 DevtoolsBrowserId,
166 || WebViewId::new(servo_base::id::TEST_PAINTER_ID),
167 |id_map: &mut IdMap, id| id_map.browser_id(id)
168 );
169 test_sequential_id_assignment!(
170 DevtoolsBrowsingContextId,
171 || BrowsingContextId::new(),
172 |id_map: &mut IdMap, id| id_map.browsing_context_id(id)
173 );
174 test_sequential_id_assignment!(
175 DevtoolsOuterWindowId,
176 || PipelineId::new(),
177 |id_map: &mut IdMap, id| id_map.outer_window_id(id)
178 );
179 }
180}