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, ByteSymbol, Span, SpanDecoder, StableSourceFileId, Symbol, SyntaxContext,
20    def_id::{CrateNum, DefIndex},
21};
22
23use crate::{CrateMetadata, METADATA_HEADER, SYMBOL_OFFSET, SYMBOL_PREDEFINED, 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_PREDEFINED => {
115                let symbol_index = self.read_u32();
116                Symbol::new(symbol_index)
117            }
118            _ => unreachable!(),
119        }
120    }
121
122    fn decode_byte_symbol(&mut self) -> ByteSymbol {
123        ByteSymbol::intern(self.read_byte_str())
124    }
125}
126
127impl<'tcx> TyDecoder<'tcx> for DecodeContext<'_, 'tcx> {
128    const CLEAR_CROSS_CRATE: bool = true;
129
130    fn interner(&self) -> TyCtxt<'tcx> {
131        self.tcx
132    }
133
134    fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> ty::Ty<'tcx>
135    where
136        F: FnOnce(&mut Self) -> ty::Ty<'tcx>,
137    {
138        let tcx = self.tcx;
139
140        let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
141
142        if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
143            return ty;
144        }
145
146        let ty = or_insert_with(self);
147        // This may overwrite the entry, but it should overwrite with the same value.
148        tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty);
149        ty
150    }
151
152    fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
153    where
154        F: FnOnce(&mut Self) -> R,
155    {
156        let new_opaque = self.opaque.split_at(pos);
157        let old_opaque = mem::replace(&mut self.opaque, new_opaque);
158        let r = f(self);
159        self.opaque = old_opaque;
160        r
161    }
162
163    fn decode_alloc_id(&mut self) -> rustc_middle::mir::interpret::AllocId {
164        bug!("Encoding `interpret::AllocId` is not supported")
165    }
166}
167
168mod errors {
169    use std::{io, path::Path};
170
171    use flux_errors::E0999;
172    use flux_macros::Diagnostic;
173
174    #[derive(Diagnostic)]
175    #[diag(metadata_decode_file_error, code = E0999)]
176    pub(super) struct DecodeFileError<'a> {
177        path: &'a Path,
178        err: io::Error,
179    }
180
181    impl<'a> DecodeFileError<'a> {
182        pub(super) fn new(path: &'a Path, err: io::Error) -> Self {
183            Self { path, err }
184        }
185    }
186}