spatialos-codegen 0.2.2

Codegen tool used with spatialos-macro and spatialos-sdk
Documentation
use std::{convert::identity, iter::FromIterator};

use nom::{
    branch::alt,
    bytes::complete::{is_not, tag},
    character::complete::{char, multispace0, multispace1, one_of},
    combinator::{map, map_opt, map_res, peek, value},
    error::ParseError,
    multi::{fold_many1, many0, many1, separated_list1},
    sequence::{delimited, pair},
    IResult,
};

pub fn ws0<'a, F: 'a, O, E: ParseError<&'a [u8]>>(
    inner: F,
) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E>
where
    F: FnMut(&'a [u8]) -> IResult<&'a [u8], O, E>,
{
    delimited(multispace0, inner, multispace0)
}

pub fn ws1<'a, F: 'a, O, E: ParseError<&'a [u8]>>(
    inner: F,
) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E>
where
    F: FnMut(&'a [u8]) -> IResult<&'a [u8], O, E>,
{
    delimited(multispace1, inner, multispace1)
}

pub fn uppercase(input: &[u8]) -> IResult<&[u8], char> {
    one_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ")(input)
}

pub fn digit(input: &[u8]) -> IResult<&[u8], char> {
    one_of("0123456789")(input)
}

pub fn lowercase(input: &[u8]) -> IResult<&[u8], char> {
    one_of("abcdefghijklmnopqrstuvwxyz")(input)
}

pub fn lower_alphanum(input: &[u8]) -> IResult<&[u8], char> {
    alt((lowercase, digit))(input)
}

pub fn camel_case_component(input: &[u8]) -> IResult<&[u8], String> {
    map(pair(uppercase, many0(lower_alphanum)), |(c, s)| {
        c.to_string() + &s.iter().collect::<String>()
    })(input)
}

pub fn camel_case(input: &[u8]) -> IResult<&[u8], String> {
    fold_many1(camel_case_component, String::new(), |acc, val| acc + &val)(input)
}

pub fn snake_case_component(input: &[u8]) -> IResult<&[u8], String> {
    fold_many1(lower_alphanum, String::new(), |acc, val| {
        acc + &val.to_string()
    })(input)
}

pub fn upper_snake_case_component(input: &[u8]) -> IResult<&[u8], String> {
    fold_many1(uppercase, String::new(), |acc, val| acc + &val.to_string())(input)
}

pub fn snake_case(input: &[u8]) -> IResult<&[u8], String> {
    map_opt(
        map(separated_list1(char('_'), snake_case_component), |v| {
            let mut it = v.into_iter();
            it.next().map(|e| it.fold(e, |acc, val| acc + "_" + &val))
        }),
        identity,
    )(input)
}

pub fn upper_snake_case(input: &[u8]) -> IResult<&[u8], String> {
    map_opt(
        map(
            separated_list1(char('_'), upper_snake_case_component),
            |v| {
                let mut it = v.into_iter();
                it.next().map(|e| it.fold(e, |acc, val| acc + "_" + &val))
            },
        ),
        identity,
    )(input)
}

pub fn parse_u32(input: &[u8]) -> IResult<&[u8], u32> {
    map_res(map(many1(digit), String::from_iter), |s| s.parse::<u32>())(input)
}

pub fn parse_comment(input: &[u8]) -> IResult<&[u8], Option<String>> {
    map(
        pair(
            tag("//"),
            alt((
                map(
                    map(map_res(is_not("\n\r"), std::str::from_utf8), |o| {
                        o.to_string()
                    }),
                    Some,
                ),
                value(None, peek(one_of("\n\r"))),
            )),
        ),
        |(_, c)| c,
    )(input)
}

pub fn parse_comments(input: &[u8]) -> IResult<&[u8], Vec<String>> {
    map(many0(ws0(parse_comment)), |c| {
        c.into_iter()
            .filter_map(identity)
            .map(|s| s.replace("\"", "\\\""))
            .collect::<Vec<_>>()
    })(input)
}

#[cfg(test)]
mod tests {

    use super::*;
    #[test]
    fn test_camel_case_component() {
        assert_eq!(
            camel_case_component(b"CamelCase"),
            Ok((&b"Case"[..], "Camel".to_string()))
        )
    }
    #[test]
    fn test_camel_case_component_end() {
        assert_eq!(
            camel_case_component(b"Camel"),
            Ok((&b""[..], "Camel".to_string()))
        )
    }
}