Using serde for serializing
This commit is contained in:
parent
978baef596
commit
53e0ec865f
8 changed files with 43 additions and 96 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -8,3 +8,5 @@ Cargo.lock
|
||||||
|
|
||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
||||||
|
settings.json
|
||||||
|
|
16
.vscode/launch.json
vendored
Normal file
16
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug",
|
||||||
|
"program": "${workspaceFolder}/gemla/target/debug/gemla.exe",
|
||||||
|
"args": ["./gemla/temp/"],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -5,6 +5,8 @@ authors = ["Jacob VanDomelen <Jacob.Vandome15@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
uuid = { version = "0.7", features = ["serde", "v4"] }
|
uuid = { version = "0.7", features = ["serde", "v4"] }
|
||||||
clap = { version = "~2.27.0", features = ["yaml"] }
|
clap = { version = "~2.27.0", features = ["yaml"] }
|
||||||
|
toml = "0.5.8"
|
||||||
regex = "1"
|
regex = "1"
|
|
@ -43,7 +43,7 @@ pub fn run_bracket() {
|
||||||
let mut height = 1;
|
let mut height = 1;
|
||||||
let mut tree = FileLinked::new(
|
let mut tree = FileLinked::new(
|
||||||
*build_tree(height).expect("Error getting result from build_tree"),
|
*build_tree(height).expect("Error getting result from build_tree"),
|
||||||
"temp",
|
"for_tests",
|
||||||
).expect("Unable to create file linked object from tree");
|
).expect("Unable to create file linked object from tree");
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@ impl<T> FileLinked<T>
|
||||||
where
|
where
|
||||||
T: FromStr + ToString + Default,
|
T: FromStr + ToString + Default,
|
||||||
{
|
{
|
||||||
pub fn from_file(path: &str) -> Result<FileLinked<T>, String> {
|
pub fn from_file(path: &str) -> Result<FileLinked<T>, String>
|
||||||
|
{
|
||||||
let meta = fs::metadata(path);
|
let meta = fs::metadata(path);
|
||||||
|
|
||||||
match &meta {
|
match &meta {
|
||||||
|
|
|
@ -35,7 +35,7 @@ fn main() {
|
||||||
|
|
||||||
println!("\n\nReading tree from temp file.");
|
println!("\n\nReading tree from temp file.");
|
||||||
let tree: file_linked::FileLinked<tree::Tree<uuid::Uuid>> =
|
let tree: file_linked::FileLinked<tree::Tree<uuid::Uuid>> =
|
||||||
file_linked::FileLinked::from_file("temp").expect(
|
file_linked::FileLinked::from_file("./for_tests").expect(
|
||||||
"Unable to read tree from existing file",
|
"Unable to read tree from existing file",
|
||||||
);
|
);
|
||||||
println!("Value read from file:\n{}", tree);
|
println!("Value read from file:\n{}", tree);
|
||||||
|
|
|
@ -18,12 +18,13 @@ fn test_new() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fmt() {
|
fn test_fmt() {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!(
|
format!(
|
||||||
"{}",
|
"{}",
|
||||||
btree!("foo", btree!("bar"),),
|
btree!("foo", btree!("bar"),),
|
||||||
),
|
),
|
||||||
"(foo: (bar: _|_)|_)"
|
"val = \"foo\"\n\n[left]\nval = \"bar\"\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ fn test_fmt_node() {
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Tree::fmt_node(&Some(Box::new(btree!(btree!("foo"))))),
|
Tree::fmt_node(&Some(Box::new(btree!(btree!("foo"))))),
|
||||||
"(foo: _|_)"
|
"val = \"foo\"\n"
|
||||||
);
|
);
|
||||||
assert_eq!(Tree::<i32>::fmt_node(&None), "_");
|
assert_eq!(Tree::<i32>::fmt_node(&None), "_");
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,9 @@
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
/// An unbalanced binary tree type where each node has an optional left and right child.
|
/// An unbalanced binary tree type where each node has an optional left and right child.
|
||||||
///
|
///
|
||||||
|
@ -48,7 +49,7 @@ use regex::Regex;
|
||||||
/// let t1 = btree!(1,btree!(2),btree!(3))
|
/// let t1 = btree!(1,btree!(2),btree!(3))
|
||||||
/// assert_eq!(format!("{}", t1), "(1: (2: _|_)|(3: _|_)")
|
/// assert_eq!(format!("{}", t1), "(1: (2: _|_)|(3: _|_)")
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Default, Clone, PartialEq, Debug)]
|
#[derive(Default, Serialize, Deserialize, Clone, PartialEq, Debug)]
|
||||||
pub struct Tree<T> {
|
pub struct Tree<T> {
|
||||||
pub val: T,
|
pub val: T,
|
||||||
pub left: Option<Box<Tree<T>>>,
|
pub left: Option<Box<Tree<T>>>,
|
||||||
|
@ -95,6 +96,7 @@ impl<T> Tree<T> {
|
||||||
where
|
where
|
||||||
T: fmt::Display,
|
T: fmt::Display,
|
||||||
{
|
{
|
||||||
|
|
||||||
match t {
|
match t {
|
||||||
Some(n) => format!("{}", (*n).val),
|
Some(n) => format!("{}", (*n).val),
|
||||||
_ => String::from("_"),
|
_ => String::from("_"),
|
||||||
|
@ -102,103 +104,26 @@ impl<T> Tree<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: fmt::Display> fmt::Display for Tree<T> {
|
impl<T: fmt::Display + Serialize> fmt::Display for Tree<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let node_str = |t: &Option<Box<Tree<T>>>| -> String {
|
let result = toml::to_string(self);
|
||||||
match t {
|
|
||||||
Some(n) => format!("{}", *n),
|
|
||||||
_ => String::from("_"),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
write!(
|
match result
|
||||||
f,
|
{
|
||||||
"({}: {}|{})",
|
Ok(string) => write!(f, "{}", string),
|
||||||
self.val,
|
Err(_) => Err(std::fmt::Error),
|
||||||
node_str(&self.left),
|
}
|
||||||
node_str(&self.right)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seperate_nodes(s: &str) -> Result<(&str, &str), ParseTreeError> {
|
|
||||||
let mut result = Err(ParseTreeError::new(
|
|
||||||
format!("Unable to seperate string: {}", s),
|
|
||||||
));
|
|
||||||
let mut stack: Vec<char> = Vec::new();
|
|
||||||
|
|
||||||
for (i, c) in s.char_indices() {
|
|
||||||
if c == '(' {
|
|
||||||
stack.push(c);
|
|
||||||
} else if c == ')' {
|
|
||||||
if stack.is_empty() {
|
|
||||||
result = Err(ParseTreeError::new(
|
|
||||||
format!("Unbalanced parenthesis found in string: {}", s),
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.pop();
|
|
||||||
} else if c == '|' && stack.is_empty() {
|
|
||||||
result = Ok((&s[..i], &s[i + 1..]));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_str_helper<T: FromStr>(s: &str) -> Result<Option<Box<Tree<T>>>, ParseTreeError> {
|
|
||||||
let mut result = Err(ParseTreeError::new(String::from(
|
|
||||||
"Unable to parse tree, string format unrecognized.",
|
|
||||||
)));
|
|
||||||
let emptyre = Regex::new(r"\s*_\s*").unwrap();
|
|
||||||
let re = Regex::new(r"\(([0-9a-fA-F-]+)\s*:\s*(.*)\)$").unwrap();
|
|
||||||
let caps = re.captures(s);
|
|
||||||
|
|
||||||
if let Some(c) = caps {
|
|
||||||
let val = T::from_str(c.get(1).unwrap().as_str()).or_else(|_| {
|
|
||||||
Err(ParseTreeError::new(format!(
|
|
||||||
"Unable to parse node value: {}",
|
|
||||||
c.get(1).unwrap().as_str()
|
|
||||||
)))
|
|
||||||
})?;
|
|
||||||
let (left, right) = seperate_nodes(c.get(2).unwrap().as_str())?;
|
|
||||||
let left = from_str_helper(left)?;
|
|
||||||
let right = from_str_helper(right)?;
|
|
||||||
|
|
||||||
result = Ok(Some(Box::new(Tree::new(val, left, right))));
|
|
||||||
} else if emptyre.is_match(s) {
|
|
||||||
result = Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> FromStr for Tree<T>
|
impl<T> FromStr for Tree<T>
|
||||||
where
|
where T: FromStr + DeserializeOwned
|
||||||
T: FromStr,
|
|
||||||
{
|
{
|
||||||
type Err = ParseTreeError;
|
type Err = String;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err>
|
||||||
let result = from_str_helper(s)?;
|
{
|
||||||
|
toml::from_str(s).or_else(|_| {Err(format!("Unable to parse string {}", s))})
|
||||||
result
|
|
||||||
.ok_or_else(|| {
|
|
||||||
ParseTreeError::new(format!("Unable to parse string {}", s))
|
|
||||||
})
|
|
||||||
.and_then(|t| Ok(*t))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ParseTreeError {
|
|
||||||
pub msg: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParseTreeError {
|
|
||||||
fn new(msg: String) -> ParseTreeError {
|
|
||||||
ParseTreeError { msg }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue