Rust Tips
Installation
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
rustc --version
Prepare data
wget https://ftp.ncbi.nlm.nih.gov/pub/clinvar/tab_delimited/variant_summary.txt.gz
gunzip variant_summary.txt.gz
Hello world
- Tạo
hello.rs
fn main() {
println!("Hello");
}
- Compile
rustc hello.rs
- Run
./hello
Hello world with Cargo
- Tạo project
cargo new hello
cd hello
- Edit
/src/main.rs
fn main() {
println!("Hello");
}
- Compile
cargo build
- Run
cargo run
Tối ưu hóa khi chạy
cargo run --release
Working with MySQL
use mysql::*;
use mysql::prelude::*;
use chrono::prelude::*; //For date and time
fn main() {
let opts = OptsBuilder::new()
.ip_or_hostname(Some("127.0.0.1"))
.user(Some("username"))
.pass(Some("password"))
.db_name(Some("database"));
let pool = Pool::new(opts).unwrap();
let mut conn = pool.get_conn().unwrap();
}
Query
conn.query_iter("select TITLE, MIM_NUMBER from CLINICAL_SYNOPSIS LIMIT 0, 10")
.unwrap()
.for_each(|row| {
let r:(String, String) = from_row(row.unwrap());
println!("{:?}, {:?}", r.0, r.1);
});
Insert
pub struct Clinvar {
pub VARIANT: String,
pub CLINICAL: String,
pub PHENOTYPE: String
}
fn main() {
...
let clinvar = Clinvar {
VARIANT: String::from("NM_139007.3(HFE):c.77-273G>C"),
CLINICAL: String::from("Pathogenic"),
PHENOTYPE: String::from("xxx")
};
match insert_clinvar(&mut conn, &clinvar) {
Ok(last_id) => println!("Inserted product with ID {}", last_id),
Err(e) => println!("Error: {:?}", e),
}
}
fn insert_clinvar(
conn: &mut PooledConn,
clinvar: &Clinvar) -> std::result::Result<u64, mysql::error::Error> {
let uuid = ::uuid::Uuid::new_v4();
conn.exec_drop(
"insert into CLINVAR (VARIANT, CLINICAL, PHENOTYPE, GUID, UDID, UUID) values (:variant, :clinical, :phenotype, 1, 1, :uuid)",
params! {
"variant" => &clinvar.VARIANT,
"clinical" => &clinvar.CLINICAL,
"phenotype" => &clinvar.PHENOTYPE,
"uuid" => uuid.simple().to_string()
},
)
.and_then(|_| Ok(conn.last_insert_id()))
}
UUID
Thêm vào trong Cargo.toml
ở mục dependencies như sau:
[dependencies]
uuid = { version = "0.6", features = ["serde", "v4"] }
Trong code, tạo UUID như sau:
let uuid = ::uuid::Uuid::new_v4();
let uuid_string = uuid.simple().to_string();
let uuid_string_2 = uuid.hyphenated().to_string();
Ellapsed time
REF: https://rust-lang-nursery.github.io/rust-cookbook/datetime/duration.html
use std::time::{Duration, Instant};
fn main() {
let start = Instant::now();
expensive_function();
let duration = start.elapsed();
println!("Time elapsed in expensive_function() is: {:?}", duration);
}
String replacement using regex
Add to Cargo.toml
[dependencies]
lazy_static = "*"
regex = "*"
Sample code:
use lazy_static::lazy_static;
use regex::Regex;
use std::borrow::Cow;
fn ensure_variant_name(name: &str) -> Cow<str> {
lazy_static! {
static ref NAME_REGEX : Regex = Regex::new(
r"(?P<p1>[^\(]+)\([A-Z0-9]+\)(?P<p2>[^\(]+)\(?.*"
).unwrap();
}
NAME_REGEX.replace_all(name, "$p1$p2")
}
Chạy code xử lý genome
cp9
cd dev/rust/hello/
cargo run --release
Curl & proxy
HTTP client
- If you want a low-level HTTP library in Rust, I recommend using hyper. It’s production-ready and fully written in Rust so you don’t have to worry too much about safety issues. Moreover, it’s the only library that mentions production-readiness.
- For a more high-level HTTP library, I would go with reqwest. The library is built on top of hyper, so it offers many of the same advantages as hyper and has a more convenient syntax to boot.
Rust & blockchain
- Tutorials:
- RESOUCES: https://github.com/rust-in-blockchain/awesome-blockchain-rust
- https://ethereum.org/en/developers/docs/programming-languages/rust/
Rust & bitcoin
- https://github.com/rust-bitcoin/rust-bitcoin
- https://www.reddit.com/r/rust/comments/a93dv8/cryptocurrencies_written_in_rust/
- https://ethereum.org/en/developers/docs/programming-languages/rust/
Scraper
- Dùng thư viện
https://crates.io/crates/scraper
- Scrapping is io bound so I wouldn’t bother choosing the language with performance as the criterion. Instead, I focus more on what the frameworks provide and ease of coding.
Count by lines
// We want to use the lines method from this trait
use std::io::BufRead;
// Let's us use ? for simple error handling
fn main() -> Result<(), std::io::Error> {
// Try to open the file
let file = std::fs::File::open("input.txt")?;
// Create a buffered version of the file so we can use lines
let buffered = std::io::BufReader::new(file);
// Iterate through each line in the file
for line in buffered.lines() {
// But we get a Result each time, get rid of the errors
let line = line?;
// And print out the line length and content
println!("{} {}", line.len(), line);
}
// Everything went fine, so we return Ok
Ok(())
}
Web server
- Nên dùng actix-web cho web API
use actix_web::{web, App, HttpRequest, HttpServer, Responder};
async fn greet(req: HttpRequest) -> impl Responder {
let name = req.match_info().get("name").unwrap_or("World");
format!("Hello {}!", &name)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/", web::get().to(greet))
.route("/{name}", web::get().to(greet))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
References
- Working with MySQL: https://mobiarch.wordpress.com/2020/06/02/access-mysql-from-rust-part-i/