Loading

RUST实践.md

RUST实践

密码

自定义密码

use rand::Rng;

pub fn main() {
    const CHARSET: &[u8] = b"abcdefghijklmnopqrstuvwxyz\
                            0123456789)(*&^%$#@!~)";
    const PASSWORD_LEN: usize = 30;
    let mut rng = rand::thread_rng();
    let password: String = (0..PASSWORD_LEN)
        .map(|_|{
            let idx = rng.gen_range(0..CHARSET.len());
            CHARSET[idx] as char
        })
        .collect();
        println!("密码:{}", password);
}

Vector排序

整数

fn main() {
    let mut vec = vec![1, 5, 8, 90, 89];
    println!("前: {:?}", vec);

    vec.sort();
    println!("后: {:?}", vec);
    assert_eq!(vec, vec![1, 5, 8, 90, 89]); // failed
}

浮点数

fn main() {
    let mut vec = vec![1.8, 5.1, 8.9, 0.90, 8.9];
    println!("前: {:?}", vec);

    vec.sort_by(|a, b| a.partial_cmp(b).unwrap());
    println!("后: {:?}", vec);
}

结构体

#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
struct Person {
    name: String,
    age: u32
}

impl Person {
    pub fn new(name: &str, age: u32) -> Self {
        Person {
            name: name.to_string(),
            age
        }
    }
}

pub fn main() {
    let mut peoples = vec![
        Person::new("Zhang", 25),
        Person::new("Liu", 60),
        Person::new("Wang", 18),
    ];
    println!("前: {:?}", peoples);
    peoples.sort_by(|a, b| b.age.cmp(&a.age));
    println!("后:{:?}", peoples);
}

命令行参数

use clap::{Arg, App};

pub fn main() {
    let matches = App::new("测试程序")
        .version("0.1.0")
        .author("MUWUREN")
        .about("Test clap")
        .arg(Arg::with_name("file")
             .short("f")
             .long("file")
             .takes_value(true)
             .help("a cool file"))
        .arg(Arg::with_name("num")
             .short("n")
             .long("num")
             .takes_value(true)
             .help("Five less than"))
        .get_matches();

    let myfile = matches.value_of("file").unwrap_or("input.txt");
    println!("file: {}", myfile);

    let num_str = matches.value_of("num");
    match num_str {
        None => println!("No idea!"),
        Some(s) => {
            match s.parse::<i32>() {
                Ok(n) => println!("NUM: {}", n),
                Err(e) => println!("Error: '{}', {}", s, e),
            }
        }
    }
}

终端颜色

use ansi_term::{Colour, Style};

pub fn main() {
    // color
    println!("This is {} in color, {} in color and {} in color",
             Colour::Red.paint("red"),
             Colour::Blue.bold().paint("blue"),
             Colour::Green.bold().paint("green")); // color and bold

    // Bold
    println!("{} and this is not", Style::new().bold().paint("BOLD"));
}

Tar

解压

use std::fs::File;
use flate2::read::GzDecoder;
use tar::Archive;

fn main() -> Result<(), std::io::Error> {
    let path = "archive.tar.gz";

    let tar_gz = File::open(path)?;
    let tar = GzDecoder::new(tar_gz);
    let mut archive = Archive::new(tar);
    archive.unpack(".")?;

    Ok(())
}

压缩

use std::fs::File;
use flate2::Compression;
use flate2::write::GzEncoder;

pub fn main() -> Result<(), std::io::Error>{
    let tar_gz = File::create("ab.tar.gz")?;
    let enc = GzEncoder::new(tar_gz, Compression::default());
    let mut tar = tar::Builder::new(enc);
    tar.append_dir_all("logs/", "/tmp/ccls/")?;
    Ok(())
}

线程

短期线程

pub fn main() {
    let arr = &[1, 25, 3, -4];
    let max = find_max(arr);
    assert_eq!(max, Some(25));
}

fn find_max(arr: &[i32]) -> Option<i32> {
    const THRESHOLD: usize = 2;
    if arr.len() <= THRESHOLD {
        return arr.iter().cloned().max();
    }
    let mid = arr.len() / 2;
    let (left, right) = arr.split_at(mid);

    crossbeam::scope(|s| {
        let thread_l = s.spawn(|_| find_max(left));
        let thread_r = s.spawn(|_| find_max(right));

        let max_l = thread_l.join().unwrap()?;
        let max_r = thread_r.join().unwrap()?;

        Some(max_l.max(max_r))
    }).unwrap()
}

管道

extern crate crossbeam;
extern crate crossbeam_channel;

use crossbeam_channel::bounded;
use std::thread;
use std::time::Duration;

pub fn main() {
    let (snd1, rcv1) = bounded(1);
    let (snd2, rcv2) = bounded(1);
    let n_msgs = 4;
    let n_workers = 2;

    crossbeam::scope(|s| {
        s.spawn(|_| {
            for i in 0..n_msgs {
                snd1.send(i).unwrap();
                println!("Source sent {}", i);
            }
            // close channel
            drop(snd1);
        });

        for _ in 0..n_workers {
            let (sendr, recvr) = (snd2.clone(), rcv1.clone());
            s.spawn(move |_| {
                thread::sleep(Duration::from_secs(1));
                for msg in recvr.iter() {
                    println!("Worker {:?} received {}", thread::current().id(), msg);
                    sendr.send(msg * 2).unwrap();
                }
            });
        }
        drop(snd2);

        for msg in rcv2.iter() {
            println!("Sink received {}", msg);
        }
    }).unwrap();
}

无限容量管道

use std::{thread, time};
use crossbeam_channel::unbounded;

pub fn main() {
    let (snd, rcv) = unbounded();
    let n_msgs = 5;
    crossbeam::scope(|s| {
        s.spawn(|_| {
            for i in 0..n_msgs {
                snd.send(i).unwrap();
                thread::sleep(time::Duration::from_secs(1));
            }
        });
    }).unwrap();
    for _ in 0..n_msgs {
        let msg = rcv.recv().unwrap();
        println!("{}", msg);
    }
}

全局变量

use error_chain::error_chain;
use lazy_static::lazy_static;
use std::sync::Mutex;

error_chain!{ }

lazy_static! {
    static ref FRUIT: Mutex<Vec<String>> = Mutex::new(Vec::new());
}

fn insert(fruit: &str) ->  Result<()> {
    let mut db = FRUIT.lock().map_err(|_| "Failed to acquire MutexGuard!")?;
    db.push(fruit.to_string());
    Ok(())
}

pub fn main() -> Result<()> {
    insert("apple")?;
    insert("orange")?;
    insert("peach")?;
    {
        let db = FRUIT.lock().map_err(|_| "Failed TO acquire MutexGuard")?;
        db.iter().enumerate().for_each(|(i, item)| println!("{}: {}", i, item));
    }
    insert("grape")?;
    Ok(())
}

SHA计算

use walkdir::WalkDir;
use std::fs::File;
use std::io::{BufReader, Read, Error};
use threadpool::ThreadPool;
use std::path::Path;
use std::sync::mpsc::channel;
use ring::digest::{Context, Digest, SHA256};

fn is_iso(entry: &Path) -> bool {
    match entry.extension() {
        Some(e) if e.to_string_lossy().to_lowercase() == "iso" => true,
        _ => false
    }
}

fn compute_digest<P: AsRef<Path>>(filepath: P) -> Result<(Digest, P), Error> {
    let mut buf_reader = BufReader::new(File::open(&filepath)?);
    let mut context = Context::new(&SHA256);
    let mut buffer = [0; 1024];

    loop {
        let count = buf_reader.read(&mut buffer)?;
        if count == 0 {
            break;
        }
        context.update(&buffer[..count]);
    }
    Ok((context.finish(), filepath))
}

pub fn main() -> Result<(), Error> {
    let pool = ThreadPool::new(num_cpus::get());

    let (tx, rx) = channel();
    
    for entry in WalkDir::new("/home/nsfoxer/ISO")
        .follow_links(true)
        .into_iter()
        .filter_map(|e| e.ok())
        .filter(|e| !e.path().is_dir() && is_iso(e.path())) {
            let path = entry.path().to_owned();
            let tx = tx.clone();
            pool.execute(move || {
                let digest = compute_digest(path);
                tx.send(digest).expect("Could not send data!");
            });
        }
    drop(tx);
    for t in rx.iter() {
        let (sha, path) = t?;
        println!("{:?}, {:?}", sha, path);
    }
    Ok(())
}

绘图

朱利亚集 f(n+1)=f(n)*f(n)+c

use error_chain::error_chain;
use std::sync::mpsc::{channel, RecvError};
use threadpool::ThreadPool;
use num::complex::Complex;
use image::{ImageBuffer, Pixel, Rgb};

error_chain! {
    foreign_links {
        MpscRecv(RecvError);
        Io(std::io::Error);
    }
}

fn wavelength_to_rgb(wavelength: u32) -> Rgb<u8> {
    let wave = wavelength as f32;

    let (r, g, b) = match wavelength {
        380..=439 => ((440.-wave)/(440.-380.), 0.0, 1.0),
        440..=489 => (0.0, (wave - 440.) / (490. - 440.), 1.0),
        490..=509 => (0.0, 1.0, (510. - wave) / (510. - 490.)),
        510..=579 => ((wave - 510.) / (580. - 510.), 1.0, 0.0),
        580..=644 => (1.0, (645. - wave) / (645. - 580.), 0.0),
        645..=780 => (1.0, 0.0, 0.0),
        _ => (0.0, 0.0, 0.0),
    };
    let factor = match wavelength {
        380..=419 => 0.3 + 0.7 * (wave - 380.) / (420. - 380.),
        701..=780 => 0.3 + 0.7 * (780. - wave) / (780. - 700.),
        _ => 1.0,
    };

    let (r, g, b) = (normalize(r, factor), normalize(g, factor), normalize(b, factor));
    Rgb::from_channels(r, g, b, 0)
}

fn julia(c: Complex<f32>, x: u32, y:u32, width: u32, height: u32, max_iter: u32) ->  u32 {
    let width = width as f32;
    let height = height as f32;

    let mut z = Complex {
        re: 3.0 * (x as f32 - 0.5*width) / width,
        im: 2.0 * (y as f32 - 0.5*height) / height,
    };

    let mut i = 0;
    for t in 0..max_iter {
        if z.norm() >= 2.0 {
            break;
        }
        z = z*z+c;
        i = t;
    }
    i
}

fn normalize(color: f32, factor: f32) -> u8 {
    ((color * factor).powf(0.8) * 255.) as u8
}

pub fn main() -> Result<()> {
    let (width, height) = (1920, 1080);
    let mut img = ImageBuffer::new(width, height);
    let iterations = 300;

    let c = Complex::new(-0.8, 0.156);
    let pool = ThreadPool::new(num_cpus::get());
    let (tx, rx) = channel();

    for y in 0..height {
        let tx = tx.clone();
        pool.execute(move || for x in 0..width {
            let i = julia(c, x, y, width, height, iterations);
            let pixel = wavelength_to_rgb(380+i*400/iterations);
            tx.send((x, y, pixel)).expect("Could not send data!");
        });
    }

    for _ in 0..(width*height) {
        let (x, y, pixel) = rx.recv()?;
        img.put_pixel(x, y, pixel);
    }
    let _ = img.save("output.png").unwrap();
    Ok(())
}

改变数组

use rayon::prelude::*;

fn main() {
    let mut arr = [0, 7, 9, 11];
    arr.par_iter_mut().for_each(|p| *p -= 1);
    println!("{:?}", arr);
}

数组测试

use rayon::prelude::*;

pub fn main() {
    let arr = vec![1, 7, 9, 11];

    // any() --> 只要有一个
    // all() --> 全部都要
    assert!(!arr.par_iter().any(|n| (*n % 2) == 0));
    assert!(arr.par_iter().all(|n| (*n % 2) != 0));

    // 查找到第一个元素就返回,但不一定是vec的第一个元素
    assert_eq!(arr.par_iter().find_any(|&&x| x == 9), Some(&9));

}

排序

use rand::{Rng, thread_rng};
use rand::distributions::Alphanumeric;
use rayon::prelude::*;

pub fn main() {
    let mut arr = vec![String::new(); 100];
    arr.par_iter_mut().for_each(|p| {
        let mut rng = thread_rng();
        *p = (0..50).map(|_| rng.sample(&Alphanumeric)).map(char::from).collect()
    });
    arr.par_sort_unstable();
    println!("{:?}", arr);

}

Map-Reduce

use rayon::prelude::*;

struct Person {
    age: u32,
}

pub fn main() {
    let v: Vec<Person> = vec![
        Person { age: 23 },
        Person { age: 19 },
        Person { age: 42 },
        Person { age: 17 },
        Person { age: 17 },
        Person { age: 31 },
        Person { age: 30 },
    ];

    let num_over_30 = v.par_iter().filter(|&x| x.age > 30).count() as f32;
    let sum_over_30 = v
        .par_iter()
        .map(|x| x.age)
        .filter(|&x| x > 30)
        .reduce(|| 0, |x, y| x + y);
    let alt_sum_30: u32 = v.par_iter().map(|x| x.age).filter(|&x| x > 30).sum();
    let avg_over_30 = sum_over_30 as f32 / num_over_30;
    let alt_avg_over_30 = alt_sum_30 as f32 / num_over_30;

    assert!((avg_over_30 - alt_avg_over_30).abs() < std::f32::EPSILON);
    println!("The average age of people older than 30 is {}", avg_over_30);
}

缩略图

use error_chain::error_chain;

use std::path::Path;
use std::fs::create_dir_all;

use error_chain::ChainedError;
use glob::{glob_with, MatchOptions};
use image::{ImageError, imageops::FilterType};
use rayon::prelude::*;

error_chain! {
    foreign_links {
        Image(ImageError);
        Io(std::io::Error);
        Glob(glob::PatternError);
    }
}

pub fn main() -> Result<()>{
    let options: MatchOptions = Default::default();
    let files: Vec<_> = glob_with("*.jpg", options)?
        .filter_map(|x| x.ok())
        .collect();

    if files.len() == 0 {
        error_chain::bail!("No .jpg was founded!");
    }
    
    let thumb_dir = "thumbnails";
    create_dir_all(thumb_dir)?;
    println!("Save {} thumbnails into `{}`...", files.len(), thumb_dir);

    let image_failures: Vec<_> = files
        .par_iter()
        .map(|path|{
            make_thumbnail(path, thumb_dir, 300)
                .map_err(|e| e.chain_err(|| path.display().to_string()))
        })
    .filter_map(|x| x.err())
    .collect();
    image_failures.iter().for_each(|x| println!("{}", x.display_chain()));

    println!("{} thumbnails saved successfully", files.len() - image_failures.len());
    Ok(())
}

fn make_thumbnail<PA, PB>(original: PA, thumb_dir: PB, longest_edge: u32) -> Result<()>
where
    PA: AsRef<Path>,
    PB: AsRef<Path>,
{
    let img = image::open(original.as_ref())?;
    let file_path = thumb_dir.as_ref().join(original);

    Ok(img.resize(longest_edge, longest_edge, FilterType::Nearest)
       .save(file_path)?)
}

密码

SHA256

use error_chain::error_chain;
use data_encoding::HEXUPPER;
use ring::digest::{Context, Digest, SHA256};
use std::fs::File;
use std::io::{BufReader, Read, Write};

error_chain! {
    foreign_links {
        Io(std::io::Error);
        Decode(data_encoding::DecodeError);
    }
}

fn sha256_digest<R: Read>(mut reader: R) -> Result<Digest> {
    let mut context = Context::new(&SHA256);
    let mut buffer = [0; 1024];

    loop {
        let count = reader.read(&mut buffer)?;
        if count == 0 {
            break;
        }
        context.update(&buffer[..count]);
    }
    Ok(context.finish())
}

pub fn main() -> Result<()>{
    let path = "file.txt";

    let mut output = File::create(path)?;
    write!(output, "We will generate a digest of the text")?;

    let input = File::open(path)?;
    let reader = BufReader::new(input);
    let digest = sha256_digest(reader)?;

    println!("SHA-256 digest is {}", HEXUPPER.encode(digest.as_ref()));
    Ok(())
}

HMAC签名和校验

use ring::{hmac, rand};
use ring::rand::SecureRandom;
use ring::error::Unspecified;

pub fn main() -> Result<(), Unspecified> {
    let mut key_value = [0u8; 48];
    let rng = rand::SystemRandom::new();
    rng.fill(&mut key_value)?;
    let key = hmac::Key::new(hmac::HMAC_SHA256, &key_value);

    let message = "Legitimate and import message";
    println!("{}", &message);

    let signature = hmac::sign(&key, message.as_bytes());
    println!("{:?}", &signature);

    hmac::verify(&key, message.as_bytes(), signature.as_ref())?;

    Ok(())
}

密码salt和hash

use data_encoding::HEXUPPER;
use ring::rand::SecureRandom;
use ring::{digest, pbkdf2, rand};
use ring::error::Unspecified;
use std::num::NonZeroU32;

pub fn main() -> Result<(), Unspecified> {
    const CREDENTIAL_LEN: usize = digest::SHA512_OUTPUT_LEN;
    let n_iter = NonZeroU32::new(100_000).unwrap();
    let rng = rand::SystemRandom::new();

    let mut salt = [0u8; CREDENTIAL_LEN];
    rng.fill(&mut salt)?;

    let password = "Guess Me If You Can";
    let mut pbkdf2_hash = [0u8; CREDENTIAL_LEN];
    pbkdf2::derive(
        pbkdf2::PBKDF2_HMAC_SHA512,
        n_iter,
        &salt,
        &password.as_bytes(),
        &mut pbkdf2_hash
    );
    println!("Salt: {:?}", &salt);
    println!("Salt: {}", HEXUPPER.encode(&salt));

    println!("PBKDF2 hash: {:?}", &pbkdf2_hash);
    println!("PBKDF2 hash: {}", HEXUPPER.encode(&pbkdf2_hash));

    let should_succeed = pbkdf2::verify(
        pbkdf2::PBKDF2_HMAC_SHA512,
        n_iter,
        &salt,
        password.as_bytes(),
        &pbkdf2_hash,
    );
    let wrong_password = "Wrong Password";
    let should_fail = pbkdf2::verify(
        pbkdf2::PBKDF2_HMAC_SHA512,
        n_iter,
        &salt,
        wrong_password.as_bytes(),
        &pbkdf2_hash,
    );

    assert!(should_succeed.is_ok());
    assert!(!should_fail.is_ok());
    Ok(())

}

数据库

创建

use rusqlite::{Connection, Result};

pub fn main() -> Result<()> {
    let conn = Connection::open("cat.db")?;

    conn.execute(
        "create table if not exists cat_colors(
            id integer primary key,
            name text not null unique
            )",
        []
    )?;
    conn.execute(
        "create table if not exists cats (
            id integer primary key,
            name text not null,
            color_id integer not null references cat_colors(id)
            )",
        []
    )?;
    Ok(())
}

插入数据 事务

use rusqlite::{Connection, Result};

pub fn main() -> Result<()> {
    let mut conn = Connection::open("cat.db")?;
    successful_tx(&mut conn)?;

    let res = rolled_back_tx(&mut conn);
    assert!(res.is_err());

    Ok(())
}

fn successful_tx(conn: &mut Connection) -> Result<()>   {
    let tx = conn.transaction()?;

    tx.execute("delete from cat_colors", [])?;
    tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?;
    tx.execute("insert into cat_colors (name) values (?1)", &[&"blue"])?;

    tx.commit()
}

fn rolled_back_tx(conn: &mut Connection) -> Result<()> {
    let tx = conn.transaction()?;

    tx.execute("delete from cat_colors", [])?;
    tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?;
    tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?;

    tx.commit()
}

时间

测量运行时间

use std::time::{Duration, Instant};
use std::thread;

pub fn main() {
    let start = Instant::now();
    expensive_fun();
    let duration = start.elapsed();
    println!("消耗时间: {:?}", duration);
}

fn expensive_fun() {
    thread::sleep(Duration::from_secs(1));
}
posted @ 2022-05-27 14:11  nsfoxer  阅读(147)  评论(0编辑  收藏  举报