I have a struct MySQLData
holding a field conn
with type mysql::Pool
and some functions to initialize a connection, add a user to the database,...
Now I want to have some kind of 'global/static' variable in my code ONE TIME. So I can always use the same variable to access all the functions in MySQLData.
Simplified version of code:
pub mod mysqldata {
pub struct MySQLData {
pub conn: u8
}
impl MySQLData {
pub fn init_connection() -> MySQLData {
MySQLData {
conn: 1
}
}
pub fn init_tables(&mut self) {
println!("Tables initialized...");
}
pub fn add_user(&mut self, data: String) {
self.conn = self.conn +1;
}
pub fn read_user(&mut self, id : u8) -> String {
unimplemented!()
}
}
}
fn register() {
unsafe {
//HERE I JUST WANT TO USE THE STATIC VARIABLE
db.unwrap().add_user("test".to_string());
}
}
//STATIC VARIABLE I WANT
static mut db : Option<mysqldata::MySQLData> = None;
fn main() {
unsafe {
//HERE I WANT TO DEFINE THE VARIABLE ONCE
db = Some(mysqldata::MySQLData::init_connection())
}
register();
}
This generates the following error:
db.unwrap().add_user("test".to_string());
| ^^ move occurs because `db` has type `std::option::Option<mysqldata::MySQLData>`, which does not implement the `Copy` trait
How would I achieve this? In this project I achieved this by defining the variable db
in my main and passing it as a parameter all functions. But I guess there should be a more elegant solution for this.
Full code:
use actix_cors::Cors;
use actix_web::{web, get, middleware, Result, Responder, HttpResponse, HttpServer, App};
use actix_web::http::StatusCode;
use serde::Deserialize;
use mysql::prelude::Queryable;
// Module for MySQL
pub mod mysqldata {
use mysql::prelude::Queryable;
use crate::RegistrationForm;
pub struct MySQLData {
pub conn: mysql::Pool
}
impl MySQLData {
//Return MySQLData object with conn field
pub fn init_connection(database_name : &String, database_user : &String, database_pass : &String) -> MySQLData {
let conn_str : String = format!("mysql://{user}:{pass}@localhost/{name}", user=database_user, pass=database_pass, name=database_name);
let conn = mysql::Pool::new(conn_str);
match conn {
Ok(_) => {
println!("Connection to {} successful!", database_name);
MySQLData {
conn: conn.unwrap()
}
},
Err(e) => {
eprintln!("Connection to {} failed: {}", database_name, e.to_string());
std::process::exit(-1);
}
}
}
// Initialize all needed tables
pub fn init_tables(&mut self) {
let mut conn = self.conn.get_conn().unwrap();
conn.query_drop(
"CREATE TABLE IF NOT EXISTS users (
ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
username VARCHAR(255) NOT NULL,
email VARCHAR(256) NOT NULL,
birthdate DATETIME,
password VARCHAR(255) NOT NULL
)"
);
println!("Tables initialized...");
}
pub fn add_user(&mut self, data: RegistrationForm) {
}
pub fn read_user(&mut self, id: u8) -> RegistrationForm {
unimplemented!()
}
}
}
#[derive(Deserialize)]
struct RegistrationForm {
username: String,
email: String,
birthdate: String,
password: String,
rp_password: String
}
//Function which gets executed with correct route
async fn register(form: web::Form<RegistrationForm>) {
unsafe {
//HERE I JUST WANT TO USE THE STATIC VARIABLE
db.unwrap().add_user(form.into_inner());
}
}
//STATIC VARIABLE I WANT
static mut db : Option<mysqldata::MySQLData> = None;
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
unsafe {
//HERE I WANT TO DEFINE THE VARIABLE ONCE
db = Some(mysqldata::MySQLData::init_connection(&String::from("rustsite"), &String::from("root"), &String::from("toor")))
}
HttpServer::new(|| App::new()
.wrap(
Cors::new()
.allowed_origin("http://rustsite.local")
.finish()
)
.service(
web::resource("/register").route(web::post().to(register))
)
)
.bind("127.0.0.1:8088")?
.run()
.await
}
Solution:
lazy_static! {
static ref db : mysqldata::MySQLData = mysqldata::MySQLData::init_connection(&String::from("rustsite"), &String::from("root"), &String::from("toor"));
}