vts_parsing 1.0.1

Crate for parsing VTS or VTM files generated by VTOL VR.
Documentation
/*
vts_parsing: rust parser for the VTS and VTM (including others) files generated by VTOL VR.
Copyright (C) 2024 BlockListed

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/
use std::fmt::{Display, Formatter, Write};

use crate::{parse::Node, Value};

pub fn unparse(v: &Node) -> String {
    let mut s = String::new();
    
    unparse_node(v, 0, &mut s);

    s
}

struct UnparseValue<'a>(&'a Value);

impl<'a> Display for UnparseValue<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self.0 {
            Value::Number(v) => {
                f.write_fmt(format_args!("{}", v))?;
            }
            Value::Float(ref v) => {
                f.write_fmt(format_args!("{}", v))?;
            }
            Value::Boolean(v) => {
                if *v {
                    f.write_str("True")?;
                } else {
                    f.write_str("False")?;
                }
            }
            Value::Vector(ref v) => {
                unparse_vector(v, f)?;
            }
            Value::VectorGroup(ref v) => {
                unparse_vectorgroup(v, f)?;
            }
            Value::Null => (),
            Value::String(v) => {
                f.write_str(v)?;
            }
        };

        Ok(())
    }
}

fn unparse_vector(v: &[f64; 3], f: &mut Formatter) -> std::fmt::Result {
    f.write_char('(')?;
    match v.split_last() {
        Some((last, rest)) => {
            for v in rest {
                f.write_fmt(format_args!("{}", v))?;
                f.write_str(", ")?;
            }
            f.write_fmt(format_args!("{}", last))?;
        }
        None => (),
    }

    f.write_char(')')?;

    Ok(())
}

fn unparse_vectorgroup(v: &[[f64; 3]], f: &mut Formatter) -> std::fmt::Result {
    for vector in v {
        unparse_vector(vector, f)?;
        f.write_char(';')?;
    }

    Ok(())
}

fn indent(depth: u32, output: &mut String) {
    (0..depth).for_each(|_| {
        output.write_char('\t').unwrap();
    });
}

fn newline(output: &mut String) {
    output.write_char('\n').unwrap();
}

fn unparse_node(node: &Node, indent_depth: u32, output: &mut String) {
    indent(indent_depth, output);
    output.write_str(&node.name).unwrap();
    newline(output);
    indent(indent_depth, output);
    output.write_char('{').unwrap();
    newline(output);
    for (k, v) in node.values.iter() {
        indent(indent_depth+1, output);
        output.write_fmt(format_args!("{} = {}", k, UnparseValue(v))).unwrap();
        newline(output);
    }
    for n in node.nodes() {
        unparse_node(n, indent_depth+1, output);
    }
    indent(indent_depth, output);
    output.write_char('}').unwrap();
    newline(output);
}