I'm keeping a Connection wrapped in an Option in a property of a struct and I'm having trouble closing the Connection. I have checked a lot of answers here at stackoverflow for the general problem but I couldnĀ“t get it working for my case.
Here's a minimal example to reproduce the error:
use rusqlite::Connection;
struct Db {
c: Option<Connection>
}
impl Db {
pub fn new() -> Self {
return Db { c: None }
}
pub fn open(&mut self) {
self.c = Some(Connection::open("test.db").unwrap());
}
pub fn close(&mut self) {
self.c.as_ref().unwrap().close();
}
}
fn main() {
let mut d= Db::new();
d.open();
d.close();
}
I get the following output, using Rust 1.61.0 (Arch Linux rust 1:1.61.0-1) with Cargo and rusqlite (rusqlite = { version = "0.27.0", features = ["bundled"] })
error[E0507]: cannot move out of a shared reference
--> foo.rs:18:9
|
18 | self.c.as_ref().unwrap().close();
| ^^^^^^^^^^^^^^^^^^^^^^^^^-------
| | |
| | value moved due to this method call
| move occurs because value has type `Connection`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves value
--> ~.cargo/registry/src/github.com-1ecc6299db9ec823/rusqlite-0.27.0/src/lib.rs:725:18
|
725 | pub fn close(self) -> Result<(), (Connection, Error)> {
| ^^^^
For more information about this error, try `rustc --explain E0507`.
The function close() from the rusqlite library which the output refers to looks like this:
/// Close the SQLite connection.
///
/// This is functionally equivalent to the `Drop` implementation for
/// `Connection` except that on failure, it returns an error and the
/// connection itself (presumably so closing can be attempted again).
///
/// # Failure
///
/// Will return `Err` if the underlying SQLite call fails.
#[inline]
pub fn close(self) -> Result<(), (Connection, Error)> {
self.flush_prepared_statement_cache();
let r = self.db.borrow_mut().close();
r.map_err(move |err| (self, err))
}
How can I fix this error without changing the general architecture, that is keeping the Connection wrapped in an Option in a property of a struct and closing it via an implementation method?
The Connection::close method consumes self, so you have to take the wrapped value inside self.c out in order to call close on it. After takeing, the c becomes None.
use rusqlite::Connection;
struct Db {
c: Option<Connection>,
}
impl Db {
pub fn new() -> Self {
return Db { c: None };
}
pub fn open(&mut self) {
self.c = Some(Connection::open("test.db").unwrap());
}
pub fn close(&mut self) {
self.c.take().unwrap().close().unwrap();
}
}
fn main() {
let mut d = Db::new();
d.open();
d.close();
}
Documentation of std::option::Option::take
Related
I created two structs, Car and CarModifier. Both Car and CarModifier are instantiated in main.rs. CarModifier modifies one of the fields of Car using data from curl request. Here is the code:
main.rs
use sample::{car::Car, car_modifier::CarModifier};
fn main() {
println!("Hello, world!");
let mut car = Car::new();
let mut car_modifier = CarModifier::new();
car_modifier.update_car(&mut car);
println!("{:?}", car.driver);
}
Car.rs
#[derive(Debug)]
pub struct Car<'a> {
pub driver: &'a [u8]
}
impl<'a> Car<'a> {
pub fn new() -> Self {
Self {
driver: &[26]
}
}
pub fn update_driver(&mut self, new_driver: &'a [u8]) {
self.driver = new_driver;
}
}
CarModifier.rs
use curl::easy::Easy;
use crate::{car::Car};
pub struct CarModifier;
impl CarModifier {
pub fn new() -> Self {
Self {
}
}
pub fn update_car(&mut self, car: &mut Car) {
let mut easy = Easy::new();
easy.url("https://www.rust-lang.org/").unwrap();
let mut transfer = easy.transfer();
transfer.write_function(|data: &[u8]| {
car.update_driver(data);
Ok(data.len())
}).unwrap();
transfer.perform().unwrap();
}
}
This is the error which I get when trying to run
error[E0521]: borrowed data escapes outside of closure
--> src/car_modifier.rs:19:13
|
13 | pub fn update_car(&mut self, car: &mut Car) {
| --- `car` declared here, outside of the closure body
...
18 | transfer.write_function(|data: &[u8]| {
| ---- `data` is a reference that is only valid in the closure body
19 | car.update_driver(data);
| ^^^^^^^^^^^^^^^^^^^^^^^ `data` escapes the closure body here
For more information about this error, try `rustc --explain E0521`.
error: could not compile `sample` due to previous error
I seem to understand from the error that data lives only in the closure body and the code tries to refer that in car.driver which will outlive the closure body, hence the error. Is this the right understanding?
I am also aware that instead of using &[u8], I could use Vec<u8> to resolve the error. But how can I keep using &[u8]?
Basically data belongs to the curl library. It may be a slice of some library internal buffer pool, and may be re-used for some other curl api calls later on, or freed after this call. You need to copy data into the Car structure instead of just having a pointer to the underlying buffer. Rust compiler helps you to catch that problem. In C++ the compiler won't even tell you this error and the C++ code will have runtime problems.
Im still trying to wrap my head around lifetimes in rust but ive run into a problem. I have a struct that has a map and im tryign to add to that map in a function. It maps a string id to an object:
pub struct AGVController<'a> {
agv_map: HashMap<&'a str, AGV>
}
impl AGVController<'_> {
// Create a new AGV Controller
pub fn new() -> Self {
Self {
agv_map: HashMap::new()
}
}
// Add a new AGV
pub fn add_agv(&mut self, ip_addr: &str) -> Option<&str> {
let new_agv = AGV::new(ip_addr);
match self.agv_map.get(ip_addr) {
Some(_) => {
let result = format!("AGV with ip address {} already exists", ip_addr);
return Some(result.as_str());
},
None => {
self.agv_map.insert(ip_addr, new_agv);
}
}
return Some("");
}
}
in add new I want to create a new instance and add that to the map. Im getting the following error:
lifetime of reference outlives lifetime of borrowed content...
--> src/agv/agv_controller.rs:58:37
|
58 | self.agv_map.insert(ip_addr, new_agv);
| ^^^^^^^
|
note: ...the reference is valid for the lifetime `'_` as defined here...
--> src/agv/agv_controller.rs:16:20
|
16 | impl AGVController<'_> {
| ^^
note: ...but the borrowed content is only valid for the anonymous lifetime defined here
--> src/agv/agv_controller.rs:50:40
|
50 | pub fn add_agv(&mut self, ip_addr: &str) -> Option<&str> {
| ^^^^
It seems like it is saying that the reference in the map will outlive the reference of the parameter passed in, which is fair I guess.
Can someone explain to me how I add an entry to a map in a function where the key is passed into the function?
This fails because the lifetime of the ip_addr reference is only valid while the add_agv method executes, but it needs to be valid for the 'a in AGVController<'a>. To fix this, add the 'a lifetime to your impl block and use it for this parameter:
impl<'a> AGVController<'a> {
// ...
pub fn add_agv(&mut self, ip_addr: &'a str) -> Option<&str> {
Which brings us to the second problem: you attempt to return a &str to a String that is owned by this function (in result). This is simply impossible; return an Option<String> instead, making the appropriate changes to your return statements.
pub fn add_agv(&mut self, ip_addr: &'a str) -> Option<String> {
return Some(result);
return Some("".to_owned());
(Playground)
Alternatively, consider returning a Result, which is a better way to indicate an operation that can fail:
use std::error::Error;
use std::fmt::{Display, Formatter, Error as FmtError};
#[derive(Debug)]
pub struct DuplicateIPAddress(pub String);
impl Error for DuplicateIPAddress {}
impl Display for DuplicateIPAddress {
fn fmt(&self, w: &mut Formatter) -> Result<(), FmtError> {
write!(w, "Duplicate IP address {}", self.0)
}
}
Now your function can return Result<(), DuplicateIPAddress>:
pub fn add_agv(&mut self, ip_addr: &'a str) -> Result<(), DuplicateIPAddress> {
return Err(DuplicateIPAddress(ip_addr.to_owned()));
return Ok(());
(Playground)
I created a library to deal with digraphs: nodes that link (reference counted) to zero or one other nodes (as in linked lists, but in a digraph a node can be linked to by more than one node).
I am trying to use my library to create a list with a current node:
struct ListWithPointer<'a> {
pub nodes: DigraphNodeRef<String>,
pub current_node: Option<&'a mut DigraphNodeRef<String>>,
}
current_node points to a link in the list.
Now I am trying to move current node to the next element of the list (or to the beginning if the list ended):
fn next_node<'a>(this: &'a mut ListWithPointer<'a>) {
if this.current_node.is_some() {
this.current_node.iter_mut().for_each(|a| {
(*a).as_rc_mut().iter_mut()
.for_each(|rc| this.current_node = Some(&mut Arc::get_mut(rc).unwrap().next));
});
} else {
this.current_node = Some(&mut this.nodes);
}
}
but whatever I do, it fails with an error like:
error[E0500]: closure requires unique access to `this.current_node` but it is already borrowed
--> src/lib.rs:150:51
|
148 | fn next_node<'a>(this: &'a mut ListWithPointer<'a>) {
| -- lifetime `'a` defined here
149 | if this.current_node.is_some() {
150 | this.current_node.iter_mut().for_each(|a| {
| ---------------------------- ^^^ closure construction occurs here
| |
| borrow occurs here
| argument requires that `this.current_node` is borrowed for `'a`
151 | (*a).as_rc_mut().iter_mut()
152 | .for_each(|rc| this.current_node = Some(&mut Arc::get_mut(rc).unwrap().next));
| ----------------- second borrow occurs due to use of `this.current_node` in closure
Help to rewrite without errors.
Here is the library code:
use std::sync::Arc;
#[derive(Clone)]
pub struct DigraphNode<T> {
pub next: DigraphNodeRef<T>, // I made it `pub` to be able `item.next.next()` to remove an item from the middle.
data: T,
}
impl<T> DigraphNode<T> {
fn new(next: DigraphNodeRef<T>, data: T) -> Self {
Self { next, data }
}
}
pub struct DigraphNodeRef<T> {
rc: Option<Arc<DigraphNode<T>>>,
}
impl<T> DigraphNodeRef<T> {
pub fn new() -> Self {
Self {
rc: None
}
}
pub fn from_node(value: DigraphNode<T>) -> Self {
Self::from(Some(Arc::new(value)))
}
pub fn from(rc: Option<Arc<DigraphNode<T>>>) -> Self {
Self {
rc
}
}
pub fn as_rc(&self) -> &Option<Arc<DigraphNode<T>>> {
&self.rc
}
pub fn as_rc_mut(&mut self) -> &mut Option<Arc<DigraphNode<T>>> {
&mut self.rc
}
pub fn is_none(&self) -> bool {
self.rc.is_none()
}
pub fn remove(&mut self) -> bool {
if let Some(rc) = self.rc.clone() {
self.rc = rc.next.rc.clone();
true
} else {
false
}
}
pub fn prepend(&mut self, value: T) -> Self {
let new_node = DigraphNode::new(self.clone(), value);
let new_node_ref = DigraphNodeRef::from_node(new_node);
*self = new_node_ref.clone();
new_node_ref
}
pub fn node(&self) -> Option<DigraphNode<T>>
where T: Clone
{
self.rc.clone().map(|node| (*node).clone())
}
/// TODO: Should return a reference.
pub fn data(&self) -> Option<T>
where T: Clone
{
self.rc.clone().map(|node| (*node).data.clone())
}
pub fn values(self) -> DigraphNodeValuesIterator<T> {
DigraphNodeValuesIterator {
underlying: self.clone()
}
}
}
impl<T> Clone for DigraphNodeRef<T> {
fn clone(&self) -> Self {
Self { rc: self.rc.clone() }
}
}
impl<T> Iterator for DigraphNodeRef<T> {
type Item = Arc<DigraphNode<T>>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(rc) = self.rc.clone() {
self.rc = rc.next.rc.clone();
Some(rc.clone())
} else {
None
}
}
}
pub struct DigraphNodeValuesIterator<T> {
underlying: DigraphNodeRef<T>,
}
impl<T: Clone> Iterator for DigraphNodeValuesIterator<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.underlying.next().map(|node| node.data.clone())
}
}
In Rust the mutable access is ensured to be exclusive, i.e. if you hold a reference, some other code can't grab a mutable reference.
Problem is this line:
this.current_node.iter_mut().for_each(...)
It grabs a mutable access to current_node, so it can't regain it again down the line.
Not to mention that iterating over Option is a strange decision.
If you want to move current_node to a different place, I'd try to reorganize your code such that reads are separate from writes, and they are performed in a sequence, instead of trying to do it in one go:
// detach the current_node for moving
if let Some(current_node_to_move) = this.current_node.take() {
let new_current_node_ref: &mut ... = ... // find new location logic
new_current_node_ref.replace(current_node_to_move);
} else {
...
}
Here in line 1 it does a write None update to current_node via this, but immediately relinquishes the mutable reference. Line 2 does a read (search), but also grabs a mutable reference to a new location. Line 3 writes to this location.
To get the linked list implementation right, I recommend https://rust-unofficial.github.io/too-many-lists/
I have this trait and implementation:
#[async_trait]
pub trait AsyncKeyProvider {
async fn get_key_async(&mut self, key_id: &str) -> Result<Option<Jwk>, ()>;
fn as_any(&self) -> &dyn Any;
}
#[async_trait]
impl AsyncKeyProvider for GoogleKeyProvider {
async fn get_key_async(&mut self, key_id: &str) -> Result<Option<Jwk>, ()> {
{...}
}
fn as_any(&self) -> &dyn Any {
self
}
}
In order to pass it into my handler in actix-web, I'm passing through a GoogleKeyProvider like this:
let key_provider = web::Data::from(Arc::new(GoogleKeyProvider::default()));
let server = HttpServer::new(move || {
App::new()
.app_data(key_provider.clone())
.route("/validate", web::post().to(validate))
})
With the handler doing this:
pub async fn validate(jwt_body: web::Json<JwtBody>, provider: web::Data<Box<dyn AsyncKeyProvider>>) -> impl Responder {
let provider_object: &GoogleKeyProvider = provider.as_any().downcast_ref::<GoogleKeyProvider>().expect("Wasn't a GoogleKeyProvider");
match validate_jwt(&jwt_body.jwt, provider_object).await {
{...}
}
}
validate_jwt then tries to call a method on the provider struct like this:
async fn validate_jwt(jwt: &String, provider: &GoogleKeyProvider) -> Result<bool, Box<dyn std::error::Error>> {
let key_to_use = provider.get_key_async(<thing>).await.unwrap();
}
Which presents me with this error:
error[E0596]: cannot borrow `*provider` as mutable, as it is behind a `&` reference
--> src\routes\validate.rs:48:22
|
48 | let key_to_use = provider.get_key_async(<thing>).await.unwrap();
| ^^^^^^^^ `provider` is a `&` reference, so the data it refers to cannot be borrowed as mutable
As far as I can understand, this is happening because the result of my downcasting is a reference (due to downcast_ref), but I think I'd be wanting the plain GoogleKeyProvider type instead - I'm not sure on that though. I believe the provider needs to be mutable as the values inside it (see below) can change during the lifetime of the provider (it's intended to provide a temporary cache for some keys, and automatically update them if they're out of date)
#[derive(Clone)]
pub struct GoogleKeyProvider {
cached: Option<JwkSet>,
expiration_time: Instant,
}
I'm not sure how to get this working with downcasting, though. Is anyone able to help me see where I've gone wrong?
You have to choice if get_key_async update somme thing at the struct.
The simple code below show you the error
trait Atrait {
fn afn(&mut self) -> i32;
}
struct Astruct {}
impl Atrait for Astruct {
fn afn(&mut self) -> i32 {
2
}
}
fn main()
{
// test should be mutable
let test = Astruct{};
let value = test.afn();
println!("Value {}", value);
}
This work because afn(self) is not declared mutable afn(&mut self)
trait Atrait {
fn afn(&self) -> i32;
}
struct Astruct {}
impl Atrait for Astruct {
fn afn(&self) -> i32 {
2
}
}
fn main()
{
let test = Astruct{};
let value = test.afn();
println!("Value {}", value);
}
// GMatrix is the structure that will implement the matrix
pub struct GMatrix {
pub vec_list: Vec<String>,
pub matrix: Vec<Vec<i32>>,
}
impl GMatrix {
pub fn new() -> GMatrix {
let v: Vec<Vec<i32>> = Vec::new();
GMatrix {
vec_list: vec![],
matrix: v,
}
}
// insert_vertex inserts into the vertex
pub fn insert_vertex(&mut self, vertex_name: &str) -> Result<(), String> {
if self.vec_list.iter().any(|i| i == vertex_name) {
return Err(format!("Vector already present"));
}
self.vec_list.push(vertex_name.to_string());
let mut v: Vec<i32> = Vec::new();
self.matrix.append(&v);
self.update_vector();
Ok(())
}
/// update_vector adds another row when another vector is added
/// will be called inside insert_vector function, so no need to
/// be public
fn update_vector(&mut self) {
for i in 0..self.vec_list.len() - 1 {
if self.matrix[i].len() < self.vec_list.len() {
self.matrix[i].push(-1);
}
}
}
}
I am trying I guess the error is in line 23 where I try to append another vector. The compiler throws the error.
|
23 | self.matrix.append(&v);
| ^^ types differ in mutability
|
= note: expected mutable reference `&mut Vec<Vec<i32>>`
found reference `&Vec<i32>`
error: aborting due to previous error
I thought I created a vector in insert_vertex that is mutable, and yet I try to append it to another vector I get an error.