python_mixin!
Write Python code to emit Rust code right in your crate.
```rust
pythonmixin! {" x = 1 + 2 print('fn getx() -> u64 { %d }' % x) "}
fn main() { let value = getx(); asserteq!(value, 3); } ```
Probably not, this is mainly me experimenting with
more language
plugins. A more
portable/usable way to do this sort of code-generation is via
a Cargo
build script plus
the include!
macro.
Some downsides (not exhaustive):
python_mixin!
relies on having correctly-named Python binaries in
the user's path, and, e.g. "python
" is sometimes Python 2 and
sometimes Python 3 and it's mean to require users to have installed
Python on Windows. (Build scripts only need a Cargo and a Rust
compiler, which the user is guaranteed to have if they're trying to
build your Rust code.)
Errors in the generated code are hard to debug, although the macro does try to give as useful error messages as possible e.g. file/line numbers emitted by Python point as closely as possible to the relevant part of the original string containing the source (including working with editors' jump-to-error facilities). The parsed Rust doesn't actually appear anywhere on disk or otherwise, so you cannot easily the full context when the compiler complains (in contrast, a build script just generates a normal file right in your file-system).
Available on crates.io, so you can just add
toml
[dependencies]
python_mixin = "*"
to your Cargo.toml
.
The python_mixin!
macro consumes a single string, passes it to a
Python interpreter and then parses the output of that as Rust code. It
behaves like a macro_rules!
macro, in that it can be used in any AST
position: expression, item etc.
The string argument to python_mixin!
can be a macro invocation
itself, it is expanded before passing to Python.
Options can be specified (comma-separated) in an optional { ... }
block before the Python string. See Options for the
possible options.
Compute the Unix time that the program was built at, by calling
Python's time.time
function.
```rust
fn main() { let timeofbuild = pythonmixin! {" import time print(time.time()) "}; println!("this was compiled at {}", timeof_build); } ```
Use Python 2's naked print statement and Python 3's division semantics:
```rust
fn main() { let value2 = pythonmixin! { { version = "2" } "print 1 / 2" }; let value3 = pythonmixin! { { version = "3" } "print(1 / 2)" };
assert_eq!(value2, 0);
assert_eq!(value3, 0.5);
} ```
Compute Fibonacci numbers in the best way possible, by making Python print a function to compute each number:
```rust
// create fib0, fib1, ..., fibN functions that return the // respective fibonacci number. pythonmixin! { r#" print("fn fib0() -> u64 { 0 }") print("fn fib1() -> u64 { 1 }")
def makefunction(n): print("fn fib%d() -> u64 { fib%d() + fib%d() }" % (n, n - 1, n - 2))
for i in range(2, 30 + 1): make_function(i) "#}
fn main() { println!("the 30th fibonacci number is {}", fib_30()); } ```
| name | type | default | |
|-----------|--------|---------|-|
| version
| string | ""
| controls the version of Python used: python_mixin!
tries to execute the python{version}
binary. |
(Maybe this table will get longer? Who knows. Tables are cool.)