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