wgsldoc 0.2.1

Documentation generator for WGSL shaders
Documentation
use std::str::FromStr;
use pest::iterators::Pair;
use thiserror::Error;
use crate::models::types::{PathType, Primitive, Type, Vector, VectorDimension};
use super::{error::ParsingError, FromPest, Rule};

impl FromPest for Type {
    fn from_pest(element: Pair<'_, Rule>) -> Result<Self, ParsingError> 
    where 
        Self: Sized 
    {
        match element.as_rule() {
            Rule::TYPE => {
                let mut ty = Type::default();

                for type_element in element.into_inner() {
                    match type_element.as_rule() {
                        Rule::PRIMITIVE => {
                            ty = Type::Primitive(Primitive::from_pest(type_element)?);
                        }, 
                        Rule::VECTOR => {
                            ty = Type::Vector(Vector::from_pest(type_element)?);
                        }, 
                        Rule::PATH_TYPE => {
                            ty = Type::Path(PathType::from_pest(type_element)?);
                        }, 
                        _ => {}
                    }
                }

                Ok(ty)
            },
            _ => Err(
                ParsingError::InvalidPestRule {
                    expected: Rule::TYPE,
                    found: element.as_rule(),
                }
            )
        }
    }
}

#[derive(Debug, Error)]
#[error("Invalid primitive type `{0}`; available are bool, f32, f64, u8, u16, u32, u64, i8, i16, i32, i64")]
pub struct InvalidPrimitiveType(String);

impl FromStr for Primitive {
    type Err = InvalidPrimitiveType;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Primitive::*;

        match s {
            "bool" => Ok(Bool),
            "f32" => Ok(Float32),
            "f64" => Ok(Float64),
            "u8" => Ok(Uint8),
            "u16" => Ok(Uint16),
            "u32" => Ok(Uint32),
            "u64" => Ok(Uint64),
            "i8" => Ok(Sint8),
            "i16" => Ok(Sint16),
            "i32" => Ok(Sint32),
            "i64" => Ok(Sint64),
            _ => Err(InvalidPrimitiveType(s.to_owned())),
        }
    }
}

impl FromPest for Primitive {
    fn from_pest(element: Pair<'_, Rule>) -> Result<Self, ParsingError> 
    where 
        Self: Sized 
    {
        match element.as_rule() {
            Rule::PRIMITIVE => Ok(
                Primitive::from_str(element.as_span().as_str())?
            ),
            _ => Err(
                ParsingError::InvalidPestRule {
                    expected: Rule::PRIMITIVE,
                    found: element.as_rule(),
                }
            )
        }
    }
}

impl FromPest for Vector {
    fn from_pest(element: Pair<'_, Rule>) -> Result<Self, ParsingError> 
    where 
        Self: Sized 
    {
        match element.as_rule() {
            Rule::VECTOR => {
                let mut dimension = VectorDimension::default();
                let mut ty = Primitive::default();

                for vector_element in element.into_inner() {
                    match vector_element.as_rule() {
                        Rule::VECTOR_DIMENSION => {
                            dimension = VectorDimension::from_pest(vector_element)?;
                        },
                        Rule::PRIMITIVE => {
                            ty = Primitive::from_pest(vector_element)?;
                        },
                        _ => {},
                    }
                }
                
                Ok(Vector::new(dimension, ty))
            },
            _ => Err(
                ParsingError::InvalidPestRule {
                    expected: Rule::VECTOR,
                    found: element.as_rule(),
                }
            )
        }
    }
}

#[derive(Debug, Error)]
#[error("Invalid vector dimension `{0}`; available are 2, 3, 4")]
pub struct InvalidVectorDimension(String);

impl FromStr for VectorDimension {
    type Err = InvalidPrimitiveType;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use VectorDimension::*;

        match s {
            "2" => Ok(D2),
            "3" => Ok(D3),
            "4" => Ok(D4),
            _ => Err(InvalidPrimitiveType(s.to_owned())),
        }
    }
}

impl FromPest for VectorDimension {
    fn from_pest(element: Pair<'_, Rule>) -> Result<Self, ParsingError> 
    where 
        Self: Sized 
    {
        match element.as_rule() {
            Rule::VECTOR_DIMENSION => Ok(
                VectorDimension::from_str(element.as_span().as_str())?
            ),
            _ => Err(
                ParsingError::InvalidPestRule {
                    expected: Rule::VECTOR_DIMENSION,
                    found: element.as_rule(),
                }
            )
        }
    }
}

impl FromPest for PathType {
    fn from_pest(element: Pair<'_, Rule>) -> Result<Self, ParsingError> 
    where 
        Self: Sized 
    {
        match element.as_rule() {
            Rule::PATH_TYPE => {
                let mut module = None;
                let mut name = String::new();

                for path_type_element in element.into_inner() {
                    match path_type_element.as_rule() {
                        Rule::MODULE => {
                            module = Some(path_type_element.as_span().as_str().to_owned())
                                .filter(|s| !s.is_empty());
                        },
                        Rule::IDENT => {
                            name = path_type_element.as_span().as_str().to_owned();
                        }
                        _ => {},
                    }
                }

                Ok(PathType::new(module, name))
            },
            _ => Err(
                ParsingError::InvalidPestRule {
                    expected: Rule::PATH_TYPE,
                    found: element.as_rule(),
                }
            )
        }
    }
}