quil_rs/program/
source_map.rs

1use super::InstructionIndex;
2
3/// A SourceMap provides information necessary to understand which parts of a target
4/// were derived from which parts of a source artifact, in such a way that they can be
5/// mapped in either direction.
6///
7/// The behavior of such mappings depends on the implementations of the generic `Index` types,
8/// but this may be a many-to-many mapping, where one element of the source is mapped (contributes)
9/// to zero or many elements of the target, and vice versa.
10///
11/// This is also intended to be mergeable in a chain, such that the combined result of a series
12/// of transformations can be expressed within a single source mapping.
13#[derive(Clone, Debug, PartialEq)]
14pub struct SourceMap<SourceIndex, TargetIndex> {
15    pub(crate) entries: Vec<SourceMapEntry<SourceIndex, TargetIndex>>,
16}
17
18impl<SourceIndex, TargetIndex> SourceMap<SourceIndex, TargetIndex> {
19    /// Return all source ranges in the source map which were used to generate the target range.
20    ///
21    /// This is `O(n)` where `n` is the number of entries in the map.
22    pub fn list_sources<QueryIndex>(&self, target_index: &QueryIndex) -> Vec<&SourceIndex>
23    where
24        TargetIndex: SourceMapIndexable<QueryIndex>,
25    {
26        self.entries
27            .iter()
28            .filter_map(|entry| {
29                if entry.target_location().intersects(target_index) {
30                    Some(entry.source_location())
31                } else {
32                    None
33                }
34            })
35            .collect()
36    }
37
38    /// Return all target ranges in the source map which were used to generate the source range.
39    ///
40    /// This is `O(n)` where `n` is the number of entries in the map.
41    pub fn list_targets<QueryIndex>(&self, source_index: &QueryIndex) -> Vec<&TargetIndex>
42    where
43        SourceIndex: SourceMapIndexable<QueryIndex>,
44    {
45        self.entries
46            .iter()
47            .filter_map(|entry| {
48                if entry.source_location().intersects(source_index) {
49                    Some(entry.target_location())
50                } else {
51                    None
52                }
53            })
54            .collect()
55    }
56}
57
58impl<SourceIndex, TargetIndex> Default for SourceMap<SourceIndex, TargetIndex> {
59    fn default() -> Self {
60        Self {
61            entries: Vec::new(),
62        }
63    }
64}
65
66impl<SourceIndex, TargetIndex> SourceMap<SourceIndex, TargetIndex> {
67    pub fn entries(&self) -> &[SourceMapEntry<SourceIndex, TargetIndex>] {
68        &self.entries
69    }
70}
71
72#[derive(Clone, Debug, PartialEq)]
73pub struct SourceMapEntry<SourceIndex, TargetIndex> {
74    /// The locator within the source artifact
75    pub(crate) source_location: SourceIndex,
76
77    /// The locator within the target artifact
78    pub(crate) target_location: TargetIndex,
79}
80
81impl<SourceIndex, TargetIndex> SourceMapEntry<SourceIndex, TargetIndex> {
82    pub fn source_location(&self) -> &SourceIndex {
83        &self.source_location
84    }
85
86    pub fn target_location(&self) -> &TargetIndex {
87        &self.target_location
88    }
89}
90
91/// A trait for types which can be used as lookup indices in a `SourceMap.`
92pub trait SourceMapIndexable<Index> {
93    /// Return `true` if a source or target index intersects `other`.
94    fn intersects(&self, other: &Index) -> bool;
95}
96
97impl SourceMapIndexable<InstructionIndex> for InstructionIndex {
98    fn intersects(&self, other: &InstructionIndex) -> bool {
99        self == other
100    }
101}