Skip to main content

jsonette/parser/
utils.rs

1/*
2 * Copyright (c) 2026 DevEtte.
3 *
4 * This project is dual-licensed under both the MIT License and the
5 * Apache License, Version 2.0 (the "License"). You may not use this
6 * file except in compliance with one of these licenses.
7 *
8 * You may obtain a copy of the Licenses at:
9 * - MIT: https://opensource.org
10 * - Apache 2.0: http://apache.org
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19//! Internal parser utilities, including mapping line/column errors back to byte offsets.
20
21/// Helper to convert a 1-indexed line and column to a 0-indexed byte offset in the input string.
22///
23/// # Arguments
24///
25/// * `input` - The raw JSON string slice.
26/// * `line` - The 1-indexed line number where the error occurred.
27/// * `col` - The 1-indexed column number where the error occurred.
28///
29/// # Returns
30///
31/// The 0-indexed byte offset of the character in the input string. If `line` is `0`, `0` is returned.
32/// If `line` or `col` exceeds the boundaries of the string, the length of the string is returned.
33pub fn line_col_to_byte_offset(input: &str, line: usize, col: usize) -> usize {
34    if line == 0 {
35        return 0;
36    }
37    let mut current_line = 1;
38    let mut line_start_offset = 0;
39    let bytes = input.as_bytes();
40
41    for (offset, &b) in bytes.iter().enumerate() {
42        if current_line == line {
43            let target_offset = line_start_offset + (col.saturating_sub(1));
44            return target_offset.min(input.len());
45        }
46        if b == b'\n' {
47            current_line += 1;
48            line_start_offset = offset + 1;
49        }
50    }
51
52    if current_line == line {
53        let target_offset = line_start_offset + (col.saturating_sub(1));
54        return target_offset.min(input.len());
55    }
56
57    input.len()
58}