Does Varlink force me to duplicate work for sake of ownership?

I'm very happy with Varlink so far as a means to create a CLI "server" and "client". It's basically RPC with a nice standard and autogenerated code.

The trouble is that based on the autogen code, Varlink methods expect owned variables as args. As a result, I'm writing code that duplicates work for the sake of ownership (note that keys1 and keys2 are the exact same thing):

pub fn run_client(addr: &str, tally: Arc<RwLock<Tally>>) -> Result<()> {
    let conn = Connection::with_address(&addr).unwrap();
    let mut iface = org_wordtree_ngrams::VarlinkClient::new(conn);

    let mut score: f64 = 0.0;

    let tally = tally.read().unwrap();
    let keys1: Vec<String> = 
        tally.iter().map(|(k, _v)| k.clone() ).collect();
    let keys2: Vec<String> = 
        tally.iter().map(|(k, _v)| k.clone() ).collect();
    let reply = iface.lookup_all(keys1).call()?;

    for (key, baseline) in keys2.iter().zip(reply.tallies.iter()) {
        let baseline = *baseline as f64;
        if baseline > 0.0 {
            let value = match tally.get(key) {
                Some(v) => *v,
                None => 0
            };
            score += (value as f64) / (baseline as f64)
        }
    }
    
    println!("Score: {:.*}", 9, score);

    Ok(())
}

(Full source code can be found here.)

The autogenerated lookup_all method signature looks like this, which is what's making me dance around borrowing:

fn lookup_all(&self, call: &mut Call_LookupAll, r#ngrams: Vec<String>) -> varlink::Result<()>;

I'm quite new to Rust, so I'm sure there's a better way. I'm primarily interested in speed. Any suggestions?

Yep. That signature forces you to make a clone.

btw I noticed you're using varlink version 8.0, but 8.1 has been released.

Is there a better/faster way to make a clone than iterating twice? I tried .copy() but it says it isn't implemented for Vec<String>.

Oh, nice catch, thanks!

You could use let keys2 = keys1.clone();

What is wrong with ...?

for (key, baseline) in tally.iter().map(|(k, _v)| k ).zip(reply.tallies.iter()) {
1 Like

Ah, so you can take the .clone() out of the other map, and give a speed boost? I like it.