36 releases

0.1.35 Oct 2, 2020
0.1.33 Jul 26, 2020
0.1.32 Oct 26, 2019
0.1.31 Nov 30, 2017
0.1.9 Nov 26, 2016

#1285 in Data structures


Used in 3 crates

MIT license

70KB
1.5K SLoC

Treeflection Build Status Crates.io Docs

treeflection_derive Crates.io Docs

Treeflection runs a command stored as a string on a tree of structs, collections and primitive types.

Commands

A command to set an int in a Vec in a struct in another struct in a Hashmap to the value 50 looks like: someHashMap["key"].someChild.anotherChild[0]:set 50

For the full syntax take a look at the Command Manual

Usage

The Node trait must be implemented for every type in the tree. Then a new NodeRunner is created using the command string and passed to the node_step method of the root node. The NodeRunner is then passed to the children specified in the command and then runs the command on the final specified child. Use the treeflection_derive crate to #[Derive(Node)] your own structs or write your own handlers.

Vec example

extern crate treeflection;
use treeflection::{NodeRunner, Node};

pub fn main() {
    let mut test_vec = vec!(0, 413, 358, 42);

    let command = "[1]:get";
    let result = test_vec.node_step(NodeRunner::new(command).unwrap());
    assert_eq!(result, "413");

    let command = "[1]:set 1111";
    let result = test_vec.node_step(NodeRunner::new(command).unwrap());
    assert_eq!(result, "");

    let command = "[1]:get";
    let result = test_vec.node_step(NodeRunner::new(command).unwrap());
    assert_eq!(result, "1111");
}

Custom struct example

Use the treeflection_derive crate to #[Derive(Node)] your own structs or write your own handlers. Your structs also need to impl the traits Serialize, Deserialize, Default and Clone as well as extern crate serde_json. This is because serde_json is used to get/set entire structs.

Currently use treeflection::{NodeRunner, Node, NodeToken}; must be included so the macro can access these types.

extern crate treeflection;
#[macro_use] extern crate treeflection_derive;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

use treeflection::{NodeRunner, Node, NodeToken};

#[derive(Node, Serialize, Deserialize, Default, Clone)]
struct SolarSystem {
    pub mercury:  Planet,
    pub earth:    Planet,
    pub mars:     Planet,
        planet_x: Planet,
}

impl SolarSystem {
    pub fn new() -> SolarSystem {
        SolarSystem {
            mercury:  Planet { radius: 2440.0 },
            earth:    Planet { radius: 6371.0 },
            mars:     Planet { radius: 3390.0 },
            planet_x: Planet { radius: 1337.0 },
        }
    }
}

#[NodeActions(
    // we want the function circumference to be accessible via treeflection by the same name
    NodeAction(function="circumference", return_string),

    // we want the function explode_internal_naming_scheme to be accessible via treeflection
    // by the name explode and we want to ignore its return value so that it will compile despite not returning a String
    NodeAction(action="explode", function="explode_internal_naming_scheme"),
)]
#[derive(Node, Serialize, Deserialize, Default, Clone)]
struct Planet {
    pub radius: f32
}

impl Planet {
    pub fn circumference(&self) -> String {
        (self.radius * 2.0 * std::f32::consts::PI).to_string()
    }

    pub fn explode_internal_naming_scheme(&mut self) {
        self.radius = 0.0;
    }
}


pub fn main() {
    let mut ss = SolarSystem::new();

    // serialize the whole struct into json
    let command = ":get";
    let result = ss.node_step(NodeRunner::new(command).unwrap());
    assert_eq!(result,
r#"{
  "mercury": {
    "radius": 2440.0
  },
  "earth": {
    "radius": 6371.0
  },
  "mars": {
    "radius": 3390.0
  },
  "planet_x": {
    "radius": 1337.0
  }
}"#);

    // access properties
    let command = "earth.radius:get";
    let result = ss.node_step(NodeRunner::new(command).unwrap());
    assert_eq!(result, "6371");

    // call methods on the struct
    let command = "earth:circumference";
    let result = ss.node_step(NodeRunner::new(command).unwrap());
    assert_eq!(result, "40030.176");

    let command = "earth:explode";
    let result = ss.node_step(NodeRunner::new(command).unwrap());
    assert_eq!(result, "");
    assert_eq!(ss.earth.radius, 0.0);

    // private properties are not accessible via treeflection
    let command = "planet_x:get";
    let result = ss.node_step(NodeRunner::new(command).unwrap());
    assert_eq!(result, "SolarSystem does not have a property 'planet_x'");
}

Contributing

This library is designed around the specific needs of Canon Collision. Pull requests are welcome but if the changes go against the needs of Canon Collision you will be stuck with your own fork. :)

Dependencies

~1.2–2MB
~44K SLoC