aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/trace.rs
blob: fc26f5a48653f202bb12a272c8a84543aa0d898c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//! Trace is a pretty niche data structure which is used when lowering a CST
//! into HIR.
//!
//! Lowering process calculates two bits of information:
//! * the lowered syntax itself
//! * a mapping between lowered syntax and original syntax
//!
//! Due to the way salsa works, the mapping is usually hot lava, as it contains
//! absolute offsets. The `Trace` structure (inspired, at least in name, by
//! Kotlin's `BindingTrace`) allows use the same code to compute both
//! projections.
use ra_arena::{map::ArenaMap, Arena, ArenaId, RawId};

pub(crate) struct Trace<ID: ArenaId, T, V> {
    for_arena: bool,
    arena: Arena<ID, T>,
    map: ArenaMap<ID, V>,
    len: u32,
}

impl<ID: ra_arena::ArenaId, T, V> Trace<ID, T, V> {
    pub(crate) fn new_for_arena() -> Trace<ID, T, V> {
        Trace { for_arena: true, arena: Arena::default(), map: ArenaMap::default(), len: 0 }
    }

    pub(crate) fn new_for_map() -> Trace<ID, T, V> {
        Trace { for_arena: false, arena: Arena::default(), map: ArenaMap::default(), len: 0 }
    }

    pub(crate) fn alloc(&mut self, value: impl Fn() -> V, data: impl Fn() -> T) {
        if self.for_arena {
            self.arena.alloc(data());
        } else {
            let id = ID::from_raw(RawId::from(self.len));
            self.len += 1;
            self.map.insert(id, value());
        }
    }

    pub(crate) fn into_arena(self) -> Arena<ID, T> {
        assert!(self.for_arena);
        self.arena
    }

    pub(crate) fn into_map(self) -> ArenaMap<ID, V> {
        assert!(!self.for_arena);
        self.map
    }
}