1 // Copyright 2017 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.
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.
11 use encoder::EncodeContext;
12 use schema::{Lazy, LazySeq};
14 use rustc::ich::{StableHashingContext, Fingerprint};
15 use rustc::ty::TyCtxt;
17 use rustc_data_structures::accumulate_vec::AccumulateVec;
18 use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
19 use rustc_serialize::Encodable;
21 /// The IsolatedEncoder provides facilities to write to crate metadata while
22 /// making sure that anything going through it is also feed into an ICH hasher.
23 pub struct IsolatedEncoder<'a, 'b: 'a, 'tcx: 'b> {
24 pub tcx: TyCtxt<'b, 'tcx, 'tcx>,
25 ecx: &'a mut EncodeContext<'b, 'tcx>,
26 hcx: Option<(StableHashingContext<'b, 'tcx>, StableHasher<Fingerprint>)>,
29 impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
31 pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self {
33 let compute_ich = ecx.compute_ich;
38 // We are always hashing spans for things in metadata because
39 // don't know if a downstream crate will use them or not.
40 // Except when -Zquery-dep-graph is specified because we don't
41 // want to mess up our tests.
42 let hcx = if tcx.sess.opts.debugging_opts.query_dep_graph {
43 StableHashingContext::new(tcx)
45 StableHashingContext::new(tcx).force_span_hashing()
48 Some((hcx, StableHasher::new()))
55 pub fn finish(self) -> (Option<Fingerprint>, &'a mut EncodeContext<'b, 'tcx>) {
56 if let Some((_, hasher)) = self.hcx {
57 (Some(hasher.finish()), self.ecx)
63 pub fn lazy<T>(&mut self, value: &T) -> Lazy<T>
64 where T: Encodable + HashStable<StableHashingContext<'b, 'tcx>>
66 if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
67 value.hash_stable(hcx, hasher);
68 debug!("metadata-hash: {:?}", hasher);
73 pub fn lazy_seq<I, T>(&mut self, iter: I) -> LazySeq<T>
74 where I: IntoIterator<Item = T>,
75 T: Encodable + HashStable<StableHashingContext<'b, 'tcx>>
77 if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
78 let iter = iter.into_iter();
79 let (lower_bound, upper_bound) = iter.size_hint();
81 if upper_bound == Some(lower_bound) {
82 lower_bound.hash_stable(hcx, hasher);
83 let mut num_items_hashed = 0;
84 let ret = self.ecx.lazy_seq(iter.inspect(|item| {
85 item.hash_stable(hcx, hasher);
86 num_items_hashed += 1;
89 // Sometimes items in a sequence are filtered out without being
90 // hashed (e.g. for &[ast::Attribute]) and this code path cannot
91 // handle that correctly, so we want to make sure we didn't hit
93 if lower_bound != num_items_hashed {
94 bug!("Hashed a different number of items ({}) than expected ({})",
98 debug!("metadata-hash: {:?}", hasher);
101 // Collect into a vec so we know the length of the sequence
102 let items: AccumulateVec<[T; 32]> = iter.collect();
103 items.hash_stable(hcx, hasher);
104 debug!("metadata-hash: {:?}", hasher);
105 self.ecx.lazy_seq(items)
108 self.ecx.lazy_seq(iter)
112 pub fn lazy_seq_ref<'x, I, T>(&mut self, iter: I) -> LazySeq<T>
113 where I: IntoIterator<Item = &'x T>,
114 T: 'x + Encodable + HashStable<StableHashingContext<'b, 'tcx>>
116 if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
117 let iter = iter.into_iter();
118 let (lower_bound, upper_bound) = iter.size_hint();
120 if upper_bound == Some(lower_bound) {
121 lower_bound.hash_stable(hcx, hasher);
122 let mut num_items_hashed = 0;
123 let ret = self.ecx.lazy_seq_ref(iter.inspect(|item| {
124 item.hash_stable(hcx, hasher);
125 num_items_hashed += 1;
128 // Sometimes items in a sequence are filtered out without being
129 // hashed (e.g. for &[ast::Attribute]) and this code path cannot
130 // handle that correctly, so we want to make sure we didn't hit
132 if lower_bound != num_items_hashed {
133 bug!("Hashed a different number of items ({}) than expected ({})",
137 debug!("metadata-hash: {:?}", hasher);
140 // Collect into a vec so we know the length of the sequence
141 let items: AccumulateVec<[&'x T; 32]> = iter.collect();
142 items.hash_stable(hcx, hasher);
143 debug!("metadata-hash: {:?}", hasher);
144 self.ecx.lazy_seq_ref(items.iter().map(|x| *x))
147 self.ecx.lazy_seq_ref(iter)
151 pub fn lazy_seq_from_slice<T>(&mut self, slice: &[T]) -> LazySeq<T>
152 where T: Encodable + HashStable<StableHashingContext<'b, 'tcx>>
154 if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
155 slice.hash_stable(hcx, hasher);
156 debug!("metadata-hash: {:?}", hasher);
158 self.ecx.lazy_seq_ref(slice.iter())
161 pub fn lazy_seq_ref_from_slice<T>(&mut self, slice: &[&T]) -> LazySeq<T>
162 where T: Encodable + HashStable<StableHashingContext<'b, 'tcx>>
164 if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
165 slice.hash_stable(hcx, hasher);
166 debug!("metadata-hash: {:?}", hasher);
168 self.ecx.lazy_seq_ref(slice.iter().map(|x| *x))