Rust Generics, "`T` may not live long enough" - rust

I'm trying to imbed Lua into Rust using Mlua. Using its guided tour, I successfully loaded and evaluated a chunk of Lua code. My next goal is to combine this with opening a file and reading its contents. This is where things get problematic:
use anyhow::Result;
use mlua::{Lua, UserData};
use std::fs;
pub struct LuaManager {
lua_state: Lua
}
impl LuaManager {
pub fn new() -> Self {
LuaManager {
lua_state: Lua::new(),
}
}
pub fn eval<T>(&self, chunk: &str) -> Result<T> where T: Clone + UserData {
let v = self.lua_state.load(chunk).eval::<T>()?;
Ok(v)
}
}
Since scripts can return literally anything, I thought a trait-locked generic annotation would solve the issue: The problem is this:
Error generated by rustc: the parameter type `T` may not live long enough... so that the type `T` will meet its required lifetime bounds...
For reference, here is the function signature as defined in lua.rs:
pub fn eval<R: FromLuaMulti<'lua>>(self) -> Result<R>
I don't understand why I'm having this issue. I've looked this up and this question pertained to user-created types, which to my knowledge I'm not doing... so what is the problem here? It's clear that things like <i32> won't die anytime soon. Cargo did suggest adding a static lifetime annotation, but doing some research into it points me to trying to solve the problem without using it first, since in 99% of cases you actually can get away without it.

Unfortunately in this case it seems like 'static is really required.
Lua::load() takes &'lua self and returns Chunk<'lua, '_>. Chunk::<'lua, '_>::eval::<R>() requires R: FromLuaMulti<'lua>. FromLuaMulti<'lua> is implemented for T: FromLua<'lua>. FromLua<'lua> is implemented for T: UserData, however it requires T: 'static (and also T: Clone, but this is irrelevant).

Related

Why doesn't BroadcastStream implement stream

I'm writing an HTTP server in the actix_web framework using the tokio runtime and tokio-stream utilities. I would like to send some data (actix::web::Bytes) from a broadcast channel in a response. I also want to do some other stuff, so I'd like to write a wrapper implementing the MessageBody trait that at some point forwards the .poll_next() method. The problematic code looks like this:
use actix_web::web::Bytes;
use actix_web::body::{BodyStream, MessageBody};
use tokio_stream::wrappers::BroadcastStream;
use futures_core::stream::Stream;
// ...
struct Wrapper {
// some other stuff
broad_rx: BodyStream<BroadcastStream<broadcast::Receiver<Bytes>>>
}
impl MessageBody for Wrapper {
type Error = BroadcastStreamRecvError;
fn size(&self) -> actix_web::body::BodySize {
BodySize::Stream
}
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<Result<Bytes, Self::Error>>> {
/*
do some other stuff
*/
self.broad_rx.poll_next(cx) // XXX the problem
}
}
This snippet doesn't compile and returns the following error:
error[E0599]: no method named `poll_next` found for struct `BodyStream` in the current scope
--> crates/demo/src/server.rs:***:***
|
*** | self.broad_rx.poll_next(cx)
| ^^^^^^^^^ method not found in `BodyStream<BroadcastStream<tokio::sync::broadcast::Receiver<actix_web::web::Bytes>>>`
I expect BodyStream to implement MessageBody and thus the .poll_next() method. because of this impl and the following chain of implementations:
Bytes implements:
Clone
Send
I'm not sure how to deduce whether it has a 'static lifetime in this context, as it's not a reference. If the lifetime isn't 'static I'd assume that is the problem, but I also don't know how to solve it. However, I'd also assume that the compiler would mention something about lifetimes if that is the case.
BroadcastStream<Bytes> implements:
Stream, if Bytes is 'static + Clone + Send. Item = Result<Bytes, BroadcastStreamRecvError> in that case.
BroadcastStreamRecvError implements:
Error and via this blanket implementation presumably also Into<Box<dyn Error + 'static, Global>>
BodyStream<Bytes> implements:
MessageBody because the Stream bound is satisfied by BroadcastStream<Bytes> and the 'static + Into<Box<dyn Error + 'static, Global>> is satisfied by
BroadcastStreamRecvError (except those pesky 'static requirements again)
Yet the error suggests, that one of the implementations doesn't apply for whatever reason. In fact even if I replace
broad_rx: BodyStream<BroadcastStream<broadcast::Receiver<Bytes>>>
with
broad_rx: BroadcastStream<broadcast::Receiver<Bytes>>
I still get an error saying that the .poll_next() method doesn't exist, despite the fact that this type should implement Stream.
How can I implement the MessageBody wrapper or further debug this?
The presented code has three problems preventing it from being compiled. The one causing the given error is caused by the problem put forth by #kmdreko. The reason why Pin is needed is a bit complicated and can be found in the async rust book. In a superficial way: If you want to use a .poll method then the thing needs to be pinned. One of the ways to solve this problem is using the pin-project crate that simplifies the creation of projections (helper functions used to access fields of pinned structs). Otherwise, one can write their own projections manually, like in this article.
The declaration then looks like this:
#[pin_project]
struct Wrapper {
#[pin]
broad_rx: BroadcastStream<broadcast::Receiver<Bytes>>,
}
and the projection that presents the pinned field (see further below) can be obtained like so:
let this = self.project();
This still doesn't compile, but for a trivial reason. First of all, the BodyStream is not needed at all, because the MessageBody is being manually implemented anyway. Secondly, the generic type of BroadcastStream isn't supposed to be the wrapped type (also because the wrapped type will always be broadcast::Receiver<_>), but the type returned from the channel. The following code compiles:
struct Wrapper {
broad_rx: BroadcastStream<Bytes>
}
impl MessageBody for Wrapper {
type Error = BroadcastStreamRecvError;
fn size(&self) -> actix_web::body::BodySize {
BodySize::Stream
}
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<Result<Bytes, Self::Error>>> {
let this = self.project();
this.broad_rx.poll_next(cx)
}
}

Conflicting trait implementations for types that clearly already implement the trait

I'm working with webassembly so I need to fetch the pointer to a buffer. In the case where T is just AsRef<[f32]> (that is, it can be converted to a slice if I'm understanding correctly), I have solved it like this:
#[derive(TS, Serialize)]
pub struct PtrBufF32(usize);
impl<T> From<T> for PtrBufF32
where T: AsRef<[f32]>
{
fn from(f32arr: T) -> Self {
let slc: &[f32] = f32arr.as_ref();
let ptr: *const f32 = slc.as_ptr();
Self(ptr as usize)
}
}
I had help from another stack overflow user to understand what's going on -- as far as I'm understanding, this means "for any T that can be converted to a refence of &[f32] (that is, a slice), then we can implement this trait. The result is simply the pointer to the start of the slice of course.
But then in addition to implementing for anything that can be represented as &[f32], we need to implement for any collection of things that can be represented by &[f32]. Like, if my type T implements Into<&[f32]>, then I can implement the type for any AsRef<[T]>, right? And so on. Any collection of those also implements it. So I thought:
impl<T> From<T> for PtrBufF32
where T: AsRef<[dyn Into<PtrBufF32>]>
{
fn from(f32arr: T) -> Self {
todo!()
}
}
But no… apparently those are "conflicting implementations" somehow?
error[E0119]: conflicting implementations of trait `std::convert::From<memory::ptrbuf::PtrBufF32>` for type `memory::ptrbuf::PtrBufF32`
Yet, if I try to PtrBufF32::from(vec![T]) and T implements Into<AsRef<[f32]>>, it doesn't let me. So clearly it's not conflicting, is it?
Thanks
As long as you implemented conversion for undefined list of types you should think a little bit more widely.
Imagine some type ForeignType, that implements both Into<PtrBufF32> and AsRef<[f32]>. Then if you call PtrBufF32::from(my_foreign_type), compiler cannot decide which of two implementation he must use.

Is there any way to implement Into<&str> or From<T> for &str?

Was writing some code in Rust trying to define a CLI, using the (otherwise pretty great) crate clap, and run into a rather critical issue. Methods of App accept an Into<&'help str>, and i've been unable to find a way to implement this trait.
Indeed from what i understand, it is absolutely unimplementable:
struct JustWorkDamnIt {
string: String
}
impl From<JustWorkDamnIt> for &str {
fn from(arg: JustWorkDamnIt) -> Self {
return arg.string.as_str()
}
}
...which yields:
error[E0515]: cannot return value referencing local data `arg.string`
--> src/cmd/interactive.rs:25:16
|
25 | return arg.string.as_str()
| ----------^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `arg.string` is borrowed here
Interestingly enough, however, returning a literal compiles just fine (which i reckon is why clap doesn't mind using this trait). Presumably that's because the literal is compiled to some static region of memory and therefore isn't owned by the function:
impl From<JustWorkDamnIt> for &str {
fn from(arg: JustWorkDamnIt) -> Self {
return "literal"
}
}
But, i mean, surely there's a way to implement this trait and return dynamic strings? Maybe some clever use of Box<> or something, idk. I believe i've tried all the things i could think of.
And if there isn't a way, then this seems like a pretty glaring flaw for Rust - traits which can be declared and used in function headers, but cannot be actually implemented meaningfully (there's not much of a point in returning a literal). If this turns out to be the case i'll create an issue on the rust-lang repository for this flow, but first i wanted to sanity-check my findings here.
UPD: Thanks for the comments, made me think more in-depth about this issue.
The problem has to do with lifetimes, it seems. I apologize for not showing the entire code, i thought the snippets i shared would describe the problem sufficiently, but in hindsight it does make sense that the context would be important with Rust's lifetimes at play.
I did find a "solution" for this particular instance of the problem. Since the code in question will only run once per executable start, i can just Box::leak the &'static str and call it a day. Still, i would like to figure out if there's a more general solution which could be used for often-created dynamic strings.
impl Cmd for InteractiveCmd {
fn build_args_parser<'a, 'b>(&'b self, builder: App<'a>) -> App<'a> {
// leak() works here but i'm curious if there's a better way
let staticStr : &'static str = Box::leak(Box::from(format!("Interactive {} shell", APPNAME).as_str()));
let rv = builder
// pub fn about<S: Into<&'b str>>(mut self, about: S) -> Self
.about(staticStr)
.version("0.1");
return rv;
}
}
fn main() {
let interactive = InteractiveCmd::new();
let mut app = App::new(APPNAME)
.version(APPVER)
.author(AUTHORS)
.subcommand(interactive.build_args_parser(App::new("interactive")));
}
Currently i am faced with 2 points of confusion here:
Why is there no impl From<String> for &str? The compiler claims that one exists for impl From<String> for &mut str, and i'm not seeing the importance of mut here.
...and if there is a good reason to not impl From<String> for &str, would it make sense to somehow discourage the usage of Into<&str> in the public APIs of libraries?
Or maybe the issue is with my build_args_parser function and it's just not an option to offload the work to it as far as Rust is concerned?
Seems like you're trying to convert a String into a &'a str. You can do it like this:
use clap::App;
fn main() {
let s = format!("Interactive {} shell", "Testing");
let app = App::new("Testing")
.about(&*s); // or `.about(s.as_str());` it's the same
}
Here's the signature of the function that we want to call:
pub fn about<S: Into<&'b str>>(self, about: S) -> Self
So the about parameter must implement trait Into<&'b str>. According to std::convert::Into, we know that &'b str does implement trait Into<&'b str>. So now we just need a way to convert String into &'b str. The std::string::String tell us that there are two ways: use either s.as_str() or &*s.

How to create a function returning a borrowed value? [duplicate]

This question already has answers here:
Is there any way to return a reference to a variable created in a function?
(5 answers)
Closed 4 years ago.
I have the following function as part of a Rust WASM application to convert a Boxed closure into the Rust-representation for a JavaScript function.
use js_sys::Function;
type Callback = Rc<RefCell<Option<Closure<FnMut()>>>>;
fn to_function(callback: &Callback) -> &Function {
callback.borrow().as_ref().unwrap().as_ref().unchecked_ref()
}
However, the compiler complains that the return value uses a borrowed value (obtained with callback.borrow()) so cannot be returned.
Hence, I decided to add lifetime annotations to inform the compiler that this new reference should live as long as the input.
use js_sys::Function;
type Callback = Rc<RefCell<Option<Closure<FnMut()>>>>;
fn to_function<'a>(callback: &'a Callback) -> &'a Function {
callback.borrow().as_ref().unwrap().as_ref().unchecked_ref()
}
Unfortunately, this hasn't helped and I get the same error. What am I doing wrong here?
Yeah, this isn't going to work.
callback.borrow().as_ref().unwrap().as_ref().unchecked_ref()
Let's break this down in steps:
You're borrowing &RefCell<Option<Closure<FnMut()>>> - so you now have Ref<Option<...>>, which is step #1 of your issues. When this happens, this intermediary value now has a different lifetime than 'a (inferior, to be precise). Anything stemming from this will inherit this lesser lifetime. Call it 'b for now
You then as_ref this Ref, turning it into Option<&'b Closure<FnMut()>>
Rust then converts &'b Closure<FnMut()> into &'b Function
Step 1 is where the snafu happens. Due to the lifetime clash, you're left with this mess. A semi-decent way to solve it the following construct:
use std::rc::{Rc};
use std::cell::{RefCell, Ref};
use std::ops::Deref;
struct CC<'a, T> {
inner: &'a Rc<RefCell<T>>,
borrow: Ref<'a, T>
}
impl<'a, T> CC<'a, T> {
pub fn from_callback(item:&'a Rc<RefCell<T>>) -> CC<'a, T> {
CC {
inner: item,
borrow: item.borrow()
}
}
pub fn to_function(&'a self) -> &'a T {
self.borrow.deref()
}
}
It's a bit unwieldy, but it's probably the cleanest way to do so.
A new struct CC is defined, containing a 'a ref to Rc<RefCell<T>> (where the T generic in your case would end up being Option<Closure<FnMut()>>) and a Ref to T with lifetime 'a, auto-populated on the from_callback constructor.
The moment you generate this object, you'll have a Ref with the same lifetime as the ref you gave as an argument, making the entire issue go away. From there, you can call to_function to retrieve a &'a reference to your inner type.
There is a gotcha to this: as long as a single of these objects exists, you will (obviously) not be able to borrow_mut() on the RefCell, which may or may not kill your use case (as one doesn't use a RefCell for the fun of it). Nevertheless, these objects are relatively cheap to instantiate, so you can afford to bin them once you're done with them.
An example with Function and Closure types replaced with u8 (because js_sys cannot be imported into the sandbox) is available here.
Although I really like Sébastien's answer and explanation, I ended up going for Ömer's suggestion of using a macro, simply for the sake of conciseness. I'll post the macro in case it's of use to anyone else.
macro_rules! callback_to_function {
($callback:expr) => {
$callback
.borrow()
.as_ref()
.unwrap()
.as_ref()
.unchecked_ref()
};
}
I'll leave Sébastien's answer as the accepted one as I believe it is the more "correct" way to solve this issue and he provides a great explanation.

Why doesn't String implement From<&String>?

Background
I know that in Rust people prefer &str rather than &String. But in some case we were only given &String.
One example is when you call std::iter::Iterator::peekable. The return value is a Peekable<I> object that wraps the original iterator into it and gives you one extra method peek.
The point here is that peek only gives you a reference to the iterator item. So if you have an iterator that contains Strings, you only have &String in this case. Of cause, you can easily use as_str to get a &str but in the code I will show below it is equivalent to a call to clone.
The question
This code
#[derive(Debug)]
struct MyStruct(String);
impl MyStruct {
fn new<T>(t: T) -> MyStruct
where
T: Into<String>,
{
MyStruct(t.into())
}
}
fn main() {
let s: String = "Hello world!".into();
let st: MyStruct = MyStruct::new(&s);
println!("{:?}", st);
}
doesn't compile because String doesn't implement From<&String>. This is not intuitive.
Why does this not work? Is it just a missing feature of the standard library or there are some other reasons that prevent the standard library from implementing it?
In the real code, I only have a reference to a String and I know to make it work I only need to call clone instead, but I want to know why.
To solve your problem, one could imagine adding a new generic impl to the standard library:
impl<'a, T: Clone> From<&'a T> for T { ... }
Or to make it more generic:
impl<B, O> From<B> for O where B: ToOwned<Owned=O> { ... }
However, there are two problems with doing that:
Specialization: the specialization feature that allows to overlapping trait-impls is still unstable. It turns out that designing specialization in a sound way is way more difficult than expected (mostly due to lifetimes).
Without it being stable, the Rust devs are very careful not to expose that feature somewhere in the standard library's public API. This doesn't mean that it isn't used at all in std! A famous example is the specialized ToString impl for str. It was introduced in this PR. As you can read in the PR's discussion, they only accepted it because it does not change the API (to_string() was already implemented for str).
However, it's different when we would add the generic impl above: it would change the API. Thus, it's not allowed in std yet.
core vs std: the traits From and Into are defined in the
core library, whereas Clone and ToOwned are defined in std. This means that we can't add a generic impl in core, because core doesn't know anything about std. But we also can't add the generic impl in std, because generic impls need to be in the same crate as the trait (it's a consequence of the orphan rules).
Thus, it would required some form of refactoring and moving around definitions (which may or may not be difficult) before able to add such a generic impl.
Note that adding
impl<'a> From<&'a String> for String { ... }
... works just fine. It doesn't require specialization and doesn't have problems with orphan rules. But of course, we wouldn't want to add a specific impl, when the generic impl would make sense.
(thanks to the lovely people on IRC for explaining stuff to me)
Since String does implement From<&str>, you can make a simple change:
fn main() {
let s: String = "Hello world!".into();
// Replace &s with s.as_str()
let st: MyStruct = MyStruct::new(s.as_str());
println!("{:?}", st);
}
All &Strings can be trivially converted into &str via as_str, which is why all APIs should prefer to use &str; it's a strict superset of accepting &String.

Resources