nobject-rs 3.0.1

A parser for wavefront Obj/Mtl files. Written with Nom.
Documentation
use std::borrow::Cow;
use std::result::Result;

use nom::{
    branch::alt,
    bytes::{complete::is_not, tag, tag_no_case, take_till},
    character::{
        complete::{line_ending, multispace1},
        multispace0,
    },
    combinator::map,
    multi::fold_many0,
    sequence::{delimited, preceded},
    Parser,
};

use super::{Token, TokenSet, TokenizeError};

pub fn parse_obj(input: &str) -> Result<TokenSet, TokenizeError> {
    match fold_many0(
        alt((
            delimited(
                multispace0(),
                map(
                    alt([
                        tag_no_case("mtllib"),
                        tag_no_case("usemtl"),
                        tag_no_case("bevel"),
                        tag_no_case("c_interp"),
                        tag_no_case("d_interp"),
                        tag_no_case("lod"),
                        tag_no_case("shadow_obj"),
                        tag_no_case("trace_obj"),
                        tag_no_case("maplib"),
                        tag_no_case("usemap"),
                        tag_no_case("vt"),
                        tag_no_case("vn"),
                        tag_no_case("vp"),
                        tag_no_case("v"),
                        tag_no_case("f"),
                        tag_no_case("l"),
                        tag_no_case("p"),
                        tag_no_case("o"),
                        tag_no_case("g"),
                        tag_no_case("s"),
                    ]),
                    kw_map,
                ),
                map(multispace1, |_| Token::Ignore),
            ),
            map(tag("/"), |_| Token::Slash),
            super::parse_float(),
            super::parse_digit(),
            map(
                preceded(tag("#"), take_till(|c| c == '\n' || c == '\r')),
                |_| Token::Ignore,
            ),
            map(alt((line_ending, multispace1)), |_| Token::Ignore),
            map(is_not("\r\n"), |s: &str| Token::String(Cow::Borrowed(s))),
        )),
        Vec::new,
        |mut acc: Vec<Token>, item| {
            if item != Token::Ignore {
                acc.push(item);
            }
            acc
        },
    )
    .parse_complete(input)
    {
        Ok((_, v)) => Ok(v.into()),
        Err(e) => Err(TokenizeError::Parse(e.to_string())),
    }
}

fn kw_map(value: &str) -> Token<'_> {
    match value.to_lowercase().as_ref() {
        "mtllib" => Token::MaterialLib,
        "usemtl" => Token::UseMaterial,
        "vt" => Token::VertexTexture,
        "vn" => Token::VertexNormal,
        "vp" => Token::VertexParam,
        "v" => Token::Vertex,
        "f" => Token::Face,
        "l" => Token::Line,
        "p" => Token::Point,
        "o" => Token::Object,
        "g" => Token::Group,
        "s" => Token::Smoothing,
        "bevel" => Token::Bevel,
        "c_interp" => Token::CInterp,
        "d_interp" => Token::DInterp,
        "lod" => Token::Lod,
        "shadow_obj" => Token::ShadowObj,
        "trace_obj" => Token::TraceObj,
        "maplib" => Token::TextureMapLib,
        "usemap" => Token::UseTextureMap,
        _ => Token::Ignore,
    }
}