]> git.lizzy.rs Git - rust.git/blob - src/librustc_metadata/isolated_encoder.rs
Alias std::cmp::max/min to Ord::max/min
[rust.git] / src / librustc_metadata / isolated_encoder.rs
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.
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
11 use encoder::EncodeContext;
12 use schema::{Lazy, LazySeq};
13
14 use rustc::ich::{StableHashingContext, Fingerprint};
15 use rustc::ty::TyCtxt;
16
17 use rustc_data_structures::accumulate_vec::AccumulateVec;
18 use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
19 use rustc_serialize::Encodable;
20
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>)>,
27 }
28
29 impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
30
31     pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self {
32         let tcx = ecx.tcx;
33         let compute_ich = ecx.compute_ich;
34         IsolatedEncoder {
35             tcx: tcx,
36             ecx: ecx,
37             hcx: if 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)
44                 } else {
45                     StableHashingContext::new(tcx).force_span_hashing()
46                 };
47
48                 Some((hcx, StableHasher::new()))
49             } else {
50                 None
51             }
52         }
53     }
54
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)
58         } else {
59             (None, self.ecx)
60         }
61     }
62
63     pub fn lazy<T>(&mut self, value: &T) -> Lazy<T>
64         where T: Encodable + HashStable<StableHashingContext<'b, 'tcx>>
65     {
66         if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
67             value.hash_stable(hcx, hasher);
68             debug!("metadata-hash: {:?}", hasher);
69         }
70         self.ecx.lazy(value)
71     }
72
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>>
76     {
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();
80
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;
87                 }));
88
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
92                 // it by accident.
93                 if lower_bound != num_items_hashed {
94                     bug!("Hashed a different number of items ({}) than expected ({})",
95                          num_items_hashed,
96                          lower_bound);
97                 }
98                 debug!("metadata-hash: {:?}", hasher);
99                 ret
100             } else {
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)
106             }
107         } else {
108             self.ecx.lazy_seq(iter)
109         }
110     }
111
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>>
115     {
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();
119
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;
126                 }));
127
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
131                 // it by accident.
132                 if lower_bound != num_items_hashed {
133                     bug!("Hashed a different number of items ({}) than expected ({})",
134                          num_items_hashed,
135                          lower_bound);
136                 }
137                 debug!("metadata-hash: {:?}", hasher);
138                 ret
139             } else {
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))
145             }
146         } else {
147             self.ecx.lazy_seq_ref(iter)
148         }
149     }
150
151     pub fn lazy_seq_from_slice<T>(&mut self, slice: &[T]) -> LazySeq<T>
152         where T: Encodable + HashStable<StableHashingContext<'b, 'tcx>>
153     {
154         if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
155             slice.hash_stable(hcx, hasher);
156             debug!("metadata-hash: {:?}", hasher);
157         }
158         self.ecx.lazy_seq_ref(slice.iter())
159     }
160
161     pub fn lazy_seq_ref_from_slice<T>(&mut self, slice: &[&T]) -> LazySeq<T>
162         where T: Encodable + HashStable<StableHashingContext<'b, 'tcx>>
163     {
164         if let Some((ref mut hcx, ref mut hasher)) = self.hcx {
165             slice.hash_stable(hcx, hasher);
166             debug!("metadata-hash: {:?}", hasher);
167         }
168         self.ecx.lazy_seq_ref(slice.iter().map(|x| *x))
169     }
170 }