idl 0.1.1

Library used for the idl language.
Documentation
use super::analyzer;
use super::nodes::*;
use super::parser;
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize, Clone)]
pub enum ClientNode {
    ClientField(Box<ClientField>),
    Comment(Vec<String>),
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ClientField {
    pub ident: String,
    pub value: Box<ItemType>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Client {
    pub ident: String,
    pub nodes: Vec<ClientNode>,
}

impl Client {
    pub fn language(&self) -> Option<String> {
        match self.get_field("language") {
            Some(ItemType::NatString(value)) => Some(value.clone()),
            _ => None,
        }
    }

    pub fn servers<'a>(
        &'a self,
        analyzer: &'a super::analyzer::Analyzer,
    ) -> Option<Vec<&'a super::server::Server>> {
        match self.get_field("servers") {
            Some(ItemType::Values(values)) => {
                if values.iter().all(|v| v.is_server()) {
                    Some(
                        values
                            .iter()
                            .filter_map(|value| match value {
                                ItemType::ServerTypeName(name) => {
                                    Some(analyzer.find_server(name).unwrap())
                                }
                                _ => None,
                            })
                            .collect(),
                    )
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    pub fn get_field(&self, name: &str) -> Option<&ItemType> {
        for node in &self.nodes {
            match node {
                ClientNode::ClientField(field) => {
                    if field.ident == name {
                        return Some(&field.value);
                    }
                }
                _ => {}
            }
        }
        None
    }
}

pub(super) fn get_node(
    item: &parser::Item,
    analyzer_items: &analyzer::AnalyzerItems,
) -> Result<IdsNode, analyzer::AnalyzerError> {
    let mut nodes = vec![];

    let create_field_node = |ident: &str, value| {
        ClientNode::ClientField(Box::new(ClientField {
            value: Box::new(value),
            ident: ident.to_owned(),
        }))
    };

    for node in item.nodes.iter() {
        match node {
            parser::ItemNode::ItemField(field) => {
                let value = analyzer_items.get_ids_node(&field.value)?;
                match field.ident.as_str() {
                    "layers" => {
                        if match &value {
                            ItemType::Values(values) => values.iter().any(|v| !v.is_identifier()),
                            _ => true,
                        } {
                            return Err(analyzer::ReferenceError(
                                analyzer::ReferenceErrorKind::NotLayer,
                                field.range,
                                field.ident.to_owned(),
                            )
                            .into());
                        }
                    }
                    "description" => {
                        if !value.is_string() {
                            return Err(analyzer::ReferenceError(
                                analyzer::ReferenceErrorKind::NotString,
                                field.range,
                                field.ident.to_owned(),
                            )
                            .into());
                        }
                    }
                    "language" => {
                        if !value.is_string() {
                            return Err(analyzer::ReferenceError(
                                analyzer::ReferenceErrorKind::NotString,
                                field.range,
                                field.ident.to_owned(),
                            )
                            .into());
                        }
                    }
                    _ => {}
                }
                nodes.push(create_field_node(&field.ident, value));
            }
            parser::ItemNode::Comment(_) => {}
        }
    }

    let ident = match &item.ident {
        parser::ItemIdent::Identifier(_) => return Err(analyzer::AnalyzerError::Undefined),
        parser::ItemIdent::TypeName(value) => value.ident.to_owned(),
    };

    Ok(IdsNode::Client(Box::new(Client { ident, nodes })))
}