I'm writing a function as follows. req.get::<State<SomeService>>().unwrap()
gets me a Arc<RwLock<SomeService>>
. When I try to do a read access on that and access functions in it, I get these errors -
`service_reader` does not live long enough
`service_state` does not live long enough
pub fn collect_stats(&self, req: &mut Request) -> Vec<ServiceStatus> {
let mut statuses = Vec::new();
for service in self.services.iter() {
match *service {
ServiceEnum::RM => {
let service_state = req.get::<State<SomeService>>().unwrap();
let service_reader = service_state.read().unwrap();
println!("{}", service_reader.service_name());
statuses.push(ServiceStatus {
name: service_reader.service_name(),
data: service_reader.data(),
});
}
_ => doNothing(),
}
}
return statuses;
}
Can you please post the entire error message? Also, what's the full return type of req.get()
? And what's the definition of ServiceStatus
?
My guess is service_reader.service_name()
and/or service_reader.data()
is returning a reference tied to service_reader. That data is only accessible while the rwlock is held, which is limited to the body of that match arm. However, the code is attempting to add this to a Vec that outlives this block.
But as @jethrogb said, we need more info to say for sure.
Full error msg:
error[E0597]: `service_state` does not live long enough
--> src/service/mod.rs:139:30
|
139 | let service_reader = service_state.read().unwrap();
| ^^^^^^^^^^^^^ does not live long enough
...
161 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 131:5...
--> src/service/mod.rs:131:5
|
131 | / pub fn collect_stats( &self, req: &mut Request ) -> Vec<ServiceStatus> {
132 | |
133 | | let mut statuses = Vec::new();
134 | | /* let service_state = req.get::<State<SomeService>>().unwrap();
... |
160 | | return statuses;
161 | | }
| |_____^
'req' is an iron request. ServiceStatus is just a struct of 'name' and 'data' fields
I guess you are right, so how do I add to a Vec inside the match arm and use that outside ?
Can you paste the definition of ServiceStatus
and of the service_name()
and data()
methods?
@vitalyd
#[derive(Serialize)]
pub struct ServiceStatus<'a> {
service_name: &'static str,
service_data: &'a Value,
}
impl Status for SomeService {
fn service_name(&self) -> &'static str {
"SomeService"
}
fn service_data(&self) -> &Value {
&self.config
}
}
pub trait Status: Send + Sync {
fn service_name(&self) -> &'static str;
fn service_data(&self) -> &Value;
}
This is the problem:
Can you clone the Value
? Is that (relatively) cheap? That would be the simplest fix: clone the value and store it in ServiceStatus
, which in turn is added to the Vec
that you return.
I tried cloning and adding a reference. I still get the error -
borrowed value does not live long enough
--> src/service/mod.rs:142:150
|
142 | statuses.push(ServiceStatus{ service_name: service_reader.service_name(), is_healthy: service_reader.is_healthy(), service_data: &service_reader.service_data().clone()});
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value only lives until here
| |
| does not live long enough
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 131:5...
ServiceStatus
would own a Value
itself, not have a reference (which is what you're trying to do above, to a temporary nonetheless). So it would look like:
// no more lifetime parameter 'a
struct ServiceStatus {
service_name: &'static str,
is_healthy: bool, // ??
service_data: Value, <== holding a value here, not a reference
}
statuses.push(ServiceStatus {
service_name: service_reader.service_name(),
is_healthy: service_reader.is_healthy(),
service_data: service_reader.service_data().clone(),
});
I'm going to assume is_healthy
is just a bool
or some other Copy
type.
Got it. That solves the lifetime problem. Thank you!