0

I store a Params structure into a SERVICES singleton. With the get_params() function, I get the Params structure back, but we must clone the structure's items in order to use it.

use lazy_static::lazy_static; // 1.4.0
use std::collections::HashMap;
use std::sync::Mutex;

#[derive(Debug)]
pub struct Params {
    pub verbose: bool,
    pub config_file: String,
}

lazy_static! {
    #[derive(Debug)]
    static ref SERVICES : Mutex<HashMap<&'static str, Params>> = Mutex::new( {
         HashMap::new()
    });
}

// OK
pub fn get_params() -> Params {
    let serv_map = &SERVICES.lock().unwrap();

    let cf: String = serv_map.get("params").unwrap().config_file.clone(); // clone here :(
    let verbose = serv_map.get("params").unwrap().verbose;

    Params {
        verbose,
        config_file: cf,
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let params = Params {
        verbose: true,
        config_file: "/user/toto.yml".to_string(),
    };

    {
        SERVICES.lock().unwrap().insert("params", params);
    }

    let pp = get_params();

    if pp.verbose {
        dbg!(&pp.config_file, pp.verbose);
    }
    Ok(())
}

playground

I would like to be able to read the Params data from the singleton, without cloning, using a routine like:

/*
 Cannot compile
*/
pub fn get_params_ref<'lt>() -> &'lt Params {
    let serv_map: &'lt HashMap<&'static str, Params> = &SERVICES.lock().unwrap();

    let pp = &serv_map.get("params").unwrap();

    pp
}

I get:

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:22:57
   |
21 | pub fn get_params_ref<'lt>() -> &'lt Params {
   |                       --- lifetime `'lt` defined here
22 |     let serv_map: &'lt HashMap<&'static str, Params> = &SERVICES.lock().unwrap();
   |                   ----------------------------------    ^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
   |                   |
   |                   type annotation requires that borrow lasts for `'lt`
...
27 | }
   | - temporary value is freed at the end of this statement

I understand why Rust cannot compile this, but is there a solution to get an immutable reference to the Params structure?

0

1 Answer 1

2

As written, you cannot return references to elements of SERVICES because the compiler doesn't know how long those will live: another part of your code could remove a service!

Assuming you only ever add elements to SERVICES but never remove any element then because they are global it's OK to leak them:

Change the definition of Params to

#[derive(Debug)]
pub struct Params {
    pub verbose: bool,
    pub config_file: &'static str,
}

And initialize your parameters' config_file using Box::leak(String::from("foo").into_boxed_str()).

Leaked memory will be reclaimed by your OS when your program shuts down.

See also:

Sign up to request clarification or add additional context in comments.

3 Comments

I have followed your very neat advice here : play.rust-lang.org/… It worked and it's a better solution. But I still have to create another "Params" struct everytime I call the get_params() routine. Is there a way to make the params struct static and return it as a ref ?
Don't bother: A struct with a boolean and a reference is very cheap to copy.
Actually, I pushed your Box technique and put the params in a Box<Params> too and...it worked :) : play.rust-lang.org/… Maybe I can simplify the code but the idea is here. Thanks a lot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.