Trapped in clippy's warning: manual implementation of `Option::map`

Hi there ! I have a question for anyone able to answer it :slight_smile:

Here is my code :

let top_consumers = consumers
            .iter()
            .filter_map(|(process, _value)|{
                if let Some(metric) = metrics.iter().find(|x| {
                    x.name == "scaph_process_power_consumption_microwatts" 
                    && process.pid == x.attributes.get("pid").unwrap().parse::<i32>().unwrap()
                }) {
                    Some(
                        Consumer {
                            exe: PathBuf::from(metric.attributes.get("exe").unwrap()),
                            pid: process.pid,
                            consumption: format!("{}", metric.metric_value).parse::<f32>().unwrap(),
                            timestamp: metric.timestamp.as_secs_f64(),
                        }
                    )
                } else { None }
            })
            .collect::<Vec<_>>();

I want to to isolate Process items (from the consumers vec) with their Metric cousin (from the metrics vec) and finally have a vec containing Consumer items with data from the Process and the Metric.

This code compiles, but clippy gives me this warning :

warning: manual implementation of `Option::map`
   --> src/exporters/json.rs:196:17
    |
196 | /                 if let Some(metric) = metrics.iter().find(|x| {
197 | |                     x.name == "scaph_process_power_consumption_microwatts" 
198 | |                     && process.pid == x.attributes.get("pid").unwrap().parse::<i32>().unwrap()
199 | |                 }) {
...   |
207 | |                     )
208 | |                 } else { None }
    | |_______________________________^
    |
    = note: `#[warn(clippy::manual_map)]` on by default
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
help: try this
    |
196 |                 metrics.iter().find(|x| {
197 |                     x.name == "scaph_process_power_consumption_microwatts" 
198 |                     && process.pid == x.attributes.get("pid").unwrap().parse::<i32>().unwrap()
199 |                 }).map(|metric| Consumer {
200 |                             exe: PathBuf::from(metric.attributes.get("exe").unwrap()),
201 |                             pid: process.pid,

warning: 1 warning emitted

I'd like to make clippy happy but I struggle to find a similar way to do that and avoid that warning :slight_smile:

I need to return either Some or None for filter_map, so using map as proposed by clippy doesn't work...

What would be a clippy compliant and somehow optimized way to rewrite this ? I've some ideas but it doesn't seem better than the current version to me. I'd like to inspire from you folks !

Thanks !

Not sure what do you mean here. Could you share a failing code example?

You can get rid of the if let bit and just let find() return an Option. Then you add another map() afterwards which turns your metrics into a Consumer.

let top_consumers = consumers
    .iter()
    .filter_map(|(process, _value)| {
        metrics.iter().find(|x| {
            x.name == "scaph_process_power_consumption_microwatts"
                && process.pid
                    == x.attributes
                        .get("pid")
                        .unwrap()
                        .parse::<i32>()
                        .unwrap()
        })
    })
    .map(|metric| Consumer {
        exe: PathBuf::from(metric.attributes.get("exe").unwrap()),
        pid: process.pid,
        consumption: format!("{}", metric.metric_value)
            .parse::<f32>()
            .unwrap(),
        timestamp: metric.timestamp.as_secs_f64(),
    })
    .collect::<Vec<_>>();

I'd also think about moving the find predicate into its a helper function that accepts just x.name, process.pid, and x.attributes because having it all inline makes the code harder to read.

1 Like

I think I was mistaken about what filter_map was waiting for. The suggestion from @Michael-F-Bryan does actually work. Thanks for noticing !

1 Like

This does work, I guess I was actually trapped by my mind, not by clippy :grinning_face_with_smiling_eyes:

Thanks for this example and for the suggestion about a helper ! I'll try that.

1 Like