-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Component: Unclear how to access exported resource returned by guest #9946
Comments
A resource is an opaque id. I think all the host can do with a guest resource is to pass it as argument when calling a guest function or to call the drop function of the resource. |
@bjorn3 , actually I figured it out and it is possible. The example code is the hint. Here's how it's done:
I wish the example actually showed this. Instead, the example doesn't have any exported functions in the interface, which doesn't seem to me to be a very common scenario. |
@tliron do you have a suggestion for what WIT you'd like to see in the example? it sounds like you figured things out otherwise, but I'd be happy to help update the example to be more useful to you. |
I mostly figured things out, but I'm sorry, I doubt that others would, too. Also, I'm still not sure if I have to manually
On that note, why does Again, going back to my suggestion 1, a full example of dealing with this would make these challenges easier to see. |
Hm I'm a bit confused, and while I agree we can improve docs I'm going to try to drill in here to be a bit more specific. Basically I'm not sure where the disconnect is and understanding that'll be important to improve the documentation.
The example linked ends with: // The `ResourceAny` type has no destructor but when the host is done
// with it it needs to invoke the guest-level destructor.
my_logger.resource_drop(&mut store)?; and the documentation states:
So I'm curious to understand more where you're left with an ambiguity of what to do? It should be the case that all
The example has this code: let my_logger = logger.call_constructor(&mut store, Level::Warn)?;
assert_eq!(logger.call_get_max_level(&mut store, my_logger)?, Level::Warn); where It's impossible for the host to create a
I definitely agree that some examples of using Could you clarify which part you think is wrong though? I skimmed over and it looks accurate (albeit not as clear as it could be) to me.
These are good questions! Unfortunately though it's not possible to do this. The reasons for this touch on the design of the component model itself and how it interacts with instantiation and static types. Basically it's impossible to statically rule out runtime type errors here. Now that doesn't mean the situation couldn't be improved with a type parameter, but even if that were the case there'd still be the possibility for a runtime type error. The current design is intended to reflect that a runtime type error is always possible. |
Let's take this slowly. I think the current example is the niche one. Perhaps there's a misunderstanding on the use cases for resources. Here's a snippet from one of my WITs to give you an idea:
The point is to show you that resources can be used as arguments and return values for functions, indeed in complex scenarios where they are nested in lists, records, or variants. I believe that's their true power. In the currently existing example the resource creation is initiated by the host, so it's clear that the host owns it and must drop it. It includes no exported or imported functions at all in the interface. Actually, it does make resources seem rather useless as they don't do much that can't be done with just exported functions (with a little extra "logger-name" argument), so I understand why it looks "niche" to you. Back to my example, the concept of ownership is unclear. Who owns a resource sent as an argument? Who owns a resource returned by a function? And who is responsible for dropping? The documentation mentions "borrows", but to be honest I don't understand what is "borrowed" here at all. The arguments and return value are all pass-by-value, intending to pass ownership, too. How does one "borrow" a resource in my example? Are there any "borrows" you can point to? My OP issue very specifically was about accessing, at the host, the result returned by the exported pub fn get_returned_list(&mut self, value: dispatcher::Value) -> Result<Vec<dispatcher::Value>> {
match value {
dispatcher::Value::ValueList(resource) => {
let value_list = self.functions.acme_acme_dispatcher().value_list();
let vector = value_list.call_get(&mut self.store, resource).unwrap();
resource.resource_drop(&mut self.store)?; // do I need this?
Ok(vector)
}
....
}
} My initial challenge was that it was unclear that I had to explicitly call The side issue (not the main reason I opened this issue): In the currently existing example, the drop is indeed obvious because in it you are constructing the resource yourself, so of course you would have to drop it when you're done using it. Nobody else would. But it's that last drop in my code that is unclear to me. Did the guest pass ownership to me? Does that mean I really have to drop the resource? What about passing resources as arguments in the call to And here's why this has me worried and I'm making a big deal out of it: If indeed the host has to drop the returned resource then, well, what happens if it doesn't? What happens if I never handle the return value the way I did above? Will this be a memory leak? If that's true, then that's a very big deal that needs to be carefully documented and made very prominent by an example. Consider that in my case, because the resources can be nested (recursively), such a cleanup would involve more than one drop. That's a lot of responsibility put on my code. I can do it, it's just not clear to me that I must. And I'm sorry but the current documentation and example have not helped me understand much about this situation. |
The exported resources example shows how to create a guest resource. Unfortunately it doesn't show how to actually send that resource to an exported client function.
But, to this issue, it doesn't show how to access a resource returned by a call to the guest.
The guest returns
ResourceAny
, and the documentation does make it clear that this is expected. However, now what?It cannot be converted to a
Resource
, becausetry_into_resource
only works on host resources. (That is also not clear in the documentation, I had to delve into the source code to figure that out.)Also, it's also unclear to me if I must call
resource_drop
on the value returned by the guest. Or is that necessary just for host resources?The documentation could be more specific, and the example is not especially useful. In any case, I do not know how to proceed.
The text was updated successfully, but these errors were encountered: