2 releases
0.1.1 | Jul 9, 2022 |
---|---|
0.1.0 | Jul 9, 2022 |
#491 in Procedural macros
Used in nalgebra_latex
21KB
284 lines
Execution of evcxr
-flavored Rust
Further evcxr
can refer to the evaluation context,
to Jupyter kernel for Rust programming language, or to its supported script-like syntax.
Example of evcxr
-flavored Rust
:dep image = "0.23"
:dep evcxr_image = "1.1"
// In a pure Rust project, the dependencies above would be specified in Cargo.toml
use evcxr_image::ImageDisplay;
image::ImageBuffer::from_fn(256, 256, |x, y| {
if (x as i32 - y as i32).abs() < 3 {
image::Rgb([0, 0, 255])
} else {
image::Rgb([0, 0, 0])
}
})
Example for Jupyter Notebook with evcxr
kernel
:dep execute_evcxr = { version = "0.1.2" }
use execute_evcxr::{execute_evcxr, Config};
// This way it's possible to specify the non-default values
let config = Config { verbose: false, ..Default::default() };
execute_evcxr(r#"
:dep nalgebra = "0.31.0"
:dep nalgebra_latex = { version = "0.1.6", features = ["lin_sys", "evcxr"] }
use nalgebra::{matrix, Const};
use nalgebra_latex::{
lin_sys::{
LinSys,
unknowns::SingleLetterBoldfaceVecOfUnknowns,
numbering::Numbering,
fmt::CasesLinSysFormatter,
},
fmt::EvcxrOutputFormatter,
};
use std::io::{stdout, Write};
let mut s = String::new();
let m = matrix!(
1,2,3;
4,5,6;
7,8,9;
);
let vec_of_unknowns = SingleLetterBoldfaceVecOfUnknowns::<_,{Numbering::OneBased}>::new('x', Const::<3>);
let ls = LinSys::new(m, vec_of_unknowns);
CasesLinSysFormatter::write_evcxr_output(&mut s, &ls).unwrap();
stdout().write_all(s.as_bytes()).unwrap();
"#, config);
Example for Rust project
extern crate execute_evcxr;
use execute_evcxr::{execute_evcxr, Config};
fn main() {
let config = Config { ..Config::default() };
execute_evcxr(r#"
:dep nalgebra = "0.31.0"
:dep nalgebra_latex = { version = "0.1.6", features = ["lin_sys", "evcxr"] }
use nalgebra::{matrix, Const};
use nalgebra_latex::{
lin_sys::{
LinSys,
unknowns::SingleLetterBoldfaceVecOfUnknowns,
numbering::Numbering,
fmt::CasesLinSysFormatter,
},
fmt::EvcxrOutputFormatter,
};
use std::io::{stdout, Write};
let mut s = String::new();
let m = matrix!(
1,2,3;
4,5,6;
7,8,9;
);
let vec_of_unknowns = SingleLetterBoldfaceVecOfUnknowns::<_,{Numbering::OneBased}>::new('x', Const::<3>);
let ls = LinSys::new(m, vec_of_unknowns);
CasesLinSysFormatter::write_evcxr_output(&mut s, &ls).unwrap();
stdout().write_all(s.as_bytes()).unwrap();
"#, config);
}
At the moment of writing, the original evcxr
kernel supports a lot but not all 1 features of Rust. This crate has been born as a temporary solution to the problem.
Note on evcxr
-flavored Rust
The syntax supported by evcxr
kernel, as opposed to pure Rust, is implementation-defined. As a result, the same evcxr
-flavored script can be executed differently by execute_evcxr
and evcxr
itself. In case of discrepancies, the behavior of evcxr
is considered correct and the deviation on the side of execute_evcxr
must be treated a bug, unless stated otherwise.
Note on limitations
-
As its name suggests,
execute_evcxr
is not an evaluation context in contrast toevcxr
. It does not "return" a value. It executes a given script supplied in the form of string instead of attempting to evaluate it, unlikeevcxr
. -
execute_evcxr
gets its job done by parsing the supplied script only. It does not analyze the source code of the crates-dependencies. This fact will become important further in the text. -
Because
execute_evcxr
is a temporary solution, it does not try to memoize which macros were defined in the script and to which kinds of syntactic entities it would expand. This fact will become important further in the text. -
execute_evcxr
works by parsingevcxr
-flavored Rust, building a binary crate from it in the temporary dir, executing the binary crate, and cleaning up. Therefore, it must know which syntactic entities (or, more precisely, "statements") should go inside themain()
function. This fact will become important further in the text. -
Due to the last three limitations above, the developer might need to annotate every macro invocation that eventually expands to "items" using
#[expands_only_to_items]
attribute. Otherwise, they will be placed inside main function. Luckily, the most common macros do not require the attribute and in many cases even if the macros do expands to "items" in themain()
, the binary crate can still work as expected. -
Execution speed of the scripts is bounded to building them anew, including downloading dependencies from the internet. It can be a wise idea to set up caching. The library author hasn't faced the need for caching, yet.
For library developers
This is a README for library users. There's a separate DEV-README.md with information that can be relevant only to library developers.
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Dependencies
~1.5MB
~37K SLoC