use regex::Regex;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
pub mod features;
const SPLIT_STR: &str = r#"//======="#;
const FEATURE_STR: &str = r#"#[cfg(feature = "#;
const FEATURE_MODE: &str = r#"#[cfg(feature = "_______")]"#;
const STR_OK: &str = r#"#[cfg(feature = "ok")]"#;
const _STR_CP: &str = r#"#[cfg(feature = "cp")]"#;
const STR_ERR: &str = r#"#[cfg(feature = "err")]"#;
const STR_NOT: &str = r#"#[cfg(all(not(feature = "ok"), not(feature = "err")))]"#;
const _STR_NOT_ALL: &str =
r#"#[cfg(all(not(feature = "ok"), not(feature = "cp"), not(feature = "err") ))]"#;
const END: &str = "\"#;";
const FN_MAIN: &str = "adjoin";
pub fn hello() {
println!("{}\n", "Start... Hello Borrowing!");
println!("{}", "use source codes:");
println!("\t\t{}", "cargo run --bin bw -- -h");
println!("\t\tcargo run --example <RUST_FILE_NAME> --features ok");
println!("\t\tcargo run --example <RUST_FILE_NAME> --features err");
println!("\texample:");
println!("\t\tcargo run --example kw_let --features ok");
println!("\n{}", "use the crate `borrowing_exerci`:");
println!("\t\t{}", "bw -h");
println!("\t\t{}", "bw --help");
println!("\t\t{}", "bw --file <RUST_FILE_NAME> --mode ok");
println!("\t\t{}", "bw --file <RUST_FILE_NAME> --mode err");
println!("\texample:");
println!("\t\t{}", "bw --file kw_let --mode err | bat -l rs ");
println!("\t\t{}", "tip: f");
println!("\t\t{}", "tip: q");
}
pub fn convert_rs(folder_name: &str, file_name: &str) {
// Create a path to the desired file
let source = read_rs(folder_name, file_name, false);
let re_feature = Regex::new(r"_______").unwrap();
let mut destination = String::new();
let re_begin = Regex::new(r"^\n").unwrap();
let re_end = Regex::new(r"\n\n$").unwrap();
let re_rs_file_name = Regex::new(r"RS").unwrap();
let begin_ok: &str = r#"pub const RS_OK :&str = r#""#;
let begin_ok = re_rs_file_name.replace_all(
begin_ok, file_name.to_uppercase().as_str()
);
let begin_ok = &format!("{}", begin_ok);
let _begin_cp: &str = r#"pub const RS_CP :&str = r#""#;
let _begin_cp = re_rs_file_name.replace_all(
_begin_cp, file_name.to_uppercase().as_str()
);
let _begin_cp = &format!("{}", _begin_cp);
let begin_err: &str = r#"pub const RS_ERR :&str = r#""#;
let begin_err = re_rs_file_name.replace_all(
begin_err, file_name.to_uppercase().as_str()
);
let begin_err = &format!("{}", begin_err);
let re_comment = Regex::new(r"^\s*//").unwrap();
let re_main = Regex::new(r"adjoin").unwrap();
// https://stackoverflow.com/questions/26643688/how-do-i-split-a-string-in-rust
let mut split: Vec<&str> = source.split(SPLIT_STR).collect();
if split.is_empty() {
unimplemented!();
} else {
if split[0].is_empty() {
unimplemented!();
} else {
let pre = split[1];
if split[1].is_empty() {
unimplemented!();
} else {
if split[2].is_empty() {
unimplemented!();
} else {
for item in split.iter_mut() {
let result = re_feature.replace(FEATURE_MODE, "ok");
if item.contains(result.as_ref()) {
print!("{}", item);
destination = format!("{}{}", pre, item);
break;
}
}
}
}
}
}
// remove the comments
//dbg!(&destination);
let lines = destination.lines();
let mut codes_str = String::new();
let mut result;
for line in lines {
if line.contains(FN_MAIN) {
result = re_main.replace(line, "main");
codes_str = format!("{}{}\n", codes_str, result.as_ref());
} else if line.contains(FEATURE_STR) {
//
} else {
if !line.is_empty() {
result = re_comment.replace(line, "");
if line == result {
codes_str = format!("{}{}\n", codes_str, result.as_ref());
}
}
}
//dbg!(&result);
}
codes_str = format!("{}{}{}", begin_ok, codes_str, END);
write_rs(file_name, codes_str);
//show_rs(file_name);
}
/*
pub fn convert_rs_x(folder_name: &str, file_name: &str) {
// Create a path to the desired file
let source = read_rs(folder_name, file_name, false);
let mut destination = String::new();
let re_begin = Regex::new(r"^\n").unwrap();
let re_end = Regex::new(r"\n\n$").unwrap();
let re_rs_file_name = Regex::new(r"RS").unwrap();
let begin_ok: &str = r#"pub const RS_OK :&str = r#""#;
let begin_ok = re_rs_file_name.replace_all(
begin_ok, file_name.to_uppercase().as_str()
);
let begin_ok = &format!("{}", begin_ok);
let _begin_cp: &str = r#"pub const RS_CP :&str = r#""#;
let _begin_cp = re_rs_file_name.replace_all(
_begin_cp, file_name.to_uppercase().as_str()
);
let _begin_cp = &format!("{}", _begin_cp);
let begin_err: &str = r#"pub const RS_ERR :&str = r#""#;
let begin_err = re_rs_file_name.replace_all(
begin_err, file_name.to_uppercase().as_str()
);
let begin_err = &format!("{}", begin_err);
let re_comment = Regex::new(r"^\s*//").unwrap();
// https://stackoverflow.com/questions/26643688/how-do-i-split-a-string-in-rust
let split: Vec<&str> = source.split(STR_OK).collect();
let pre = split[0];
if split.is_empty() {
unimplemented!();
} else {
if split[0].contains("main()") {
unimplemented!();
} else {
if split[1].contains("main()") {
destination = format!("{}{}{}", destination, begin_ok, pre);
//let split: Vec<&str> = split[1].split(STR_CP).split(STR_ERR).collect();
let split: Vec<&str> = split[1].split(STR_ERR).collect();
if split[0].contains("main()") {
//dbg!(split[0]); //ok
let result = re_begin.replace_all(split[0], "");
//let result = &format!("{}", result); // is equal to as_ref()
let result = re_end.replace_all(result.as_ref(), "\n");
destination = format!("{}{}{}\n\n", destination, result, END);
let split: Vec<&str> = split[1].split(STR_NOT).collect();
if split[0].contains("main()") {
destination = format!("{}{}{}", destination, begin_err, pre);
//dbg!(split[0]); //err
let result = re_begin.replace_all(split[0], "");
let result = re_end.replace_all(result.as_ref(), "\n");
destination = format!("{}{}{}", destination, result, END);
} else {
unimplemented!();
}
} else {
unimplemented!();
}
} else {
unimplemented!();
}
}
}
// remove the comments
//dbg!(&destination);
let lines = destination.lines();
let mut codes_str = String::new();
for line in lines {
let result = re_comment.replace_all(line, "");
if line == result {
codes_str = format!("{}{}\n", codes_str, result.as_ref());
}
//dbg!(&result);
}
write_rs(file_name, codes_str);
//show_rs(file_name);
}
*/
// https://doc.rust-lang.org/rust-by-example/std_misc/file/open.html
// https://doc.rust-lang.org/rust-by-example/std_misc/file/create.html
fn read_rs(folder_name: &str, file_name: &str, visible: bool) -> String {
let file = format!("./examples/{}/{}.rs", folder_name, file_name);
let path = Path::new(&file);
let display = path.display();
// Open the path in read-only mode, returns `io::Result<File>`
let mut file = match File::open(&path) {
// The `description` method of `io::Error` returns a string that
// describes the error
Err(why) => panic!("couldn't open {}: {}", display, why.description()),
Ok(file) => file,
};
// Read the file contents into a string, returns `io::Result<usize>`
let mut s = String::new();
match file.read_to_string(&mut s) {
Err(why) => panic!("couldn't read {}: {}", display, why.description()),
Ok(_) => {
if visible {
print!("\n\n\n{} contains:\n{}\n\n\n", display, s);
} else {
print!("successfully read to\n{}\n\n", display);
}
}
}
s
}
fn write_rs(file_name: &str, stream: String) {
// Create a path to the desired file
let file = format!("./src/features/rs_files/{}.rs", file_name);
let new_path = Path::new(&file);
let new_display = new_path.display();
// Open a file in write-only mode, returns `io::Result<File>`
let mut new_file = match File::create(&new_path) {
Err(why) => panic!("couldn't create {}: {}", new_display, why.description()),
Ok(new_file) => new_file,
};
// Write the `LOREM_IPSUM` string to `file`, returns `io::Result<()>`
match new_file.write_all(stream.as_bytes()) {
Err(why) => panic!("couldn't write to {}: {}", new_display, why.description()),
Ok(_) => println!("successfully wrote to\n{}\n\n", new_display),
}
}
/*
fn show_rs(file_name: &str) {
let file = format!("./src/features/rs_files/{}.rs", file_name);
let new_path = Path::new(&file);
let new_display = new_path.display();
// Open the path in read-only mode, returns `io::Result<File>`
let mut new_file = match File::open(&new_path) {
// The `description` method of `io::Error` returns a string that
// describes the error
Err(why) => panic!("couldn't open {}: {}", new_display,
why.description()),
Ok(new_file) => new_file,
};
let mut s = String::new();
match new_file.read_to_string(&mut s) {
Err(why) => panic!("couldn't read {}: {}", new_display,
why.description()),
Ok(_) => print!("{} contains:\n{}\n\n\n", new_display, s),
}
}
*/
pub fn allx_cmds(file_name: &str) {
let ret = format!(
r#"
# Show this command
cargo run --bin bw -- --file {0} | bat -l cmd
cargo install borrowing_exerci
bw --file {0}
bw --file {0} | bat -l cmd
# Show the Help for Rust File
cargo run --bin bw -- --file <FILENAME>
cargo install borrowing_exerci
bw --file <FILENAME> | bat -l cmd
# Run OK:
cargo run --bin bw -- --file <FILENAME> --mode ok
cargo run --example <FILENAME> --features ok
cargo install borrowing_exerci
bw --file <FILENAME> --mode ok
# Compile-Time Error:
cargo run --bin bw -- -f <FILENAME> -m err | bat -l rs
cargo run --example <FILENAME> --features err
cargo install borrowing_exerci
bw --file <FILENAME> -m err | bat -l rs
"#,
file_name
);
println!("{}", ret);
}
pub fn devx_cmds(file_name: &str) {
let ret = format!(
r#"
# Show this Help for Developer
cargo run --bin bw -- --file {0} | bat -l cmd
../target/debug/bw --file {0} | bat -l cmd
cargo install borrowing_exerci
bw --file {0}
bw --file {0} | bat -l cmd
# Use the tool cargo-expand
cargo expand --example {0} --features ok | bat -l cmd
cargo expand --example {0} --features err | bat -l cmd
RUSTFLAGS="--emit mir" cargo build --release --example {0} --features ok
RUSTFLAGS="--emit mir" cargo build --release --example {0} --features err
ls -al ../target/release/examples/{0}-*.mir
open -t ../target/release/examples/{0}-*.mir
# Show the Help for User
cargo run --bin bw -- --file {0}
../target/debug/bw --file {0}
cargo install borrowing_exerci
bw --file {0} | bat -l cmd
# Run OK:
cargo run --example {0} --features ok | bat -l cmd
cargo run --bin bw -- --file {0} --mode ok | bat -l cmd
../target/debug/bw --file {0} --mode ok | bat -l cmd
cargo install borrowing_exerci
bw --file {0} --mode ok
# Compile-Time Error:
cargo run --example {0} --features err | bat -l cmd
cargo run --bin bw -- -f {0} -m err | bat -l rs
../target/debug/bw --file {0} --mode err | bat -l cmd
cargo install borrowing_exerci
bw --file {0} -m err | bat -l rs
"#,
file_name
);
println!("{}", ret);
}
pub fn user_cmds(file_name: &str) {
let ret = format!(
r#"
// Show this command
cargo install borrowing_exerci
bw --file {0} | bat -l cmd
// Run OK:
cargo install borrowing_exerci
bw --file <RS_FILE_NAME> --mode ok | bat -l rs
// Compile-Time Error:
cargo install borrowing_exerci
bw --file <RS_FILE_NAME> -m err | bat -l rs
"#,
file_name
);
println!("{}", ret);
}
//## 题外话
//- https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=50eaf399f641e0965e86be08a6d2d777
// https://stackoverflow.com/questions/26946646/rust-package-with-both-a-library-and-a-binary
// Cow, as_ref()
// https://stackoverflow.com/questions/47147844/how-do-i-get-a-str-or-string-from-stdborrowcowstr
// https://jwilm.io/blog/from-str-to-cow/
// fn contains
// https://stackoverflow.com/questions/48794974/how-to-check-if-a-string-contains-a-substring-in-rust
// fn is_empty
// https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.is_empty
// regex
// https://stackoverflow.com/questions/19274493/regular-expression-match-lines-starting-with-a-certain-character-or-whitespace-a
// https://stackoverflow.com/questions/1240504/regular-expression-to-match-string-starting-with-stop
// fn split
// https://stackoverflow.com/questions/26643688/how-do-i-split-a-string-in-rust
// fn to_uppercase
// https://doc.rust-lang.org/std/char/struct.ToUppercase.html
// file read write
// https://doc.rust-lang.org/rust-by-example/std_misc/file/open.html
// https://doc.rust-lang.org/rust-by-example/std_misc/file/create.html