From f3720847ed93e512657d86713eb9df25c86feaec Mon Sep 17 00:00:00 2001 From: Jacob VanDomelen Date: Tue, 12 Jan 2021 20:17:12 -0800 Subject: [PATCH] Modified FileLinked struct --- gemla/src/bracket/mod.rs | 11 +-- gemla/src/file_linked/mod.rs | 124 +++++++++++++++++---------------- gemla/src/main.rs | 5 +- gemla/src/tests/file_linked.rs | 32 +++++++++ gemla/src/tests/mod.rs | 2 +- gemla/src/tests/tree.rs | 11 +-- gemla/src/tree/mod.rs | 72 +++++++++---------- 7 files changed, 143 insertions(+), 114 deletions(-) diff --git a/gemla/src/bracket/mod.rs b/gemla/src/bracket/mod.rs index be3bb4b..3936a57 100644 --- a/gemla/src/bracket/mod.rs +++ b/gemla/src/bracket/mod.rs @@ -1,10 +1,10 @@ mod state; -use super::tree; use super::file_linked::FileLinked; +use super::tree; -use uuid::Uuid; use std::str::FromStr; +use uuid::Uuid; impl tree::Tree { pub fn run_simulation(&self) { @@ -44,8 +44,8 @@ pub fn run_bracket() { let mut tree = FileLinked::new( *build_tree(height).expect("Error getting result from build_tree"), "for_tests", - ).expect("Unable to create file linked object from tree"); - + ) + .expect("Unable to create file linked object from tree"); // Building tree one node at a time, appending to the top. loop { @@ -56,7 +56,8 @@ pub fn run_bracket() { Uuid::new_v4(), Some(Box::new(tree.readonly().clone())), build_tree(height), - )).expect("Error building up tree node"); + )) + .expect("Error building up tree node"); tree.readonly().run_simulation(); if height == 3 { diff --git a/gemla/src/file_linked/mod.rs b/gemla/src/file_linked/mod.rs index f2290d6..8e38964 100644 --- a/gemla/src/file_linked/mod.rs +++ b/gemla/src/file_linked/mod.rs @@ -1,37 +1,85 @@ -use std::fs; -use std::str::FromStr; use std::fmt; -use std::string::String; -use std::string::ToString; +use std::fs; use std::io::Read; use std::io::Write; +use std::str::FromStr; +use std::string::String; +use std::string::ToString; pub struct FileLinked { val: T, path: String, } +impl FileLinked { + pub fn readonly(&self) -> &T { + &self.val + } +} + impl FileLinked where - T: FromStr + ToString + Default, + T: ToString, { - pub fn from_file(path: &str) -> Result, String> - { + pub fn new(val: T, path: &str) -> Result, String> { + let result = FileLinked { + val, + path: String::from(path), + }; + + result.write_data()?; + + Ok(result) + } + + pub fn write_data(&self) -> Result<(), String> { + let mut file = fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(&self.path) + .map_err(|_| format!("Unable to open path {}", self.path))?; + + write!(file, "{}", self.val.to_string()) + .or_else(|_| Err(String::from("Unable to write to file.")))?; + + Ok(()) + } + + pub fn mutate U>(&mut self, op: F) -> Result { + let result = op(&mut self.val); + + self.write_data()?; + + Ok(result) + } + + pub fn replace(&mut self, val: T) -> Result<(), String> { + self.val = val; + + self.write_data() + } +} + +impl FileLinked +where + T: ToString + FromStr + Default, +{ + pub fn from_file(path: &str) -> Result, String> { let meta = fs::metadata(path); match &meta { Ok(m) if m.is_file() => { - let mut file = fs::OpenOptions::new().read(true).open(path).or_else(|_| { - Err(format!("Unable to open file {}", path)) - })?; + let mut file = fs::OpenOptions::new() + .read(true) + .open(path) + .map_err(|_| format!("Unable to open file {}", path))?; let mut s = String::new(); - file.read_to_string(&mut s).or_else(|_| { - Err(String::from("Unable to read from file.")) - })?; + file.read_to_string(&mut s) + .map_err(|_| String::from("Unable to read from file."))?; - let val = T::from_str(&s).or_else(|_| { - Err(String::from("Unable to parse value from file.")) - })?; + let val = T::from_str(&s) + .map_err(|_| String::from("Unable to parse value from file."))?; Ok(FileLinked { val, @@ -51,50 +99,6 @@ where } } } - - pub fn new(val: T, path: &str) -> Result, String> { - let result = FileLinked { - val, - path: String::from(path), - }; - - result.write_data()?; - - Ok(result) - } - - pub fn write_data(&self) -> Result<(), String> { - let mut file = fs::OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(&self.path) - .or_else(|_| Err(format!("Unable to open path {}", self.path)))?; - - write!(file, "{}", self.val.to_string()).or_else(|_| { - Err(String::from("Unable to write to file.")) - })?; - - Ok(()) - } - - pub fn readonly(&self) -> &T { - &self.val - } - - pub fn mutate U>(&mut self, op: F) -> Result { - let result = op(&mut self.val); - - self.write_data()?; - - Ok(result) - } - - pub fn replace(&mut self, val: T) -> Result<(), String> { - self.val = val; - - self.write_data() - } } impl fmt::Display for FileLinked { diff --git a/gemla/src/main.rs b/gemla/src/main.rs index 38d1637..d59928a 100644 --- a/gemla/src/main.rs +++ b/gemla/src/main.rs @@ -35,9 +35,8 @@ fn main() { println!("\n\nReading tree from temp file."); let tree: file_linked::FileLinked> = - file_linked::FileLinked::from_file("./for_tests").expect( - "Unable to read tree from existing file", - ); + file_linked::FileLinked::from_file("./for_tests") + .expect("Unable to read tree from existing file"); println!("Value read from file:\n{}", tree); } Ok(_) => println!("{} is not a valid directory!", directory), diff --git a/gemla/src/tests/file_linked.rs b/gemla/src/tests/file_linked.rs index 8b13789..7e69404 100644 --- a/gemla/src/tests/file_linked.rs +++ b/gemla/src/tests/file_linked.rs @@ -1 +1,33 @@ +use super::super::file_linked::FileLinked; +use super::super::tree::Tree; +#[test] +fn test_mutate() -> Result<(), String> { + let tree = btree!(1, btree!(2), btree!(3, btree!(4),)); + let mut linked_tree = FileLinked::new(tree, "blah.txt")?; + + assert_eq!( + format!("{}", linked_tree.readonly()), + "val = 1\n\n[left]\nval = 2\n\n[right]\nval = 3\n\n[right.left]\nval = 4\n" + ); + + linked_tree.mutate(|v1| v1.val = 10)?; + + assert_eq!( + format!("{}", linked_tree.readonly()), + "val = 10\n\n[left]\nval = 2\n\n[right]\nval = 3\n\n[right.left]\nval = 4\n" + ); + + linked_tree.mutate(|v1| { + let mut left = v1.left.clone().unwrap(); + left.val = 13; + v1.left = Some(left); + })?; + + assert_eq!( + format!("{}", linked_tree.readonly()), + "val = 10\n\n[left]\nval = 13\n\n[right]\nval = 3\n\n[right.left]\nval = 4\n" + ); + + Ok(()) +} diff --git a/gemla/src/tests/mod.rs b/gemla/src/tests/mod.rs index 398820d..44e20c6 100644 --- a/gemla/src/tests/mod.rs +++ b/gemla/src/tests/mod.rs @@ -1,3 +1,3 @@ -mod tree; mod bracket; mod file_linked; +mod tree; diff --git a/gemla/src/tests/tree.rs b/gemla/src/tests/tree.rs index 7025f7f..152e66b 100644 --- a/gemla/src/tests/tree.rs +++ b/gemla/src/tests/tree.rs @@ -18,12 +18,8 @@ fn test_new() { #[test] fn test_fmt() { - assert_eq!( - format!( - "{}", - btree!("foo", btree!("bar"),), - ), + format!("{}", btree!("foo", btree!("bar"),),), "val = \"foo\"\n\n[left]\nval = \"bar\"\n" ); } @@ -31,10 +27,7 @@ fn test_fmt() { #[test] fn test_fmt_node() { let t = btree!(17, btree!(16), btree!(12)); - assert_eq!( - Tree::fmt_node(&t.left), - "16" - ); + assert_eq!(Tree::fmt_node(&t.left), "16"); assert_eq!( Tree::fmt_node(&Some(Box::new(btree!(btree!("foo"))))), "val = \"foo\"\n" diff --git a/gemla/src/tree/mod.rs b/gemla/src/tree/mod.rs index 9138df1..a37baca 100644 --- a/gemla/src/tree/mod.rs +++ b/gemla/src/tree/mod.rs @@ -1,20 +1,20 @@ //! An unbalanced binary tree type where each node has an optional left and right child. -//! +//! //! # Examples -//! +//! //! ``` //! let mut t = Tree::new(1, None, None); //! let t2 = Tree::new(2, Some(Box::new(t)), Some(Box::new(Tree::new(3, None, None)))); //! let s = format!("{}", t2); -//! +//! //! assert_eq!(s, "(2: (1: _|_)|(3: _|_))"); //! t.left = Some(Box::new(Tree::new(4, None, None))); //! assert_eq!(Tree::fmt_node(t.left), 4); //! assert_eq!(Tree::from_str(s), t2); //! ``` -//! +//! //! Additionally the `btree!` macro can be used to conveniently initialize trees: -//! +//! //! ``` //! # #[macro_use] extern crate tree; //! # fn main() { @@ -23,28 +23,28 @@ //! # } //! ``` -use std::fmt; -use serde::{Serialize, Deserialize}; use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; +use std::fmt; use std::str::FromStr; /// An unbalanced binary tree type where each node has an optional left and right child. -/// +/// /// # Examples -/// +/// /// ``` /// let mut t = Tree::new(1, None, None); /// let t2 = Tree::new(2, Some(Box::new(t)), Some(Box::new(Tree::new(3, None, None)))); /// let s = format!("{}", t2); -/// +/// /// assert_eq!(s, "(2: (1: _|_)|(3: _|_))"); /// t.left = Some(Box::new(Tree::new(4, None, None))); /// assert_eq!(Tree::fmt_node(t.left), 4); /// assert_eq!(Tree::from_str(s), t2); /// ``` -/// +/// /// Additionally the `btree!` macro can be used to conveniently initialize trees: -/// +/// /// ``` /// let t1 = btree!(1,btree!(2),btree!(3)) /// assert_eq!(format!("{}", t1), "(1: (2: _|_)|(3: _|_)") @@ -57,33 +57,36 @@ pub struct Tree { } /// Used to construct trees in a cleaner manner. `btree!` takes 3 arguments, the first being the -/// value of the root node, and the other two being child nodes. The last two arguments are +/// value of the root node, and the other two being child nodes. The last two arguments are /// optional. -/// +/// /// ``` /// // A tree with two child nodes. /// let t = btree!(1, btree!(2), btree!(3)); -/// +/// /// // A tree with only a left node. /// let t_left = btree!(1, btree!(2),); -/// +/// /// // A tree with only a right node. /// let t_right = btree!(1, ,btree!(3)); -/// +/// /// // A tree with no children nodes. /// let t_single = btree!(1) /// ``` #[macro_export] macro_rules! btree { - ($val:expr, $l:expr, $r:expr) => { - $crate::tree::Tree::new( - $val, - Some(Box::new($l)), - Some(Box::new($r)) - ) }; - ($val:expr, , $r:expr) => { $crate::tree::Tree::new($val, None, Some(Box::new($r))) }; - ($val:expr, $l:expr,) => { $crate::tree::Tree::new($val, Some(Box::new($l)), None) }; - ($val:expr) => { Tree::new($val, None, None) }; + ($val:expr, $l:expr, $r:expr) => { + $crate::tree::Tree::new($val, Some(Box::new($l)), Some(Box::new($r))) + }; + ($val:expr, , $r:expr) => { + $crate::tree::Tree::new($val, None, Some(Box::new($r))) + }; + ($val:expr, $l:expr,) => { + $crate::tree::Tree::new($val, Some(Box::new($l)), None) + }; + ($val:expr) => { + Tree::new($val, None, None) + }; } impl Tree { @@ -91,12 +94,11 @@ impl Tree { pub fn new(val: T, left: Option>>, right: Option>>) -> Tree { Tree { val, left, right } } - + pub fn fmt_node(t: &Option>>) -> String where T: fmt::Display, { - match t { Some(n) => format!("{}", (*n).val), _ => String::from("_"), @@ -107,23 +109,21 @@ impl Tree { impl fmt::Display for Tree { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let result = toml::to_string(self); - - match result - { + + match result { Ok(string) => write!(f, "{}", string), Err(_) => Err(std::fmt::Error), } } } - impl FromStr for Tree - where T: FromStr + DeserializeOwned +where + T: FromStr + DeserializeOwned, { type Err = String; - fn from_str(s: &str) -> Result - { - toml::from_str(s).or_else(|_| {Err(format!("Unable to parse string {}", s))}) + fn from_str(s: &str) -> Result { + toml::from_str(s).map_err(|_| format!("Unable to parse string {}", s)) } }