Newbie ownership issue


#1

Hi,

I’m relatively new to rust and I’m struggling a bit with types an ownership. For back ground I am using rustler to write a nif for Elixir to access the rust aerospike library. (Yeah, I’m in way over my head.) I have the nif mostly working but I’m not sure about one part. The relavant code is:

    let mut bins: Vec<&Bin> = Vec::new();
    for (k, v) in values {
        let s: String = try!(v.decode());
        let bin: Bin<'a> = as_bin!(k.decode()?, s);
        bins.push(&bin)
    }
    let res = match client.client.put(&WritePolicy::default(), &key, &bins) {
...

I’m making a vector of references to Bins to pass to put(). The issue is that the bin is dropped at the end of the for loop so bins.push(&bin) is an error.

How do I fix this?


#2

You probably want bins to own the Bin values, i.e.:

let mut bins: Vec<Bin> = Vec::new();
...
let bin = as_bin!(k.decode()?, s);
bins.push(bin);

It’s a bit hard to say without seeing the definition of the involved types/functions.


#3

Also you can use the iterators and collect it into the vector. That way you don’t need a mutable vector.


#4

Sorry, I should have supplied the definition of put(). It looks like:

fn put(&self, policy: &WritePolicy, key: &Key, bins: &[&Bin]) -> Result<()>

The difficulty is making the &[&Bin]] value.


#5

Is put() in your control?


#6

No, put() is part of the aerospike rust library.


#7

That’s too bad - there might’ve been a way to make it generic over a slice of either owned or borrowed Bins. But ok …

So the simple approach, then, would be to build a second Vec of references:

let mut bins: Vec<Bin> = Vec::new();
...
let bins = bins.iter().collect::<Vec<_>>();
put(..., &bins);

Kind of unfortunate to have to do this though.


#8

or

let bins: Vec<Bin> = bins.iter().collect();

#9

What’s the initial bins in your example? His example has a for loop over some tuples, but he has fallible operators inside the body of the loop that do a function exit if an Err is seen. That won’t work with iterator combinators without more code refactoring.

But anyway, that stylistic thing is sort of secondary to the main question, I think :slight_smile:.


#10
let bins = bins.iter().collect::<Vec<_>>();

worked.

iex(1)> {:ok, client} = Aerospike.connect("172.28.128.3:3000")
                {:ok, #Reference<0.347712306.2185625606.33170>}
iex(2)> res = Aerospike.put(client, "test", "test", "test", %{"id" => "1234", "uuid" => "abcd"})
{:ok, "ok"}
iex(3)> {:ok, res} = Aerospike.get(client, "test", "test", "test")
{:ok, %{"id" => "1234", "int" => 999, "uuid" => "abcd"}}

Thanks everyone!

Yeah, I need to read up a bit more on ownership.


#11

If you want, ask aerospike lib maintainers to change put() to:

fn put<A: AsRef<Bin>>(..., bins: &[A]) ...
// or if a slice isn’t necessary and iterator works
fn put<I: IntoIterator<Item=A>, A: AsRef<Bin>>(iter: I) ...

Then you won’t need that second Vec of references.