tref/
lib.rs

1//! # TREF
2//!
3//! TREF is a plain text file format to describe trees in a human readable way.
4//! 
5//! 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.
6//! 
7//! 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.
8//! 
9//! A simple TREF file looks like:
10//! 
11//! ```tref
12//! # A simple tree.
13//! [my_tree]
14//! + root_nodess
15//! + + child_1
16//! + + + child_1_1
17//! + + + child_1_2
18//! + + child_2
19//! + + + child_2_1
20//! + + child_3
21//! ```
22//! File `simpletree.tref`
23//! 
24//! Check out the repo [README](https://github.com/asllop/tref/blob/master/README.md) for further details about the TREF format.
25//! 
26//! # Examples
27//! 
28//! To load this crate just use:
29//! 
30//! ```
31//! use tref;
32//! ```
33//! 
34//! Parse the `file.tref` file, traverse `my_tree`, modify tree and serialize:
35//! 
36//! ```
37//! use std::{fs::File, io::{BufReader, BufWriter}};
38//! use tref::*;
39//! 
40//! if let Ok(file) = File::open("file.tref") {
41//!     // Parse document
42//!     match <tref::Model>::parse(BufReader::new(file)) {
43//!         Ok(mut forest) => {
44//!             // Get the `my_tree` model.
45//!             if let Some(tree) = forest.get_mut_tree("my_tree") {
46//!                 // Traverse the tree using the BFS algorithm
47//!                 for (n, _) in tree.iterators().bfs() {
48//!                     // Print the node content
49//!                     println!("{}", n.get_content_ref().get_val());
50//!                 }
51//! 
52//!                 // Unlink node at index 1
53//!                 tree.unlink_node(1);
54//!             }
55//! 
56//!             // Serialize the resulting forest back into a TREF file
57//!             let f = File::create("serialized.tref").expect("Unable to create file");
58//!             let mut buf_writer = BufWriter::new(f);
59//!             match <tref::Model>::serialize(&forest, &mut buf_writer) {
60//!                 Ok(num_lines) => {
61//!                     println!("Tree serialized correctly, num lines = {}", num_lines);
62//!                 },
63//!                 Err(e) => {
64//!                     println!("Failed serializing tree: {}", e);
65//!                 }
66//!             }
67//!         },
68//!         Err(e) => {
69//!             println!("Could not parse TREF: {}", e)
70//!         }
71//!     }
72//! }
73//! ```
74//! 
75//! 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.
76//! 
77//! # Dialects
78//! 
79//! 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.
80//! 
81//! For example, imagine we want to model a tree with nodes that can only have integer values. Something like:
82//! 
83//! ```tref
84//! [my_dialect_tree]
85//! + 1000
86//! + + 800
87//! + + + 2500
88//! + + + 130
89//! ```
90//! 
91//! First we have to define a [`NodeContent`][`socarel::NodeContent`] to parse our custom nodes:
92//! 
93//! ```
94//! # use tref::*;
95//! 
96//! pub struct IntegerNode {
97//!     num: i32,
98//!     content: String
99//! }
100//! 
101//! impl IntegerNode {
102//!     pub fn get_num(&self) -> i32 {
103//!         self.num
104//!     }
105//! }
106//! 
107//! impl NodeContent for IntegerNode {
108//!     fn new(content: &str) -> Option<Self> {
109//!         // Try to parse the node content as integer
110//!         match content.trim().parse() {
111//!             Ok(num) => {
112//!                 let content = String::from(content);
113//!                 Some(IntegerNode { num, content })
114//!             },
115//!             Err(_) => None
116//!         }
117//!     }
118//! 
119//!     fn get_val(&self) -> &str {
120//!         &self.content
121//!     }
122//! 
123//!     fn gen_content(&self) -> String {
124//!         String::from(self.get_val())
125//!     }
126//! }
127//! ```
128//! 
129//! And then use it to parse the tree:
130//! 
131//! ```
132//! # use socarel::NodeContent;
133//! # use std::io::BufReader;
134//! # pub struct IntegerNode;
135//! # impl NodeContent for IntegerNode {
136//! #    fn new(content: &str) -> Option<Self> { None }
137//! #    fn get_val(&self) -> &str { "" }
138//! #    fn gen_content(&self) -> String { String::new() }
139//! # }
140//! let tref =
141//! "[my_dialect_tree]\n\
142//! + 1000\n\
143//! + + 800\n\
144//! + + + 2500\n\
145//! + + + 130\n";
146//! 
147//! let forest = tref::Model::<IntegerNode>::parse(BufReader::new(tref.as_bytes()));
148//! ```
149//! 
150//! All nodes inside the tree will be of type `IntegerNode`.
151//! 
152//! 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.
153
154mod parser;
155mod stack;
156mod model;
157mod error;
158
159pub use model::*;
160pub use error::*;
161pub use socarel::NodeContent;
162
163#[cfg(test)]
164mod tests;