summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: eda1c01a76c6690da6e886dbb5e0b5547ea973aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
extern crate clap;
extern crate rand;

use clap::{Arg, App};
use std::collections::vec_deque::VecDeque;
use std::io::{self, BufRead};
use std::result::Result;

fn some<R: rand::Rng, T: Iterator<Item = Result<String, io::Error>>>(
    r: &mut R,
    n: usize,
    lines: T,
) -> Result<VecDeque<String>, io::Error> {
    let mut result: VecDeque<String> = VecDeque::with_capacity(n);
    fn push(v: &mut VecDeque<String>, n: usize, x: String) {
        v.push_back(x);
        if v.len() > n {
            v.pop_front();
        }
    };

    for (i, line) in lines.enumerate() {
        let line = line?;
        if result.len() < n {
            push(&mut result, n, line);
        } else if r.gen_range(0, i) < n {
            let victim = r.gen_range(0, n);
            result.remove(victim);
            push(&mut result, n, line);
        }
    }
    return Ok(result);
}

fn main() {
    let matches = App::new("some")
        .version("0.1")
        .author("Kjetil Ørbekk <kj@orbekk.com>")
        .arg(
            Arg::with_name("lines")
                .short("n")
                .value_name("NUM")
                .help("Number of lines to print")
                .takes_value(true),
        )
        .get_matches();
    let num_lines = matches
        .value_of("lines")
        .unwrap_or("10")
        .parse::<usize>()
        .expect("number of lines to print");
    let stdin = io::stdin();
    let lines = some(&mut rand::thread_rng(), num_lines, stdin.lock().lines());
    match lines {
        Ok(lines) => {
            for line in lines {
                println!("{}", line);
            }
        }
        Err(e) => println!("Error: {}", e),
    }
}