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;
use super::tree;
use super::file_linked::FileLinked;
use super::tree;
use uuid::Uuid;
use std::str::FromStr;
use uuid::Uuid;
impl tree::Tree<Uuid> {
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 {

View file

@ -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<T> {
val: T,
path: String,
}
impl<T> FileLinked<T> {
pub fn readonly(&self) -> &T {
&self.val
}
}
impl<T> FileLinked<T>
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);
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<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> {

View file

@ -35,9 +35,8 @@ fn main() {
println!("\n\nReading tree from temp file.");
let tree: file_linked::FileLinked<tree::Tree<uuid::Uuid>> =
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),

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 file_linked;
mod tree;

View file

@ -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"

View file

@ -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<T> {
}
/// 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<T> Tree<T> {
@ -91,12 +94,11 @@ impl<T> Tree<T> {
pub fn new(val: T, left: Option<Box<Tree<T>>>, right: Option<Box<Tree<T>>>) -> Tree<T> {
Tree { val, left, right }
}
pub fn fmt_node(t: &Option<Box<Tree<T>>>) -> String
where
T: fmt::Display,
{
match t {
Some(n) => format!("{}", (*n).val),
_ => String::from("_"),
@ -107,23 +109,21 @@ impl<T> Tree<T> {
impl<T: fmt::Display + Serialize> fmt::Display for Tree<T> {
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<T> FromStr for Tree<T>
where T: FromStr + DeserializeOwned
where
T: FromStr + DeserializeOwned,
{
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err>
{
toml::from_str(s).or_else(|_| {Err(format!("Unable to parse string {}", s))})
fn from_str(s: &str) -> Result<Self, Self::Err> {
toml::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
}
}