Here we've got some examples of things you can do with rerast. If you've got any more examples, please feel free to send pull requests.
fn rule1<T,E,X: From<E>>(r: Result<T,E>) -> Result<T,X> {
replace!(r#try!(r) => r?);
unreachable!()
}
This will change:
pub fn get_file_contents(filename: &std::path::Path) -> std::io::Result<String> {
let mut result = String::new();
use std::io::Read;
try!(try!(std::fs::File::open(filename)).read_to_string(&mut result));
Ok(result)
}
Into this:
pub fn get_file_contents(filename: &std::path::Path) -> std::io::Result<String> {
let mut result = String::new();
use std::io::Read;
std::fs::File::open(filename)?.read_to_string(&mut result)?;
Ok(result)
}
This rule also shows how to handle rules that have return statements in
them. i.e. specify a return type for your rule function. unreachable!()
can then be used to avoid having to construct an actual value.
fn r(mut p: Point, x: i32, y: i32) {
replace!(Point{ x: x, y: y } => Point::new(x, y));
replace!(p.x = x => p.set_x(x));
replace!(&mut p.x => p.get_mut_x());
replace!(p.x => p.get_x());
}
This will change:
fn f1(point: Point, point_ref: &Point, mut_point_ref: &mut Point) {
let p2 = Point { x: 1, y: 2 };
process_i32(point.x);
mut_point_ref.x = 1;
let x = &mut mut_point_ref.x;
*x = 42;
process_i32(point_ref.x);
}
Into:
fn f1(point: Point, point_ref: &Point, mut_point_ref: &mut Point) {
let p2 = Point::new(1, 2);
process_i32(point.get_x());
mut_point_ref.set_x(1);
let x = mut_point_ref.get_mut_x();
*x = 42;
process_i32(point_ref.get_x());
}
This is a real world example from the Cargo project (issue, PR).
use cargotest::support::{ project, project_foo };
fn rule1(a: &'static str) {
replace!(project("foo") => project_foo());
replace!(project(a) => project_foo().at(a));
}
Changes:
let p = project("foo")
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.build();
let _p2 = project("bar")
.file("Cargo.toml", &basic_bin_manifest("bar"))
.file("src/bar.rs", &main_file(r#""i am bar""#, &[]))
.build();
Into:
let p = project_foo()
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.build();
let _p2 = project_foo().at("bar")
.file("Cargo.toml", &basic_bin_manifest("bar"))
.file("src/bar.rs", &main_file(r#""i am bar""#, &[]))
.build();
When run like this:
cargo +nightly rerast --rules_file=rewrite.rs --force --targets tests --file tests/testsuite/main.rs
Afterwhich a simple search and replace can rename project_foo
back to project
and the argument
can be dropped.
Since await can only be used from within an async function, you'll need to delcare your rule function async. This cannot be done from the command line, so you'll need to create a rule file with the following contents:
async fn rule1<T: std::future::Future>(r: T) {
replace!(await!(r) => r.await)
}
Since yield can only be used from within a generator, you'll need to delcare your replace rule inside a generator. For example:
fn r1(x: i32) {
let _ = || {
replace!(yield x => yield x + 1);
};
}