diff --git a/README.md b/README.md index b8c28aadf..9dcb647b4 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,13 @@ cargo build --release --target wasm32-wasi --features="freeze-stdlib" > Note: we use the `freeze-stdlib` to include the standard library inside the binary. + +## Embedding RustPython into your Rust Applications + +Interested in exposing Python scripting in an application written in Rust, +perhaps to allow quickly tweaking logic where Rust's compile times would be inhibitive? +Then `examples/hello_embed.rs` and `examples/mini_repl.rs` may be of some assistance. + ## Disclaimer RustPython is in a development phase and should not be used in production or a diff --git a/examples/hello_embed.rs b/examples/hello_embed.rs new file mode 100644 index 000000000..c8c5a8c54 --- /dev/null +++ b/examples/hello_embed.rs @@ -0,0 +1,20 @@ +use rustpython_compiler::compile; +use rustpython_vm::{pyobject::PyResult, PySettings, VirtualMachine}; + +fn main() -> PyResult<()> { + let vm = VirtualMachine::new(PySettings::default()); + + let scope = vm.new_scope_with_builtins(); + + let code_obj = vm + .compile( + r#"print("Hello World!")"#, + compile::Mode::Exec, + "".to_string(), + ) + .map_err(|err| vm.new_syntax_error(&err))?; + + vm.run_code_obj(code_obj, scope)?; + + Ok(()) +} diff --git a/examples/mini_repl.rs b/examples/mini_repl.rs new file mode 100644 index 000000000..8cbdb35c3 --- /dev/null +++ b/examples/mini_repl.rs @@ -0,0 +1,53 @@ +///! This example show cases a very simple REPL. +///! While a much better REPL can be found in ../src/shell, +///! This much smaller REPL is still a useful example because it showcases inserting +///! values and functions into the Python runtime's scope, and showcases use +///! of the compilation mode "Single". +///! Note that in particular this REPL does a horrible job of showing users their errors +///! (instead it simply crashes). +use rustpython_compiler::compile; +use rustpython_vm::{pyobject::PyResult, PySettings, VirtualMachine}; +// this needs to be in scope in order to insert things into scope.globals +use rustpython_vm::pyobject::ItemProtocol; + +fn main() -> PyResult<()> { + let mut on = true; + + let mut input = String::with_capacity(50); + let stdin = std::io::stdin(); + + let vm = VirtualMachine::new(PySettings::default()); + let scope = vm.new_scope_with_builtins(); + + // typing `quit()` is too long, let's make `on(False)` work instead. + scope + .globals + .set_item( + "on", + vm.context().new_rustfunc({ + let on: *mut bool = &mut on; + move |b: bool, _: &VirtualMachine| unsafe { *on = b } + }), + &vm, + ) + .unwrap(); + + while on { + input.clear(); + stdin.read_line(&mut input).unwrap(); + + let code_obj = vm + .compile(&input, compile::Mode::Single, "".to_string()) + .map_err(|err| vm.new_syntax_error(&err))?; + + // this line also automatically prints the output + let output = vm.run_code_obj(code_obj, scope.clone())?; + + // store the last value in the "last" variable + if !vm.is_none(&output) { + scope.globals.set_item("last", output, &vm).unwrap(); + } + } + + Ok(()) +}