flux_metadata/
decoder.rs

1use std::{
2    fs,
3    io::{self, Read},
4    mem,
5    path::Path,
6};
7
8use flux_common::bug;
9use flux_errors::FluxSession;
10use rustc_data_structures::sync::HashMapExt;
11use rustc_hir::def_id::DefId;
12use rustc_middle::{
13    implement_ty_decoder,
14    ty::{self, TyCtxt},
15};
16use rustc_serialize::{Decodable, Decoder as _, opaque::MemDecoder};
17use rustc_session::StableCrateId;
18use rustc_span::{
19    BytePos, Span, SpanDecoder, StableSourceFileId, Symbol, SyntaxContext,
20    def_id::{CrateNum, DefIndex},
21};
22use rustc_type_ir::TyDecoder;
23
24use crate::{CrateMetadata, METADATA_HEADER, SYMBOL_OFFSET, SYMBOL_PREINTERNED, SYMBOL_STR};
25
26struct DecodeContext<'a, 'tcx> {
27    tcx: TyCtxt<'tcx>,
28    opaque: MemDecoder<'a>,
29}
30
31pub(super) fn decode_crate_metadata(
32    tcx: TyCtxt,
33    sess: &FluxSession,
34    path: &Path,
35) -> Option<CrateMetadata> {
36    let mut file = match fs::File::open(path) {
37        Ok(file) => file,
38        Err(err) if let io::ErrorKind::NotFound = err.kind() => return None,
39        Err(err) => sess.emit_fatal(errors::DecodeFileError::new(path, err)),
40    };
41    let mut buf = vec![];
42    file.read_to_end(&mut buf)
43        .unwrap_or_else(|err| sess.emit_fatal(errors::DecodeFileError::new(path, err)));
44
45    if !buf.starts_with(METADATA_HEADER) {
46        bug!("incompatible metadata version");
47    }
48
49    let mut decoder =
50        DecodeContext { tcx, opaque: MemDecoder::new(&buf, METADATA_HEADER.len()).unwrap() };
51    Some(CrateMetadata::decode(&mut decoder))
52}
53
54implement_ty_decoder!(DecodeContext<'a, 'tcx>);
55
56impl SpanDecoder for DecodeContext<'_, '_> {
57    fn decode_attr_id(&mut self) -> rustc_ast::AttrId {
58        self.tcx.sess.psess.attr_id_generator.mk_attr_id()
59    }
60
61    fn decode_crate_num(&mut self) -> CrateNum {
62        let stable_id = StableCrateId::decode(self);
63        self.tcx.stable_crate_id_to_crate_num(stable_id)
64    }
65
66    fn decode_def_index(&mut self) -> DefIndex {
67        DefIndex::from_u32(self.read_u32())
68    }
69
70    fn decode_def_id(&mut self) -> DefId {
71        DefId { krate: Decodable::decode(self), index: Decodable::decode(self) }
72    }
73
74    fn decode_syntax_context(&mut self) -> rustc_span::SyntaxContext {
75        bug!("cannot decode `SyntaxContext` with `DecodeContext`");
76    }
77
78    fn decode_expn_id(&mut self) -> rustc_span::ExpnId {
79        bug!("cannot decode `ExpnId` with `DecodeContext`");
80    }
81
82    fn decode_span(&mut self) -> rustc_span::Span {
83        let sm = self.tcx.sess.source_map();
84        let pos = [(); 2].map(|_| {
85            let ssfi = StableSourceFileId::decode(self);
86            let rel_bp = BytePos::decode(self);
87            // See comment in 'encoder.rs'
88            //
89            // This should hopefully never fail,
90            // so maybe could be an `unwrap` instead?
91            sm.source_file_by_stable_id(ssfi)
92                .map_or(BytePos(0), |sf| sf.start_pos + rel_bp)
93        });
94        Span::new(pos[0], pos[1], SyntaxContext::root(), None)
95    }
96
97    fn decode_symbol(&mut self) -> rustc_span::Symbol {
98        let tag = self.read_u8();
99
100        match tag {
101            SYMBOL_STR => {
102                let s = self.read_str();
103                Symbol::intern(s)
104            }
105            SYMBOL_OFFSET => {
106                // read str offset
107                let pos = self.read_usize();
108
109                // move to str offset and read
110                self.opaque.with_position(pos, |d| {
111                    let s = d.read_str();
112                    Symbol::intern(s)
113                })
114            }
115            SYMBOL_PREINTERNED => {
116                let symbol_index = self.read_u32();
117                Symbol::new_from_decoded(symbol_index)
118            }
119            _ => unreachable!(),
120        }
121    }
122}
123
124impl<'tcx> TyDecoder for DecodeContext<'_, 'tcx> {
125    type I = TyCtxt<'tcx>;
126
127    const CLEAR_CROSS_CRATE: bool = true;
128
129    fn interner(&self) -> Self::I {
130        self.tcx
131    }
132
133    fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> ty::Ty<'tcx>
134    where
135        F: FnOnce(&mut Self) -> ty::Ty<'tcx>,
136    {
137        let tcx = self.tcx;
138
139        let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
140
141        if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
142            return ty;
143        }
144
145        let ty = or_insert_with(self);
146        // This may overwrite the entry, but it should overwrite with the same value.
147        tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty);
148        ty
149    }
150
151    fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
152    where
153        F: FnOnce(&mut Self) -> R,
154    {
155        let new_opaque = self.opaque.split_at(pos);
156        let old_opaque = mem::replace(&mut self.opaque, new_opaque);
157        let r = f(self);
158        self.opaque = old_opaque;
159        r
160    }
161
162    fn decode_alloc_id(&mut self) -> rustc_middle::mir::interpret::AllocId {
163        bug!("Encoding `interpret::AllocId` is not supported")
164    }
165}
166
167mod errors {
168    use std::{io, path::Path};
169
170    use flux_errors::E0999;
171    use flux_macros::Diagnostic;
172
173    #[derive(Diagnostic)]
174    #[diag(metadata_decode_file_error, code = E0999)]
175    pub(super) struct DecodeFileError<'a> {
176        path: &'a Path,
177        err: io::Error,
178    }
179
180    impl<'a> DecodeFileError<'a> {
181        pub(super) fn new(path: &'a Path, err: io::Error) -> Self {
182            Self { path, err }
183        }
184    }
185}