Crates.io | rusteval |
lib.rs | rusteval |
version | 0.2.0 |
source | src |
created_at | 2020-10-27 11:51:47.438029 |
updated_at | 2022-12-01 18:08:17.038569 |
description | Make your application's structs and functions interactive |
homepage | |
repository | https://github.com/dimpolo/rusteval/ |
max_upload_size | |
id | 305964 |
size | 99,540 |
This crate provides traits and macros that make your application's structs and functions interactive.
Annotating a struct with #[derive(Interactive)]
, a struct's methods with #[Methods]
and a free function with #[Function]
will implement a set of traits,
that will allow you to access them as if Rust had a REPL.
Use this crate as an alternative for "print debugging" or as an ergonomic testing API.
This crate is no_std
compatible so you can use it to interact with embedded devices
and blink those LEDs from a USB or UART connection.
Interactive
, Methods
and Function
InteractiveRoot
for iteval_to_string
but others allow for more custom behaviour)Since this crate makes a lot of use of the Debug
trait the helper macro [PartialDebug
] is provided.
It implements Debug
for a struct replacing all fields that do not implement Debug
with a placeholder.
Functions like get_all_field_names
are provided.
This makes it possible to implement things like auto-completion.
Have a look at the autocomplete example for how this might be done using the rustyline crate.
use rusteval::{Interactive, Methods, InteractiveRoot, Function, PartialDebug};
#[derive(Default)]
struct NoDebug;
#[derive(Interactive, PartialDebug, Default)]
struct ChildStruct {
last_sum: f32,
no_debug: NoDebug,
}
#[Methods]
impl ChildStruct {
fn add(&mut self, a: f32, b: f32) -> f32 {
self.last_sum = a + b;
self.last_sum
}
}
#[derive(Interactive, Debug, Default)]
struct ParentStruct {
child: ChildStruct,
}
#[derive(InteractiveRoot, Debug, Default)]
struct Root {
parent: ParentStruct,
}
#[Function]
fn split_str_at(s: &str, mid: usize) -> (&str, &str) {
s.split_at(mid)
}
let mut root = Root::default();
assert_eq!(root.eval_to_string("parent.child.add(4.2, 6.9)"), "11.1");
assert_eq!(root.eval_to_string("parent.child"), "ChildStruct { last_sum: 11.1, no_debug: Unknown }");
// split_str_at("foobar", 3) => ("foo", "bar")
assert_eq!(root.eval_to_string("split_str_at(\"foobar\", 3)"), "(\"foo\", \"bar\")");
This crate makes use of the unstable specialization
feature, so it is only available on nightly.
Methods like try_as_interactive
are implemented on all types.
The method normally returns an error but in the specialized case
a trait object (&dyn Interactive
in this case) is returned.
The macros then implement getters that look something like this:
fn get_field<'a>(&'a self, field_name: &'a str) -> Result<'_, &dyn Interactive> {
match field_name {
"field1" => self.field1.try_as_interactive(),
"field2" => self.field2.try_as_interactive(),
_ => Err(InteractiveError::FieldNotFound {
type_name: "Struct",
field_name,
}),
}
}
See the macro's documentation for more details.
Methods and functions can only be made interactive if their argument types are supported
Enums are not supported