blob: b850073462f5a87a2e666825897d236dce6ded35 [file] [log] [blame]
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::hir::def_id::{DefId, DefIndex};
use rbml;
use std::io::{Cursor, Write};
use std::slice;
use std::u32;
/// As part of the metadata, we generate an index that stores, for
/// each DefIndex, the position of the corresponding RBML document (if
/// any). This is just a big `[u32]` slice, where an entry of
/// `u32::MAX` indicates that there is no RBML document. This little
/// struct just stores the offsets within the metadata of the start
/// and end of this slice. These are actually part of an RBML
/// document, but for looking things up in the metadata, we just
/// discard the RBML positioning and jump directly to the data.
pub struct Index {
data_start: usize,
data_end: usize,
}
impl Index {
/// Given the RBML doc representing the index, save the offests
/// for later.
pub fn from_rbml(index: rbml::Doc) -> Index {
Index { data_start: index.start, data_end: index.end }
}
/// Given the metadata, extract out the offset of a particular
/// DefIndex (if any).
#[inline(never)]
pub fn lookup_item(&self, bytes: &[u8], def_index: DefIndex) -> Option<u32> {
let words = bytes_to_words(&bytes[self.data_start..self.data_end]);
let index = def_index.as_usize();
debug!("lookup_item: index={:?} words.len={:?}",
index, words.len());
let position = u32::from_be(words[index]);
if position == u32::MAX {
debug!("lookup_item: position=u32::MAX");
None
} else {
debug!("lookup_item: position={:?}", position);
Some(position)
}
}
}
/// While we are generating the metadata, we also track the position
/// of each DefIndex. It is not required that all definitions appear
/// in the metadata, nor that they are serialized in order, and
/// therefore we first allocate the vector here and fill it with
/// `u32::MAX`. Whenever an index is visited, we fill in the
/// appropriate spot by calling `record_position`. We should never
/// visit the same index twice.
pub struct IndexData {
positions: Vec<u32>,
}
impl IndexData {
pub fn new(max_index: usize) -> IndexData {
IndexData {
positions: vec![u32::MAX; max_index]
}
}
pub fn record(&mut self, def_id: DefId, position: u64) {
assert!(def_id.is_local());
self.record_index(def_id.index, position);
}
pub fn record_index(&mut self, item: DefIndex, position: u64) {
let item = item.as_usize();
assert!(position < (u32::MAX as u64));
let position = position as u32;
assert!(self.positions[item] == u32::MAX,
"recorded position for item {:?} twice, first at {:?} and now at {:?}",
item, self.positions[item], position);
self.positions[item] = position;
}
pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) {
for &position in &self.positions {
write_be_u32(buf, position);
}
}
}
/// A dense index with integer keys. Different API from IndexData (should
/// these be merged?)
pub struct DenseIndex {
start: usize,
end: usize
}
impl DenseIndex {
pub fn lookup(&self, buf: &[u8], ix: u32) -> Option<u32> {
let data = bytes_to_words(&buf[self.start..self.end]);
data.get(ix as usize).map(|d| u32::from_be(*d))
}
pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self {
assert!((end-start)%4 == 0 && start <= end && end <= buf.len());
DenseIndex {
start: start,
end: end
}
}
}
pub fn write_dense_index(entries: Vec<u32>, buf: &mut Cursor<Vec<u8>>) {
let elen = entries.len();
assert!(elen < u32::MAX as usize);
for entry in entries {
write_be_u32(buf, entry);
}
info!("write_dense_index: {} entries", elen);
}
fn write_be_u32<W: Write>(w: &mut W, u: u32) {
let _ = w.write_all(&[
(u >> 24) as u8,
(u >> 16) as u8,
(u >> 8) as u8,
(u >> 0) as u8,
]);
}
fn bytes_to_words(b: &[u8]) -> &[u32] {
assert!(b.len() % 4 == 0);
unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) }
}