Modified FileLinked struct

This commit is contained in:
Jacob VanDomelen 2021-01-12 20:17:12 -08:00
parent 53e0ec865f
commit f3720847ed
7 changed files with 143 additions and 114 deletions

View file

@ -1,10 +1,10 @@
mod state; mod state;
use super::tree;
use super::file_linked::FileLinked; use super::file_linked::FileLinked;
use super::tree;
use uuid::Uuid;
use std::str::FromStr; use std::str::FromStr;
use uuid::Uuid;
impl tree::Tree<Uuid> { impl tree::Tree<Uuid> {
pub fn run_simulation(&self) { pub fn run_simulation(&self) {
@ -44,8 +44,8 @@ pub fn run_bracket() {
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"),
"for_tests", "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. // Building tree one node at a time, appending to the top.
loop { loop {
@ -56,7 +56,8 @@ pub fn run_bracket() {
Uuid::new_v4(), Uuid::new_v4(),
Some(Box::new(tree.readonly().clone())), Some(Box::new(tree.readonly().clone())),
build_tree(height), build_tree(height),
)).expect("Error building up tree node"); ))
.expect("Error building up tree node");
tree.readonly().run_simulation(); tree.readonly().run_simulation();
if height == 3 { if height == 3 {

View file

@ -1,37 +1,85 @@
use std::fs;
use std::str::FromStr;
use std::fmt; use std::fmt;
use std::string::String; use std::fs;
use std::string::ToString;
use std::io::Read; use std::io::Read;
use std::io::Write; use std::io::Write;
use std::str::FromStr;
use std::string::String;
use std::string::ToString;
pub struct FileLinked<T> { pub struct FileLinked<T> {
val: T, val: T,
path: String, path: String,
} }
impl<T> FileLinked<T> {
pub fn readonly(&self) -> &T {
&self.val
}
}
impl<T> FileLinked<T> impl<T> FileLinked<T>
where where
T: FromStr + ToString + Default, T: ToString,
{ {
pub fn from_file(path: &str) -> Result<FileLinked<T>, String> pub fn new(val: T, path: &str) -> Result<FileLinked<T>, 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, F: FnOnce(&mut T) -> U>(&mut self, op: F) -> Result<U, String> {
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<T> FileLinked<T>
where
T: ToString + FromStr + Default,
{
pub fn from_file(path: &str) -> Result<FileLinked<T>, String> {
let meta = fs::metadata(path); let meta = fs::metadata(path);
match &meta { match &meta {
Ok(m) if m.is_file() => { Ok(m) if m.is_file() => {
let mut file = fs::OpenOptions::new().read(true).open(path).or_else(|_| { let mut file = fs::OpenOptions::new()
Err(format!("Unable to open file {}", path)) .read(true)
})?; .open(path)
.map_err(|_| format!("Unable to open file {}", path))?;
let mut s = String::new(); let mut s = String::new();
file.read_to_string(&mut s).or_else(|_| { file.read_to_string(&mut s)
Err(String::from("Unable to read from file.")) .map_err(|_| String::from("Unable to read from file."))?;
})?;
let val = T::from_str(&s).or_else(|_| { let val = T::from_str(&s)
Err(String::from("Unable to parse value from file.")) .map_err(|_| String::from("Unable to parse value from file."))?;
})?;
Ok(FileLinked { Ok(FileLinked {
val, val,
@ -51,50 +99,6 @@ where
} }
} }
} }
pub fn new(val: T, path: &str) -> Result<FileLinked<T>, 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, F: FnOnce(&mut T) -> U>(&mut self, op: F) -> Result<U, String> {
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<T: fmt::Display> fmt::Display for FileLinked<T> { impl<T: fmt::Display> fmt::Display for FileLinked<T> {

View file

@ -35,9 +35,8 @@ 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("./for_tests").expect( file_linked::FileLinked::from_file("./for_tests")
"Unable to read tree from existing file", .expect("Unable to read tree from existing file");
);
println!("Value read from file:\n{}", tree); println!("Value read from file:\n{}", tree);
} }
Ok(_) => println!("{} is not a valid directory!", directory), Ok(_) => println!("{} is not a valid directory!", directory),

View file

@ -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(())
}

View file

@ -1,3 +1,3 @@
mod tree;
mod bracket; mod bracket;
mod file_linked; mod file_linked;
mod tree;

View file

@ -18,12 +18,8 @@ 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"),),
),
"val = \"foo\"\n\n[left]\nval = \"bar\"\n" "val = \"foo\"\n\n[left]\nval = \"bar\"\n"
); );
} }
@ -31,10 +27,7 @@ fn test_fmt() {
#[test] #[test]
fn test_fmt_node() { fn test_fmt_node() {
let t = btree!(17, btree!(16), btree!(12)); let t = btree!(17, btree!(16), btree!(12));
assert_eq!( assert_eq!(Tree::fmt_node(&t.left), "16");
Tree::fmt_node(&t.left),
"16"
);
assert_eq!( assert_eq!(
Tree::fmt_node(&Some(Box::new(btree!(btree!("foo"))))), Tree::fmt_node(&Some(Box::new(btree!(btree!("foo"))))),
"val = \"foo\"\n" "val = \"foo\"\n"

View file

@ -23,9 +23,9 @@
//! # } //! # }
//! ``` //! ```
use std::fmt;
use serde::{Serialize, Deserialize};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::str::FromStr; use std::str::FromStr;
/// 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.
@ -76,14 +76,17 @@ pub struct Tree<T> {
#[macro_export] #[macro_export]
macro_rules! btree { macro_rules! btree {
($val:expr, $l:expr, $r:expr) => { ($val:expr, $l:expr, $r:expr) => {
$crate::tree::Tree::new( $crate::tree::Tree::new($val, Some(Box::new($l)), Some(Box::new($r)))
$val, };
Some(Box::new($l)), ($val:expr, , $r:expr) => {
Some(Box::new($r)) $crate::tree::Tree::new($val, None, Some(Box::new($r)))
) }; };
($val:expr, , $r:expr) => { $crate::tree::Tree::new($val, None, Some(Box::new($r))) }; ($val:expr, $l:expr,) => {
($val:expr, $l:expr,) => { $crate::tree::Tree::new($val, Some(Box::new($l)), None) }; $crate::tree::Tree::new($val, Some(Box::new($l)), None)
($val:expr) => { Tree::new($val, None, None) }; };
($val:expr) => {
Tree::new($val, None, None)
};
} }
impl<T> Tree<T> { impl<T> Tree<T> {
@ -96,7 +99,6 @@ 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("_"),
@ -108,22 +110,20 @@ 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 result = toml::to_string(self); let result = toml::to_string(self);
match result match result {
{
Ok(string) => write!(f, "{}", string), Ok(string) => write!(f, "{}", string),
Err(_) => Err(std::fmt::Error), Err(_) => Err(std::fmt::Error),
} }
} }
} }
impl<T> FromStr for Tree<T> impl<T> FromStr for Tree<T>
where T: FromStr + DeserializeOwned where
T: FromStr + DeserializeOwned,
{ {
type Err = String; type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> fn from_str(s: &str) -> Result<Self, Self::Err> {
{ toml::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
toml::from_str(s).or_else(|_| {Err(format!("Unable to parse string {}", s))})
} }
} }