#tree #reflection #treeflection

macro treeflection_derive

#[derive(Node)] macro for the Treeflection library

23 releases

0.4.0 Aug 14, 2019
0.3.2 Sep 14, 2018
0.3.0 May 23, 2018
0.2.0 Jan 14, 2018
0.1.8 Nov 30, 2016

#85 in #reflection

Download history 2/week @ 2024-07-29 34/week @ 2024-09-23 2/week @ 2024-09-30

85 downloads per month
Used in 2 crates

MIT license

27KB
593 lines

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.7–2.4MB
~54K SLoC