fadedbee
fadedbee

Reputation: 44739

Searching a Vec for a match

My first Rust program compiles and runs:

use structopt::StructOpt;
use pcap::{Device,Capture};
use std::process::exit;

#[derive(StructOpt)]
struct Cli {
    /// the capture device
    device: String,
}

fn main() {    
    let devices = Device::list();
    let args = Cli::from_args();

    let mut optdev :Option<Device> = None;
    for d in devices.unwrap() {
        //println!("device: {:?}", d);
        if d.name == args.device {
            optdev = Some(d);
        }
    }

    let dev = match optdev {
        None => {
            println!("Device {} not found.", args.device);
            exit(1);
        },
        Some(dev) => dev,
    };

    let mut cap = Capture::from_device(dev).unwrap()
              .promisc(true)
              .snaplen(100)
              .open().unwrap();

    while let Ok(packet) = cap.next() {
        println!("received packet! {:?}", packet);
    }
}

I have some complex code which iterates through the Vec of devices, testing each one's .name property against args.device.

I'm guessing that there is a method of 'looking-up' an entry in a Vec, such that I can replace all the optdev lines with something like:

let dev = match devices.unwrap().look_up(.name == args.device) {
    None => {
        println!("Device {} not found.", args.device);
        exit(1);
    },
    Some(dev) => dev,
};

What is the syntax for such a look_up()?

Or is there a more idiomatic way of doing this?

Upvotes: 1

Views: 1500

Answers (1)

Masklinn
Masklinn

Reputation: 42207

What is the syntax for such a look_up()?

Iterator::find. Since the operation is not specific to vectors (or slices), it doesn't live there, and is applicable to any iterator instead.

It'd look something like this:

let dev = match devices.unwrap().into_iter().find(|d| d.name == args.device) {
    None => {
        println!("Device {} not found.", args.device);
        exit(1);
    },
    Some(dev) => dev,
};

or

let dev = if let Some(dev) = devices.unwrap().into_iter().find(|d| d.name == args.device) {
    dev
} else {
    println!("Device {} not found.", args.device);
    exit(1);
};

(side-note: you may also want to use eprintln for, well, error reporting).

Though a somewhat cleaner error handling could be along the lines of (note: not tested so there might be semantic or syntactic mistakes):

use std::fmt;
use std:errors::Error;

#[derive(Debug)]
struct NoDevice(String);
impl fmt::Display for NoDevice {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Device {} not found", self.0)
    }
}
impl Error for NoDevice {}

fn main() -> Result<(), Box<dyn Error>> {    
    let devices = Device::list()?;
    let args = Cli::from_args();

    let dev = devices.into_iter()
                     .find(|d| d.name == args.device)
                     .ok_or_else(|| NoDevice(args.device))?

    let mut cap = Capture::from_device(dev)?
              .promisc(true)
              .snaplen(100)
              .open()?;

    while let Ok(packet) = cap.next() {
        println!("received packet! {:?}", packet);
    }
}

Upvotes: 3

Related Questions