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