]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
b039eaaf SL |
11 | use middle::def_id::{DefId, DefIndex}; |
12 | use rbml; | |
e9174d1e SL |
13 | use std::io::{Cursor, Write}; |
14 | use std::slice; | |
15 | use std::u32; | |
e9174d1e | 16 | |
b039eaaf SL |
17 | /// As part of the metadata, we generate an index that stores, for |
18 | /// each DefIndex, the position of the corresponding RBML document (if | |
19 | /// any). This is just a big `[u32]` slice, where an entry of | |
20 | /// `u32::MAX` indicates that there is no RBML document. This little | |
21 | /// struct just stores the offsets within the metadata of the start | |
22 | /// and end of this slice. These are actually part of an RBML | |
23 | /// document, but for looking things up in the metadata, we just | |
24 | /// discard the RBML positioning and jump directly to the data. | |
25 | pub struct Index { | |
26 | data_start: usize, | |
27 | data_end: usize, | |
e9174d1e SL |
28 | } |
29 | ||
b039eaaf SL |
30 | impl Index { |
31 | /// Given the RBML doc representing the index, save the offests | |
32 | /// for later. | |
33 | pub fn from_rbml(index: rbml::Doc) -> Index { | |
34 | Index { data_start: index.start, data_end: index.end } | |
e9174d1e SL |
35 | } |
36 | ||
b039eaaf SL |
37 | /// Given the metadata, extract out the offset of a particular |
38 | /// DefIndex (if any). | |
39 | #[inline(never)] | |
40 | pub fn lookup_item(&self, bytes: &[u8], def_index: DefIndex) -> Option<u32> { | |
41 | let words = bytes_to_words(&bytes[self.data_start..self.data_end]); | |
42 | let index = def_index.as_usize(); | |
43 | ||
44 | debug!("lookup_item: index={:?} words.len={:?}", | |
45 | index, words.len()); | |
46 | ||
47 | let position = u32::from_be(words[index]); | |
48 | if position == u32::MAX { | |
49 | debug!("lookup_item: position=u32::MAX"); | |
50 | None | |
51 | } else { | |
52 | debug!("lookup_item: position={:?}", position); | |
53 | Some(position) | |
e9174d1e SL |
54 | } |
55 | } | |
56 | } | |
57 | ||
b039eaaf SL |
58 | /// While we are generating the metadata, we also track the position |
59 | /// of each DefIndex. It is not required that all definitions appear | |
60 | /// in the metadata, nor that they are serialized in order, and | |
61 | /// therefore we first allocate the vector here and fill it with | |
62 | /// `u32::MAX`. Whenever an index is visited, we fill in the | |
63 | /// appropriate spot by calling `record_position`. We should never | |
64 | /// visit the same index twice. | |
65 | pub struct IndexData { | |
66 | positions: Vec<u32>, | |
e9174d1e SL |
67 | } |
68 | ||
b039eaaf SL |
69 | impl IndexData { |
70 | pub fn new(max_index: usize) -> IndexData { | |
71 | IndexData { | |
72 | positions: vec![u32::MAX; max_index] | |
73 | } | |
74 | } | |
75 | ||
76 | pub fn record(&mut self, def_id: DefId, position: u64) { | |
77 | assert!(def_id.is_local()); | |
78 | self.record_index(def_id.index, position) | |
79 | } | |
80 | ||
81 | pub fn record_index(&mut self, item: DefIndex, position: u64) { | |
82 | let item = item.as_usize(); | |
83 | ||
84 | assert!(position < (u32::MAX as u64)); | |
85 | let position = position as u32; | |
e9174d1e | 86 | |
b039eaaf SL |
87 | assert!(self.positions[item] == u32::MAX, |
88 | "recorded position for item {:?} twice, first at {:?} and now at {:?}", | |
89 | item, self.positions[item], position); | |
e9174d1e | 90 | |
b039eaaf | 91 | self.positions[item] = position; |
e9174d1e SL |
92 | } |
93 | ||
b039eaaf SL |
94 | pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) { |
95 | for &position in &self.positions { | |
96 | write_be_u32(buf, position); | |
e9174d1e | 97 | } |
e9174d1e | 98 | } |
b039eaaf | 99 | } |
e9174d1e | 100 | |
b039eaaf SL |
101 | /// A dense index with integer keys. Different API from IndexData (should |
102 | /// these be merged?) | |
103 | pub struct DenseIndex { | |
104 | start: usize, | |
105 | end: usize | |
e9174d1e SL |
106 | } |
107 | ||
b039eaaf SL |
108 | impl DenseIndex { |
109 | pub fn lookup(&self, buf: &[u8], ix: u32) -> Option<u32> { | |
110 | let data = bytes_to_words(&buf[self.start..self.end]); | |
111 | data.get(ix as usize).map(|d| u32::from_be(*d)) | |
112 | } | |
113 | pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self { | |
114 | assert!((end-start)%4 == 0 && start <= end && end <= buf.len()); | |
115 | DenseIndex { | |
116 | start: start, | |
117 | end: end | |
e9174d1e SL |
118 | } |
119 | } | |
b039eaaf | 120 | } |
e9174d1e | 121 | |
b039eaaf SL |
122 | pub fn write_dense_index(entries: Vec<u32>, buf: &mut Cursor<Vec<u8>>) { |
123 | let elen = entries.len(); | |
124 | assert!(elen < u32::MAX as usize); | |
e9174d1e | 125 | |
b039eaaf SL |
126 | for entry in entries { |
127 | write_be_u32(buf, entry); | |
e9174d1e SL |
128 | } |
129 | ||
b039eaaf | 130 | info!("write_dense_index: {} entries", elen); |
e9174d1e SL |
131 | } |
132 | ||
133 | fn write_be_u32<W: Write>(w: &mut W, u: u32) { | |
134 | let _ = w.write_all(&[ | |
135 | (u >> 24) as u8, | |
136 | (u >> 16) as u8, | |
137 | (u >> 8) as u8, | |
138 | (u >> 0) as u8, | |
139 | ]); | |
140 | } | |
141 | ||
142 | fn bytes_to_words(b: &[u8]) -> &[u32] { | |
143 | assert!(b.len() % 4 == 0); | |
144 | unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) } | |
145 | } |