wdl-analysis 0.26.0

Analysis of Workflow Description Language (WDL) documents.
Documentation
//! A module for utility functions for lint rules.

/// Iterates over the lines of a string and returns the line, starting offset,
/// and next possible starting offset.
pub fn lines_with_offset(s: &str) -> impl Iterator<Item = (&str, usize, usize)> {
    let mut offset = 0;
    std::iter::from_fn(move || {
        if offset >= s.len() {
            return None;
        }

        let start = offset;
        loop {
            match s[offset..].find(|c| ['\r', '\n'].contains(&c)) {
                Some(i) => {
                    let end = offset + i;
                    offset = end + 1;

                    if s.as_bytes().get(end) == Some(&b'\r') {
                        if s.as_bytes().get(end + 1) != Some(&b'\n') {
                            continue;
                        }

                        // There are two characters in the newline
                        offset += 1;
                    }

                    return Some((&s[start..end], start, offset));
                }
                None => {
                    offset = s.len();
                    return Some((&s[start..], start, offset));
                }
            }
        }
    })
}

#[cfg(test)]
mod tests {
    use pretty_assertions::assert_eq;

    use super::*;

    #[test]
    fn test_lines_with_offset() {
        let s = "This string\nhas many\n\nnewlines, including Windows\r\n\r\nand even a \r that \
                 should not be a newline\n";
        let lines = lines_with_offset(s).collect::<Vec<_>>();
        assert_eq!(
            lines,
            &[
                ("This string", 0, 12),
                ("has many", 12, 21),
                ("", 21, 22),
                ("newlines, including Windows", 22, 51),
                ("", 51, 53),
                ("and even a \r that should not be a newline", 53, 95),
            ]
        );
    }
}