1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
mod json;
mod json_properties;
mod lisplike;

use std::str::FromStr;
use std::vec::Vec;

#[derive(Debug, PartialEq)]
pub struct Node {
    pub name: String,
    pub children: Vec<Node>,
}

impl Node {
    pub fn new(name: String) -> Node {
        Node {
            name,
            children: vec![],
        }
    }
}

pub enum InputFormat {
    LispLike,
    Json,
    JsonProperties,
}

impl FromStr for InputFormat {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "lisp" => Ok(InputFormat::LispLike),
            "json" => Ok(InputFormat::Json),
            "jsonprop" => Ok(InputFormat::JsonProperties),
            _ => Err("invalid format type"),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Error {
    EmptyInputError,
    MissingNameError,
    MultipleRootsError,
    FormatSpecificError(String),
}

pub fn prettify(serialized: String, format: InputFormat) -> Result<String, Error> {
    let root = match format {
        InputFormat::LispLike => lisplike::deserialize(serialized),
        InputFormat::Json => json::deserialize(serialized),
        InputFormat::JsonProperties => json_properties::deserialize(serialized),
    }?;
    Ok(node_to_lines(&root).join("\n"))
}

pub fn node_to_lines(node: &Node) -> Vec<String> {
    let mut lines = vec![node.name.clone()];
    let children = &node.children;
    let last_child_idx = if children.len() > 1 {
        children.len() - 1
    } else {
        0
    };
    for child in children[0..last_child_idx].iter() {
        let child_node_lines = node_to_lines(child);
        if let Some(first_line) = child_node_lines.first() {
            lines.push(format!("├── {}", first_line));
        }
        for line in child_node_lines[1..].iter() {
            lines.push(format!("│   {}", line));
        }
    }
    if let Some(last_child) = children.last() {
        let last_child_node_lines = node_to_lines(last_child);
        if let Some(first_line) = last_child_node_lines.first() {
            lines.push(format!("└── {}", first_line));
        }
        for line in last_child_node_lines[1..].iter() {
            lines.push(format!("    {}", line));
        }
    }
    lines
}