quil_rs/program/
source_map.rs

1use std::fmt::Debug;
2
3use crate::instruction::GateSignature;
4
5use super::{CalibrationSource, InstructionIndex};
6
7/// A `SourceMap` provides information necessary to understand which parts of a target
8/// were derived from which parts of a source artifact, in such a way that they can be
9/// mapped in either direction.
10///
11/// The behavior of such mappings depends on the implementations of the generic `Index` types,
12/// but this may be a many-to-many mapping, where one element of the source is mapped (contributes)
13/// to zero or many elements of the target, and vice versa.
14///
15/// This is also intended to be mergeable in a chain, such that the combined result of a series
16/// of transformations can be expressed within a single source mapping.
17#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct SourceMap<SourceIndex, TargetIndex> {
19    pub(crate) entries: Vec<SourceMapEntry<SourceIndex, TargetIndex>>,
20}
21
22impl<SourceIndex, TargetIndex> SourceMap<SourceIndex, TargetIndex> {
23    pub fn new(entries: Vec<SourceMapEntry<SourceIndex, TargetIndex>>) -> Self {
24        Self { entries }
25    }
26
27    /// Return all source ranges in the source map which were used to generate the target range.
28    ///
29    /// This is `O(n)` where `n` is the number of entries in the map.
30    pub fn list_sources<QueryIndex>(&self, target_index: &QueryIndex) -> Vec<&SourceIndex>
31    where
32        TargetIndex: SourceMapIndexable<QueryIndex>,
33    {
34        self.entries
35            .iter()
36            .filter(|&entry| entry.target_location().contains(target_index))
37            .map(SourceMapEntry::source_location)
38            .collect()
39    }
40
41    /// Return all target ranges in the source map which were used to generate the source range.
42    ///
43    /// This is `O(n)` where `n` is the number of entries in the map.
44    pub fn list_targets<QueryIndex>(&self, source_index: &QueryIndex) -> Vec<&TargetIndex>
45    where
46        SourceIndex: SourceMapIndexable<QueryIndex>,
47    {
48        self.entries
49            .iter()
50            .filter(|entry| entry.source_location().contains(source_index))
51            .map(SourceMapEntry::target_location)
52            .collect()
53    }
54}
55
56impl<SourceIndex, TargetIndex> Default for SourceMap<SourceIndex, TargetIndex> {
57    fn default() -> Self {
58        Self {
59            entries: Vec::new(),
60        }
61    }
62}
63
64impl<SourceIndex, TargetIndex> SourceMap<SourceIndex, TargetIndex> {
65    pub fn entries(&self) -> &[SourceMapEntry<SourceIndex, TargetIndex>] {
66        &self.entries
67    }
68}
69
70#[derive(Clone, Debug, PartialEq, Eq)]
71pub struct SourceMapEntry<SourceIndex, TargetIndex> {
72    /// The locator within the source artifact
73    pub(crate) source_location: SourceIndex,
74
75    /// The locator within the target artifact
76    pub(crate) target_location: TargetIndex,
77}
78
79impl<SourceIndex, TargetIndex> SourceMapEntry<SourceIndex, TargetIndex> {
80    pub fn new(source_location: SourceIndex, target_location: TargetIndex) -> Self {
81        Self {
82            source_location,
83            target_location,
84        }
85    }
86
87    pub fn source_location(&self) -> &SourceIndex {
88        &self.source_location
89    }
90
91    pub fn target_location(&self) -> &TargetIndex {
92        &self.target_location
93    }
94}
95
96/// A trait for types which can be used as lookup indices in a `SourceMap.`
97pub trait SourceMapIndexable<Index> {
98    /// Return `true` if `self` contains or is equal to `other`.
99    fn contains(&self, other: &Index) -> bool;
100}
101
102impl SourceMapIndexable<InstructionIndex> for InstructionIndex {
103    fn contains(&self, other: &InstructionIndex) -> bool {
104        self == other
105    }
106}
107
108#[derive(Clone, Debug, PartialEq)]
109pub enum ExpansionResult<R> {
110    Unmodified(InstructionIndex),
111    Rewritten(R),
112}
113
114impl<R> SourceMapIndexable<InstructionIndex> for ExpansionResult<R>
115where
116    R: SourceMapIndexable<InstructionIndex>,
117{
118    fn contains(&self, other: &InstructionIndex) -> bool {
119        match self {
120            Self::Unmodified(index) => index == other,
121            Self::Rewritten(rewrite) => rewrite.contains(other),
122        }
123    }
124}
125
126impl<R> SourceMapIndexable<CalibrationSource> for ExpansionResult<R>
127where
128    R: SourceMapIndexable<CalibrationSource>,
129{
130    fn contains(&self, other: &CalibrationSource) -> bool {
131        if let Self::Rewritten(rewrite) = self {
132            rewrite.contains(other)
133        } else {
134            false
135        }
136    }
137}
138
139impl<'a, R> SourceMapIndexable<GateSignature<'a>> for ExpansionResult<R>
140where
141    R: SourceMapIndexable<GateSignature<'a>>,
142{
143    fn contains(&self, other: &GateSignature<'a>) -> bool {
144        if let Self::Rewritten(rewrite) = self {
145            rewrite.contains(other)
146        } else {
147            false
148        }
149    }
150}