Coverage Report

Created: 2026-10-28 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/oxc_sourcemap-9.0.0/src/token.rs
Line
Count
Source
1
use crate::SourceMap;
2
3
/// Sentinel value representing an invalid/missing ID for source or name.
4
/// Used when a token doesn't have an associated source file or name.
5
pub(crate) const INVALID_ID: u32 = u32::MAX;
6
7
/// The `Token` is used to generate vlq `mappings`.
8
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
9
pub struct Token {
10
    pub(crate) dst_line: u32,
11
    pub(crate) dst_col: u32,
12
    pub(crate) src_line: u32,
13
    pub(crate) src_col: u32,
14
    source_id: u32,
15
    name_id: u32,
16
}
17
18
impl Token {
19
0
    pub fn new(
20
0
        dst_line: u32,
21
0
        dst_col: u32,
22
0
        src_line: u32,
23
0
        src_col: u32,
24
0
        source_id: Option<u32>,
25
0
        name_id: Option<u32>,
26
0
    ) -> Self {
27
0
        Self {
28
0
            dst_line,
29
0
            dst_col,
30
0
            src_line,
31
0
            src_col,
32
0
            source_id: source_id.unwrap_or(INVALID_ID),
33
0
            name_id: name_id.unwrap_or(INVALID_ID),
34
0
        }
35
0
    }
36
37
    /// Translate this token for a concatenated source map: shift the generated line by
38
    /// `line_offset` and renumber the source/name ids by `source_offset` / `name_offset`,
39
    /// preserving the missing-id sentinel. Operates on the raw ids so there is no `Option`
40
    /// round-trip in the concat hot loop.
41
    #[inline]
42
0
    pub(crate) fn translated(self, line_offset: u32, source_offset: u32, name_offset: u32) -> Self {
43
0
        let shift = |id: u32, offset: u32| if id == INVALID_ID { INVALID_ID } else { id + offset };
44
0
        Self {
45
0
            dst_line: self.dst_line + line_offset,
46
0
            source_id: shift(self.source_id, source_offset),
47
0
            name_id: shift(self.name_id, name_offset),
48
0
            ..self
49
0
        }
50
0
    }
51
52
    #[inline]
53
0
    pub fn get_dst_line(&self) -> u32 {
54
0
        self.dst_line
55
0
    }
56
57
    #[inline]
58
0
    pub fn get_dst_col(&self) -> u32 {
59
0
        self.dst_col
60
0
    }
61
62
    #[inline]
63
0
    pub fn get_src_line(&self) -> u32 {
64
0
        self.src_line
65
0
    }
66
67
    #[inline]
68
0
    pub fn get_src_col(&self) -> u32 {
69
0
        self.src_col
70
0
    }
71
72
    #[inline]
73
0
    pub fn get_name_id(&self) -> Option<u32> {
74
0
        if self.name_id == INVALID_ID { None } else { Some(self.name_id) }
75
0
    }
76
77
    #[inline]
78
0
    pub fn get_source_id(&self) -> Option<u32> {
79
0
        if self.source_id == INVALID_ID { None } else { Some(self.source_id) }
80
0
    }
81
}
82
83
#[derive(Debug, Clone, Default, PartialEq, Eq)]
84
pub struct TokenChunk {
85
    pub start: u32,
86
    pub end: u32,
87
    pub prev_dst_line: u32,
88
    pub prev_dst_col: u32,
89
    pub prev_src_line: u32,
90
    pub prev_src_col: u32,
91
    pub prev_name_id: u32,
92
    pub prev_source_id: u32,
93
}
94
95
impl TokenChunk {
96
    #[expect(clippy::too_many_arguments)]
97
0
    pub fn new(
98
0
        start: u32,
99
0
        end: u32,
100
0
        prev_dst_line: u32,
101
0
        prev_dst_col: u32,
102
0
        prev_src_line: u32,
103
0
        prev_src_col: u32,
104
0
        prev_name_id: u32,
105
0
        prev_source_id: u32,
106
0
    ) -> Self {
107
0
        Self {
108
0
            start,
109
0
            end,
110
0
            prev_dst_line,
111
0
            prev_dst_col,
112
0
            prev_src_line,
113
0
            prev_src_col,
114
0
            prev_name_id,
115
0
            prev_source_id,
116
0
        }
117
0
    }
118
}
119
120
/// The `SourceViewToken` provider extra `source` and `source_content` value.
121
///
122
/// Two lifetimes:
123
/// * `'sm` — the borrow of the [`SourceMap`] reference itself.
124
/// * `'data` — the underlying string data inside the [`SourceMap`] (the input
125
///   JSON buffer, for maps parsed via [`SourceMap::from_json_string`]).
126
#[derive(Debug, Clone, Copy)]
127
pub struct SourceViewToken<'sm, 'data> {
128
    pub(crate) token: Token,
129
    pub(crate) sourcemap: &'sm SourceMap<'data>,
130
}
131
132
impl<'sm, 'data> SourceViewToken<'sm, 'data> {
133
0
    pub fn new(token: Token, sourcemap: &'sm SourceMap<'data>) -> Self {
134
0
        Self { token, sourcemap }
135
0
    }
136
137
0
    pub fn get_dst_line(&self) -> u32 {
138
0
        self.token.dst_line
139
0
    }
140
141
0
    pub fn get_dst_col(&self) -> u32 {
142
0
        self.token.dst_col
143
0
    }
144
145
0
    pub fn get_src_line(&self) -> u32 {
146
0
        self.token.src_line
147
0
    }
148
149
0
    pub fn get_src_col(&self) -> u32 {
150
0
        self.token.src_col
151
0
    }
152
153
0
    pub fn get_name_id(&self) -> Option<u32> {
154
0
        self.token.get_name_id()
155
0
    }
156
157
0
    pub fn get_source_id(&self) -> Option<u32> {
158
0
        self.token.get_source_id()
159
0
    }
160
161
0
    pub fn get_name(&self) -> Option<&'sm str> {
162
0
        self.get_name_id().and_then(|id| self.sourcemap.get_name(id))
163
0
    }
164
165
0
    pub fn get_source(&self) -> Option<&'sm str> {
166
0
        self.get_source_id().and_then(|id| self.sourcemap.get_source(id))
167
0
    }
168
169
0
    pub fn get_source_content(&self) -> Option<&'sm str> {
170
0
        self.get_source_id().and_then(|id| self.sourcemap.get_source_content(id))
171
0
    }
172
173
0
    pub fn get_source_and_content(&self) -> Option<(&'sm str, &'sm str)> {
174
0
        self.get_source_id().and_then(|id| self.sourcemap.get_source_and_content(id))
175
0
    }
176
177
    #[expect(clippy::wrong_self_convention)]
178
0
    pub fn to_tuple(&self) -> (Option<&'sm str>, u32, u32, Option<&'sm str>) {
179
0
        (self.get_source(), self.get_src_line(), self.get_src_col(), self.get_name())
180
0
    }
181
}
182
183
#[cfg(test)]
184
mod tests {
185
    use std::borrow::Cow;
186
187
    use super::*;
188
189
    fn sample_map() -> SourceMap<'static> {
190
        SourceMap::new(
191
            None,
192
            vec![Cow::Borrowed("name0")],
193
            None,
194
            vec![Cow::Borrowed("src0.js")],
195
            vec![Some(Cow::Borrowed("the source content"))],
196
            vec![Token::new(2, 3, 4, 5, Some(0), Some(0))].into_boxed_slice(),
197
            None,
198
        )
199
    }
200
201
    #[test]
202
    fn token_getters() {
203
        let token = Token::new(1, 2, 3, 4, Some(5), Some(6));
204
        assert_eq!(token.get_dst_line(), 1);
205
        assert_eq!(token.get_dst_col(), 2);
206
        assert_eq!(token.get_src_line(), 3);
207
        assert_eq!(token.get_src_col(), 4);
208
        assert_eq!(token.get_source_id(), Some(5));
209
        assert_eq!(token.get_name_id(), Some(6));
210
211
        let missing = Token::new(0, 0, 0, 0, None, None);
212
        assert_eq!(missing.get_source_id(), None);
213
        assert_eq!(missing.get_name_id(), None);
214
    }
215
216
    #[test]
217
    fn token_translated() {
218
        let token = Token::new(1, 2, 3, 4, Some(5), Some(6));
219
        assert_eq!(token.translated(10, 100, 1000), Token::new(11, 2, 3, 4, Some(105), Some(1006)));
220
221
        // The missing-id sentinel survives translation rather than wrapping.
222
        let missing = Token::new(0, 0, 0, 0, None, None);
223
        let shifted = missing.translated(5, 5, 5);
224
        assert_eq!(shifted.get_dst_line(), 5);
225
        assert_eq!(shifted.get_source_id(), None);
226
        assert_eq!(shifted.get_name_id(), None);
227
    }
228
229
    #[test]
230
    fn source_view_token_accessors() {
231
        let sm = sample_map();
232
        let token = sm.get_source_view_token(0).unwrap();
233
        assert_eq!(token.get_dst_line(), 2);
234
        assert_eq!(token.get_dst_col(), 3);
235
        assert_eq!(token.get_src_line(), 4);
236
        assert_eq!(token.get_src_col(), 5);
237
        assert_eq!(token.get_source_id(), Some(0));
238
        assert_eq!(token.get_name_id(), Some(0));
239
        assert_eq!(token.get_name(), Some("name0"));
240
        assert_eq!(token.get_source(), Some("src0.js"));
241
        assert_eq!(token.get_source_content(), Some("the source content"));
242
        assert_eq!(token.get_source_and_content(), Some(("src0.js", "the source content")));
243
        assert_eq!(token.to_tuple(), (Some("src0.js"), 4, 5, Some("name0")));
244
    }
245
246
    #[test]
247
    fn source_view_token_without_ids() {
248
        let sm = SourceMap::new(
249
            None,
250
            vec![],
251
            None,
252
            vec![],
253
            vec![],
254
            vec![Token::new(0, 0, 0, 0, None, None)].into_boxed_slice(),
255
            None,
256
        );
257
        let token = sm.get_source_view_token(0).unwrap();
258
        assert_eq!(token.get_name(), None);
259
        assert_eq!(token.get_source(), None);
260
        assert_eq!(token.get_source_content(), None);
261
        assert_eq!(token.get_source_and_content(), None);
262
    }
263
}