parse_that 0.2.1

Zero-copy parser combinator library for Rust
Documentation
use crate::combinators::ParserSpan;
use crate::leaf::*;
use crate::parse::*;

use super::utils::escaped_span;

use pprint::{Doc, Join};
use smallvec::SmallVec;

#[derive(Debug, PartialEq)]
pub enum CSV<'a> {
    Lines(Vec<SmallVec<[&'a str; 16]>>),
}

impl<'a> From<CSV<'a>> for Doc<'a> {
    fn from(val: CSV<'a>) -> Self {
        let CSV::Lines(lines) = val;

        lines
            .into_iter()
            .map(|line| {
                line.into_iter()
                    .map(Doc::from)
                    .collect::<Vec<Doc<'_>>>()
                    .join(",")
            })
            .collect::<Vec<Doc<'_>>>()
            .join(Doc::Hardline)
    }
}

pub fn csv_parser<'a>() -> Parser<'a, CSV<'a>> {
    let delim = || string_span(",");

    let double_quotes = (string_span("\"\"") | escaped_span() | take_while_span(|c| c != '"'))
        .many_span(..)
        .wrap_span(string_span("\""), string_span("\""));

    let no_quotes = take_while_span(|c| c != ',' && c != '"' && c != '\r' && c != '\n');

    let empty = string_span("").look_ahead(delim());

    let token = (double_quotes | no_quotes | empty).map(|span| span.as_str());

    let line = token.sep_by_small::<_, [&str; 16]>(delim(), 1..);

    let csv = line.sep_by(regex_span(r"[ \t]*(\r?\n)+[ \t]*"), ..);

    csv.trim_whitespace().map(CSV::Lines)
}