devtools/
id.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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}