3 use rustc::hir::def_id::{DefId, DefIndex};
4 use rustc_serialize::opaque::Encoder;
8 /// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
9 pub trait FixedSizeEncoding {
10 const BYTE_LEN: usize;
12 // FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
13 // once that starts being allowed by the compiler (i.e. lazy normalization).
14 fn from_bytes(b: &[u8]) -> Self;
15 fn write_to_bytes(self, b: &mut [u8]);
17 // FIXME(eddyb) make these generic functions, or at least defaults here.
18 // (same problem as above, needs `[u8; Self::BYTE_LEN]`)
19 // For now, a macro (`fixed_size_encoding_byte_len_and_defaults`) is used.
20 fn read_from_bytes_at(b: &[u8], i: usize) -> Self;
21 fn write_to_bytes_at(self, b: &mut [u8], i: usize);
24 // HACK(eddyb) this shouldn't be needed (see comments on the methods above).
25 macro_rules! fixed_size_encoding_byte_len_and_defaults {
27 const BYTE_LEN: usize = $byte_len;
28 fn read_from_bytes_at(b: &[u8], i: usize) -> Self {
29 const BYTE_LEN: usize = $byte_len;
30 // HACK(eddyb) ideally this would be done with fully safe code,
31 // but slicing `[u8]` with `i * N..` is optimized worse, due to the
32 // possibility of `i * N` overflowing, than indexing `[[u8; N]]`.
34 std::slice::from_raw_parts(
35 b.as_ptr() as *const [u8; BYTE_LEN],
39 Self::from_bytes(&b[i])
41 fn write_to_bytes_at(self, b: &mut [u8], i: usize) {
42 const BYTE_LEN: usize = $byte_len;
43 // HACK(eddyb) ideally this would be done with fully safe code,
44 // see similar comment in `read_from_bytes_at` for why it can't yet.
46 std::slice::from_raw_parts_mut(
47 b.as_mut_ptr() as *mut [u8; BYTE_LEN],
51 self.write_to_bytes(&mut b[i]);
56 impl FixedSizeEncoding for u32 {
57 fixed_size_encoding_byte_len_and_defaults!(4);
59 fn from_bytes(b: &[u8]) -> Self {
60 let mut bytes = [0; Self::BYTE_LEN];
61 bytes.copy_from_slice(&b[..Self::BYTE_LEN]);
62 Self::from_le_bytes(bytes)
65 fn write_to_bytes(self, b: &mut [u8]) {
66 b[..Self::BYTE_LEN].copy_from_slice(&self.to_le_bytes());
70 /// While we are generating the metadata, we also track the position
71 /// of each DefIndex. It is not required that all definitions appear
72 /// in the metadata, nor that they are serialized in order, and
73 /// therefore we first allocate the vector here and fill it with
74 /// `u32::MAX`. Whenever an index is visited, we fill in the
75 /// appropriate spot by calling `record_position`. We should never
76 /// visit the same index twice.
82 pub fn new(max_index: usize) -> Index {
84 positions: vec![0xff; max_index * 4],
88 pub fn record(&mut self, def_id: DefId, entry: Lazy<Entry<'_>>) {
89 assert!(def_id.is_local());
90 self.record_index(def_id.index, entry);
93 pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry<'_>>) {
94 assert!(entry.position < (u32::MAX as usize));
95 let position = entry.position as u32;
96 let array_index = item.as_array_index();
98 let positions = &mut self.positions;
99 assert!(u32::read_from_bytes_at(positions, array_index) == u32::MAX,
100 "recorded position for item {:?} twice, first at {:?} and now at {:?}",
102 u32::read_from_bytes_at(positions, array_index),
105 position.write_to_bytes_at(positions, array_index)
108 pub fn write_index(&self, buf: &mut Encoder) -> LazySeq<Index> {
109 let pos = buf.position();
111 // First we write the length of the lower range ...
112 buf.emit_raw_bytes(&(self.positions.len() as u32 / 4).to_le_bytes());
113 // ... then the values.
114 buf.emit_raw_bytes(&self.positions);
115 LazySeq::with_position_and_length(pos as usize, self.positions.len() / 4 + 1)
119 impl<'tcx> LazySeq<Index> {
120 /// Given the metadata, extract out the offset of a particular
121 /// DefIndex (if any).
123 pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
124 let bytes = &bytes[self.position..];
125 debug!("Index::lookup: index={:?} len={:?}",
129 let position = u32::read_from_bytes_at(bytes, 1 + def_index.as_array_index());
130 if position == u32::MAX {
131 debug!("Index::lookup: position=u32::MAX");
134 debug!("Index::lookup: position={:?}", position);
135 Some(Lazy::with_position(position as usize))