Stream: wit-bindgen

Topic: Giving a list of params


view this post on Zulip bachrc (Mar 19 2023 at 09:24):

Hello! I have a function in my wit which takes a list of struct as a parameter.

interface michel-api {
  ...
  new-documents-for-index: func(index: string, documents: list<document>)
}

The problem is: my document list is computed, I cannot inline it. And I have lifetime issues..

let docs: Vec<DocumentParam<'a>> = files
        .iter()
        .map(|it| DocumentParam {
            identifier: &it.id.to_string(),
            fields: &[
                FieldParam {
                    name: "filename",
                    value: Text(&it.filename.to_string()),
                },
                FieldParam {
                    name: "path",
                    value: Text(&it.path.to_string_lossy()),
                },
            ],
        })
        .collect();

I have this error : cannot return value referencing temporary value [E0515] returns a value referencing data owned by the current function

view this post on Zulip bachrc (Mar 19 2023 at 09:27):

The files is a Vec<FileDocument> where FileDocument is an owned object of mine

view this post on Zulip bachrc (Mar 19 2023 at 09:29):

It just doesn't seem possible to give this list

view this post on Zulip bachrc (Mar 21 2023 at 11:47):

Well, after searching even further, I don’t think this is possible. I know this is more a Rust problem, but I can’t find any solution to this. I can only wait for the issue speaking about disabling borrowed types

view this post on Zulip bachrc (Mar 22 2023 at 22:19):

And I guess that the fact that I don't get any answers means it's not possible :sob:

view this post on Zulip Joel Dice (Mar 22 2023 at 22:28):

Something like this, perhaps?

let files = files.iter().map(|it| {
  (it.id.to_string(), it.filename.to_string(), it.path.to_string_lossy())
}).collect::<Vec<_>>();

let docs: Vec<DocumentParam<'_>> = files
        .iter()
        .map(|(id, filename, path)| DocumentParam {
            identifier: id.as_str(),
            fields: &[
                FieldParam {
                    name: "filename",
                    value: Text(filename.as_str()),
                },
                FieldParam {
                    name: "path",
                    value: Text(path.as_str()),
                },
            ],
        })
        .collect();

view this post on Zulip Joel Dice (Mar 22 2023 at 22:48):

err, actually:

    let files = files
        .iter()
        .map(|it| {
            (
                it.id.to_string(),
                it.filename.to_string(),
                it.path.to_string_lossy(),
            )
        })
        .collect::<Vec<_>>();

    let files = files
        .iter()
        .map(|(id, filename, path)| {
            (
                id,
                [
                    FieldParam {
                        name: "filename",
                        value: Text(filename.as_str()),
                    },
                    FieldParam {
                        name: "path",
                        value: Text(path.as_str()),
                    },
                ],
            )
        })
        .collect::<Vec<_>>();

    let docs: Vec<DocumentParam<'_>> = files
        .iter()
        .map(|(id, fields)| DocumentParam {
            identifier: id.as_str(),
            fields,
        })
        .collect();

view this post on Zulip bachrc (Mar 24 2023 at 19:10):

Wow, it seems like it is working... i totally did not understand how splitting this in three variables would help with the ownership in the function, but I really thank you for your time, it really means a lot

view this post on Zulip Joel Dice (Mar 24 2023 at 21:05):

Storing the stings and arrays in named variables in the outer scope instead of temporaries in the inner scopes of the closures ensures that the references don't outlive their referents, which is what is needed to make the compiler happy. The first Vec stores the strings, the second Vec stores the arrays which refer to the strings in the first Vec, and the third Vec stores the references to the arrays in the second Vec, plus the id strings stored in the first Vec.

You could technically do this more concisely if you venture into the world of self-referential structs using e.g. ouroboros but I wouldn't recommend that for simple situations like this.


Last updated: Nov 22 2024 at 16:03 UTC