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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
//! # TREF
//!
//! TREF is a plain text file format to describe trees in a human readable way.
//!
//! With TREF a human can write a tree and understand the structure by having a quick look, because it is designed to be both easy to read for humans and easy to parse for machines.
//!
//! Writing a tree in a file can be useful for many reasons: as a config file for an application, to store information that can be modified and read by an app and its user, to serialize tree-like memory structures, etc.
//!
//! A simple TREF file looks like:
//!
//! ```tref
//! # A simple tree.
//! [my_tree]
//! + root_nodess
//! + + child_1
//! + + + child_1_1
//! + + + child_1_2
//! + + child_2
//! + + + child_2_1
//! + + child_3
//! ```
//! File `simpletree.tref`
//!
//! Check out the repo [README](https://github.com/asllop/tref/blob/master/README.md) for further details about the TREF format.
//!
//! # Examples
//!
//! To load this crate just use:
//!
//! ```
//! use tref;
//! ```
//!
//! Parse the `file.tref` file, traverse `my_tree`, modify tree and serialize:
//!
//! ```
//! use std::{fs::File, io::{BufReader, BufWriter}};
//! use tref::*;
//!
//! if let Ok(file) = File::open("file.tref") {
//! // Parse document
//! match <tref::Model>::parse(BufReader::new(file)) {
//! Ok(mut forest) => {
//! // Get the `my_tree` model.
//! if let Some(tree) = forest.get_mut_tree("my_tree") {
//! // Traverse the tree using the BFS algorithm
//! for (n, _) in tree.iterators().bfs() {
//! // Print the node content
//! println!("{}", n.get_content_ref().get_val());
//! }
//!
//! // Unlink node at index 1
//! tree.unlink_node(1);
//! }
//!
//! // Serialize the resulting forest back into a TREF file
//! let f = File::create("serialized.tref").expect("Unable to create file");
//! let mut buf_writer = BufWriter::new(f);
//! match <tref::Model>::serialize(&forest, &mut buf_writer) {
//! Ok(num_lines) => {
//! println!("Tree serialized correctly, num lines = {}", num_lines);
//! },
//! Err(e) => {
//! println!("Failed serializing tree: {}", e);
//! }
//! }
//! },
//! Err(e) => {
//! println!("Could not parse TREF: {}", e)
//! }
//! }
//! }
//! ```
//!
//! The example above uses [`unlink_node()`][`socarel::Tree::unlink_node`] to disconnect a node from the tree. To know more about how to manupulate trees, please check out the [`socarel`] crate documentation.
//!
//! # Dialects
//!
//! TREF also supports user defined dialects, that are trees that have nodes with a specific format. This is achived using the [`NodeContent`][`socarel::NodeContent`] trait.
//!
//! For example, imagine we want to model a tree with nodes that can only have integer values. Something like:
//!
//! ```tref
//! [my_dialect_tree]
//! + 1000
//! + + 800
//! + + + 2500
//! + + + 130
//! ```
//!
//! First we have to define a [`NodeContent`][`socarel::NodeContent`] to parse our custom nodes:
//!
//! ```
//! # use tref::*;
//!
//! pub struct IntegerNode {
//! num: i32,
//! content: String
//! }
//!
//! impl IntegerNode {
//! pub fn get_num(&self) -> i32 {
//! self.num
//! }
//! }
//!
//! impl NodeContent for IntegerNode {
//! fn new(content: &str) -> Option<Self> {
//! // Try to parse the node content as integer
//! match content.trim().parse() {
//! Ok(num) => {
//! let content = String::from(content);
//! Some(IntegerNode { num, content })
//! },
//! Err(_) => None
//! }
//! }
//!
//! fn get_val(&self) -> &str {
//! &self.content
//! }
//!
//! fn gen_content(&self) -> String {
//! String::from(self.get_val())
//! }
//! }
//! ```
//!
//! And then use it to parse the tree:
//!
//! ```
//! # use socarel::NodeContent;
//! # use std::io::BufReader;
//! # pub struct IntegerNode;
//! # impl NodeContent for IntegerNode {
//! # fn new(content: &str) -> Option<Self> { None }
//! # fn get_val(&self) -> &str { "" }
//! # fn gen_content(&self) -> String { String::new() }
//! # }
//! let tref =
//! "[my_dialect_tree]\n\
//! + 1000\n\
//! + + 800\n\
//! + + + 2500\n\
//! + + + 130\n";
//!
//! let forest = tref::Model::<IntegerNode>::parse(BufReader::new(tref.as_bytes()));
//! ```
//!
//! All nodes inside the tree will be of type `IntegerNode`.
//!
//! The [`NodeContent::new()`][`socarel::NodeContent::new()`] is called every time a node of the tree is parsed. It returns an [`Option`], that means it can be None, in which case the TREF parser will fail, returing an error.
mod parser;
mod stack;
mod model;
mod error;
pub use model::*;
pub use error::*;
pub use socarel::NodeContent;
#[cfg(test)]
mod tests;