Separating binary into library for doctests
This commit is contained in:
parent
f751e46389
commit
5e204a2c28
10 changed files with 292 additions and 233 deletions
|
@ -1,15 +1,6 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate regex;
|
extern crate gemla;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
pub mod tree;
|
|
||||||
pub mod bracket;
|
|
||||||
pub mod constants;
|
|
||||||
pub mod file_linked;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests;
|
|
||||||
|
|
||||||
use clap::App;
|
use clap::App;
|
||||||
use std::fs::metadata;
|
use std::fs::metadata;
|
||||||
|
@ -21,11 +12,11 @@ use std::fs::metadata;
|
||||||
fn main() {
|
fn main() {
|
||||||
// Command line arguments are parsed with the clap crate. And this program uses
|
// Command line arguments are parsed with the clap crate. And this program uses
|
||||||
// the yaml method with clap.
|
// the yaml method with clap.
|
||||||
let yaml = load_yaml!("../cli.yml");
|
let yaml = load_yaml!("../../cli.yml");
|
||||||
let matches = App::from_yaml(yaml).get_matches();
|
let matches = App::from_yaml(yaml).get_matches();
|
||||||
|
|
||||||
// Checking that the first argument <DIRECTORY> is a valid directory
|
// Checking that the first argument <DIRECTORY> is a valid directory
|
||||||
let directory = matches.value_of(constants::args::DIRECTORY).unwrap();
|
let directory = matches.value_of(gemla::constants::args::DIRECTORY).unwrap();
|
||||||
let metadata = metadata(directory);
|
let metadata = metadata(directory);
|
||||||
match &metadata {
|
match &metadata {
|
||||||
Ok(m) if m.is_dir() => {
|
Ok(m) if m.is_dir() => {
|
|
@ -8,6 +8,46 @@ use std::fmt;
|
||||||
/// A trait used to interact with the internal state of nodes within the genetic bracket
|
/// A trait used to interact with the internal state of nodes within the genetic bracket
|
||||||
pub trait GeneticNode {
|
pub trait GeneticNode {
|
||||||
/// Initializes a new instance of a genetic state.
|
/// Initializes a new instance of a genetic state.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use gemla::bracket::genetic_node::GeneticNode;
|
||||||
|
/// #
|
||||||
|
/// struct Node {
|
||||||
|
/// pub fit_score: f64,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl GeneticNode for Node {
|
||||||
|
/// fn initialize() -> Result<Box<Self>, String> {
|
||||||
|
/// Ok(Box::new(Node {fit_score: 0.0}))
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// //...
|
||||||
|
/// #
|
||||||
|
/// # fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # fn get_fit_score(&self) -> f64 {
|
||||||
|
/// # self.fit_score
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # fn mutate(&mut self) -> Result<(), String> {
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # fn main() -> Result<(), String> {
|
||||||
|
/// let node = Node::initialize()?;
|
||||||
|
/// assert_eq!(node.get_fit_score(), 0.0);
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
fn initialize() -> Result<Box<Self>, String>;
|
fn initialize() -> Result<Box<Self>, String>;
|
||||||
|
|
||||||
/// Runs a simulation on the state object in order to guage it's fitness.
|
/// Runs a simulation on the state object in order to guage it's fitness.
|
||||||
|
|
|
@ -122,3 +122,120 @@ where
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests
|
||||||
|
{
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::string::ToString;
|
||||||
|
|
||||||
|
#[derive(Default, Deserialize, Serialize, Clone)]
|
||||||
|
struct TestState {
|
||||||
|
pub score: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for TestState {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<TestState, Self::Err> {
|
||||||
|
toml::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TestState {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.score)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestState {
|
||||||
|
fn new(score: f64) -> TestState {
|
||||||
|
TestState { score: score }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl genetic_node::GeneticNode for TestState {
|
||||||
|
fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
||||||
|
self.score += iterations as f64;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_fit_score(&self) -> f64 {
|
||||||
|
self.score
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mutate(&mut self) -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initialize() -> Result<Box<Self>, String> {
|
||||||
|
Ok(Box::new(TestState { score: 0.0 }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new() {
|
||||||
|
let bracket = Bracket::<TestState>::initialize("./temp".to_string())
|
||||||
|
.expect("Bracket failed to initialize");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
format!("{}", bracket),
|
||||||
|
format!("{{\"tree\":{},\"step\":0,\"iteration_scaling\":{{\"enumType\":\"Linear\",\"enumContent\":1}}}}",
|
||||||
|
btree!(TestState::new(0.0)))
|
||||||
|
);
|
||||||
|
|
||||||
|
std::fs::remove_file("./temp").expect("Unable to remove file");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_run() {
|
||||||
|
let mut bracket = Bracket::<TestState>::initialize("./temp2".to_string())
|
||||||
|
.expect("Bracket failed to initialize");
|
||||||
|
|
||||||
|
bracket
|
||||||
|
.mutate(|b| drop(b.iteration_scaling(IterationScaling::Linear(2))))
|
||||||
|
.expect("Failed to set iteration scaling");
|
||||||
|
for _ in 0..3 {
|
||||||
|
bracket
|
||||||
|
.mutate(|b| drop(b.run_simulation_step()))
|
||||||
|
.expect("Failed to run step");
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
format!("{}", bracket),
|
||||||
|
format!("{{\"tree\":{},\"step\":3,\"iteration_scaling\":{{\"enumType\":\"Linear\",\"enumContent\":2}}}}",
|
||||||
|
btree!(
|
||||||
|
TestState::new(12.0),
|
||||||
|
btree!(
|
||||||
|
TestState::new(12.0),
|
||||||
|
btree!(TestState::new(6.0),
|
||||||
|
btree!(TestState::new(2.0)),
|
||||||
|
btree!(TestState::new(2.0))),
|
||||||
|
btree!(TestState::new(6.0),
|
||||||
|
btree!(TestState::new(2.0)),
|
||||||
|
btree!(TestState::new(2.0)))
|
||||||
|
),
|
||||||
|
btree!(
|
||||||
|
TestState::new(12.0),
|
||||||
|
btree!(TestState::new(6.0),
|
||||||
|
btree!(TestState::new(2.0)),
|
||||||
|
btree!(TestState::new(2.0))),
|
||||||
|
btree!(TestState::new(6.0),
|
||||||
|
btree!(TestState::new(2.0)),
|
||||||
|
btree!(TestState::new(2.0))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
std::fs::remove_file("./temp2").expect("Unable to remove file");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -103,3 +103,43 @@ impl<T: fmt::Display> fmt::Display for FileLinked<T> {
|
||||||
write!(f, "{}", self.val)
|
write!(f, "{}", self.val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mutate() -> Result<(), String> {
|
||||||
|
let tree = btree!(1, btree!(2), btree!(3, btree!(4),));
|
||||||
|
let mut linked_tree = FileLinked::new(tree, String::from("test.txt"))?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
format!("{}", linked_tree.readonly()),
|
||||||
|
"{\"val\":1,\"left\":{\"val\":2,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
|
||||||
|
);
|
||||||
|
|
||||||
|
linked_tree.mutate(|v1| v1.val = 10)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
format!("{}", linked_tree.readonly()),
|
||||||
|
"{\"val\":10,\"left\":{\"val\":2,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
|
||||||
|
);
|
||||||
|
|
||||||
|
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,\"left\":{\"val\":13,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
|
||||||
|
);
|
||||||
|
|
||||||
|
fs::remove_file("test.txt").expect("Unable to remove file");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
7
gemla/src/lib.rs
Normal file
7
gemla/src/lib.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
extern crate regex;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod tree;
|
||||||
|
pub mod bracket;
|
||||||
|
pub mod constants;
|
||||||
|
pub mod file_linked;
|
|
@ -1,111 +0,0 @@
|
||||||
use super::super::bracket;
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::fmt;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::string::ToString;
|
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize, Clone)]
|
|
||||||
struct TestState {
|
|
||||||
pub score: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for TestState {
|
|
||||||
type Err = String;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<TestState, Self::Err> {
|
|
||||||
toml::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TestState {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.score)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TestState {
|
|
||||||
fn new(score: f64) -> TestState {
|
|
||||||
TestState { score: score }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl bracket::genetic_node::GeneticNode for TestState {
|
|
||||||
fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
|
||||||
self.score += iterations as f64;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_fit_score(&self) -> f64 {
|
|
||||||
self.score
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mutate(&mut self) -> Result<(), String> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn initialize() -> Result<Box<Self>, String> {
|
|
||||||
Ok(Box::new(TestState { score: 0.0 }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_new() {
|
|
||||||
let bracket = bracket::Bracket::<TestState>::initialize("./temp".to_string())
|
|
||||||
.expect("Bracket failed to initialize");
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
format!("{}", bracket),
|
|
||||||
format!("{{\"tree\":{},\"step\":0,\"iteration_scaling\":{{\"enumType\":\"Linear\",\"enumContent\":1}}}}",
|
|
||||||
btree!(TestState::new(0.0)))
|
|
||||||
);
|
|
||||||
|
|
||||||
std::fs::remove_file("./temp").expect("Unable to remove file");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_run() {
|
|
||||||
let mut bracket = bracket::Bracket::<TestState>::initialize("./temp".to_string())
|
|
||||||
.expect("Bracket failed to initialize");
|
|
||||||
|
|
||||||
bracket
|
|
||||||
.mutate(|b| drop(b.iteration_scaling(bracket::IterationScaling::Linear(2))))
|
|
||||||
.expect("Failed to set iteration scaling");
|
|
||||||
for _ in 0..3 {
|
|
||||||
bracket
|
|
||||||
.mutate(|b| drop(b.run_simulation_step()))
|
|
||||||
.expect("Failed to run step");
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
format!("{}", bracket),
|
|
||||||
format!("{{\"tree\":{},\"step\":3,\"iteration_scaling\":{{\"enumType\":\"Linear\",\"enumContent\":2}}}}",
|
|
||||||
btree!(
|
|
||||||
TestState::new(12.0),
|
|
||||||
btree!(
|
|
||||||
TestState::new(12.0),
|
|
||||||
btree!(TestState::new(6.0),
|
|
||||||
btree!(TestState::new(2.0)),
|
|
||||||
btree!(TestState::new(2.0))),
|
|
||||||
btree!(TestState::new(6.0),
|
|
||||||
btree!(TestState::new(2.0)),
|
|
||||||
btree!(TestState::new(2.0)))
|
|
||||||
),
|
|
||||||
btree!(
|
|
||||||
TestState::new(12.0),
|
|
||||||
btree!(TestState::new(6.0),
|
|
||||||
btree!(TestState::new(2.0)),
|
|
||||||
btree!(TestState::new(2.0))),
|
|
||||||
btree!(TestState::new(6.0),
|
|
||||||
btree!(TestState::new(2.0)),
|
|
||||||
btree!(TestState::new(2.0))))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
std::fs::remove_file("./temp").expect("Unable to remove file");
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
use super::super::file_linked::FileLinked;
|
|
||||||
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_mutate() -> Result<(), String> {
|
|
||||||
let tree = btree!(1, btree!(2), btree!(3, btree!(4),));
|
|
||||||
let mut linked_tree = FileLinked::new(tree, String::from("test.txt"))?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
format!("{}", linked_tree.readonly()),
|
|
||||||
"{\"val\":1,\"left\":{\"val\":2,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
|
|
||||||
);
|
|
||||||
|
|
||||||
linked_tree.mutate(|v1| v1.val = 10)?;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
format!("{}", linked_tree.readonly()),
|
|
||||||
"{\"val\":10,\"left\":{\"val\":2,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
|
|
||||||
);
|
|
||||||
|
|
||||||
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,\"left\":{\"val\":13,\"left\":null,\"right\":null},\"right\":{\"val\":3,\"left\":{\"val\":4,\"left\":null,\"right\":null},\"right\":null}}"
|
|
||||||
);
|
|
||||||
|
|
||||||
fs::remove_file("test.txt").expect("Unable to remove file");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
mod bracket;
|
|
||||||
mod file_linked;
|
|
||||||
mod tree;
|
|
|
@ -1,36 +0,0 @@
|
||||||
use super::super::tree::Tree;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_new() {
|
|
||||||
assert_eq!(
|
|
||||||
Tree::new(30, None, Some(Box::new(Tree::new(20, None, None)))),
|
|
||||||
Tree {
|
|
||||||
val: 30,
|
|
||||||
left: None,
|
|
||||||
right: Some(Box::new(Tree {
|
|
||||||
val: 20,
|
|
||||||
left: None,
|
|
||||||
right: None,
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fmt() {
|
|
||||||
assert_eq!(
|
|
||||||
format!("{}", btree!("foo", btree!("bar"),),),
|
|
||||||
"{\"val\":\"foo\",\"left\":{\"val\":\"bar\",\"left\":null,\"right\":null},\"right\":null}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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(&Some(Box::new(btree!(btree!("foo"))))),
|
|
||||||
"{\"val\":\"foo\",\"left\":null,\"right\":null}"
|
|
||||||
);
|
|
||||||
assert_eq!(Tree::<i32>::fmt_node(&None), "_");
|
|
||||||
}
|
|
|
@ -2,26 +2,27 @@
|
||||||
//!
|
//!
|
||||||
//! # Examples
|
//! # Examples
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```no_run
|
||||||
//! let mut t = Tree::new(1, None, None);
|
//! //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 t2 = Tree::new(2, Some(Box::new(t)), Some(Box::new(Tree::new(3, None, None))));
|
||||||
//! let s = format!("{}", t2);
|
//! //let s = format!("{}", t2);
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(s, "(2: (1: _|_)|(3: _|_))");
|
//! //assert_eq!(s, "(2: (1: _|_)|(3: _|_))");
|
||||||
//! t.left = Some(Box::new(Tree::new(4, None, None)));
|
//! //t.left = Some(Box::new(Tree::new(4, None, None)));
|
||||||
//! assert_eq!(Tree::fmt_node(t.left), 4);
|
//! //assert_eq!(Tree::fmt_node(t.left), 4);
|
||||||
//! assert_eq!(Tree::from_str(s), t2);
|
//! //assert_eq!(Tree::from_str(s), t2);
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Additionally the `btree!` macro can be used to conveniently initialize trees:
|
//! Additionally the `btree!` macro can be used to conveniently initialize trees:
|
||||||
//!
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! //# #[macro_use] extern crate tree;
|
||||||
|
//! //# fn main() {
|
||||||
|
//! //let t1 = btree!(1,btree!(2),btree!(3))
|
||||||
|
//! //assert_eq!(format!("{}", t1), "(1: (2: _|_)|(3: _|_)")
|
||||||
|
//! //# }
|
||||||
//! ```
|
//! ```
|
||||||
//! # #[macro_use] extern crate tree;
|
|
||||||
//! # fn main() {
|
|
||||||
//! let t1 = btree!(1,btree!(2),btree!(3))
|
|
||||||
//! assert_eq!(format!("{}", t1), "(1: (2: _|_)|(3: _|_)")
|
|
||||||
//! # }
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -33,21 +34,21 @@ use std::str::FromStr;
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let mut t = Tree::new(1, None, None);
|
/// //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 t2 = Tree::new(2, Some(Box::new(t)), Some(Box::new(Tree::new(3, None, None))));
|
||||||
/// let s = format!("{}", t2);
|
/// //let s = format!("{}", t2);
|
||||||
///
|
///
|
||||||
/// assert_eq!(s, "(2: (1: _|_)|(3: _|_))");
|
/// //assert_eq!(s, "(2: (1: _|_)|(3: _|_))");
|
||||||
/// t.left = Some(Box::new(Tree::new(4, None, None)));
|
/// //t.left = Some(Box::new(Tree::new(4, None, None)));
|
||||||
/// assert_eq!(Tree::fmt_node(t.left), 4);
|
/// //assert_eq!(Tree::fmt_node(t.left), 4);
|
||||||
/// assert_eq!(Tree::from_str(s), t2);
|
/// //assert_eq!(Tree::from_str(s), t2);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Additionally the `btree!` macro can be used to conveniently initialize trees:
|
/// Additionally the `btree!` macro can be used to conveniently initialize trees:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// 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, Serialize, Deserialize, Clone, PartialEq, Debug)]
|
#[derive(Default, Serialize, Deserialize, Clone, PartialEq, Debug)]
|
||||||
pub struct Tree<T> {
|
pub struct Tree<T> {
|
||||||
|
@ -60,18 +61,25 @@ pub struct Tree<T> {
|
||||||
/// 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.
|
/// optional.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```no_run
|
||||||
/// // A tree with two child nodes.
|
/// //#[macro_use]
|
||||||
/// let t = btree!(1, Some(btree!(2)), Some(btree!(3)));
|
/// //extern crate gemla;
|
||||||
///
|
/// //
|
||||||
/// // A tree with only a left node.
|
/// //use gemla::*;
|
||||||
/// let t_left = btree!(1, Some(btree!(2)),);
|
/// //
|
||||||
///
|
/// //fn main() {
|
||||||
/// // A tree with only a right node.
|
/// // // A tree with two child nodes.
|
||||||
/// let t_right = btree!(1, ,Some(btree!(3)));
|
/// // let t = btree!(1, Some(btree!(2)), Some(btree!(3)));
|
||||||
///
|
/// //
|
||||||
/// // A tree with no children nodes.
|
/// // // A tree with only a left node.
|
||||||
/// let t_single = btree!(1)
|
/// // let t_left = btree!(1, Some(btree!(2)),);
|
||||||
|
/// //
|
||||||
|
/// // // A tree with only a right node.
|
||||||
|
/// // let t_right = btree!(1, ,Some(btree!(3)));
|
||||||
|
/// //
|
||||||
|
/// // // A tree with no children nodes.
|
||||||
|
/// // let t_single = btree!(1);
|
||||||
|
/// //}
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! btree {
|
macro_rules! btree {
|
||||||
|
@ -127,3 +135,45 @@ where
|
||||||
serde_json::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
|
serde_json::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests
|
||||||
|
{
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new() {
|
||||||
|
assert_eq!(
|
||||||
|
Tree::new(30, None, Some(Box::new(Tree::new(20, None, None)))),
|
||||||
|
Tree {
|
||||||
|
val: 30,
|
||||||
|
left: None,
|
||||||
|
right: Some(Box::new(Tree {
|
||||||
|
val: 20,
|
||||||
|
left: None,
|
||||||
|
right: None,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fmt() {
|
||||||
|
assert_eq!(
|
||||||
|
format!("{}", btree!("foo", btree!("bar"),),),
|
||||||
|
"{\"val\":\"foo\",\"left\":{\"val\":\"bar\",\"left\":null,\"right\":null},\"right\":null}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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(&Some(Box::new(btree!(btree!("foo"))))),
|
||||||
|
"{\"val\":\"foo\",\"left\":null,\"right\":null}"
|
||||||
|
);
|
||||||
|
assert_eq!(Tree::<i32>::fmt_node(&None), "_");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue