once_cell
once_cell copied to clipboard
How can I reset the contents
I have a function for creating the instance and initialising the cell, but in some cases, for instance under testing , i need to reset the cell to a new value.
Here is an example:
struct Configuration {
// many more fields but omitted. This object gets created in the "get()" method which loads the cell
name : String
count : i32
}
static INSTANCE: OnceCell<Configuration> = OnceCell::new();
impl Configuration {
pub fn get() -> &'static Configuration {
Instance.get_or_init(|| {
Configuration {
name: "blah".to_string(),
count: 0
}
})
pub fn reset(config: Configuration) {
// how do I reset it? seems this fails if the cell had already been initialized
/// Sets the contents of this cell to `value`.
///
/// Returns `Ok(())` if the cell was empty and `Err(value)` if it was
/// full.
INSTANCE.set(config);
}
}
You need &mut access for that, it is impossible to reset once cell using only a shared ref
On Thursday, 12 November 2020, Avner [email protected] wrote:
I have a function for creating the instance and initialising the cell, but in some cases, for instance under testing , i need to reset the cell to a new value.
Here is an example:
struct Configuration { // many more fields but omitted. This object gets created in the "get()" method which loads the cell name : String count : i32 }
static INSTANCE: OnceCell<Configuration> = OnceCell::new();
impl Configuration { pub fn get() -> &'static Configuration { Instance.get_or_init(|| { Configuration { name: "blah".to_string(), count: 0 } })
pub fn reset(config: Configuration) { // how do I reset it? seems this fails if the cell had already been initialized /// Sets the contents of this cell to
value. /// /// ReturnsOk(())if the cell was empty andErr(value)if it was /// full. INSTANCE.set(config); } }— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/matklad/once_cell/issues/127, or unsubscribe https://github.com/notifications/unsubscribe-auth/AANB3M2MGD573QEBI3BCA5DSPPQM3ANCNFSM4TTJPCOQ .
so what would I need to do for that to work?
I'd change the design to not rely on global static instance of Config. Otherwise, something like OnceCell<Mutex<Config>> or OnceCell<ArcSwap<Config>> should work.
https://docs.rs/arc-swap/0.4.7/arc_swap/
At some level I can see how the request here is a contradiction to the design of once_cell. However, it is a feature that would be great to have: reloading the config. Perhaps there is a version of the once_cell that might have the extra accounting of shared refs required to do so. Likely a related idea, the feature would require encapsulating the shared use of the configuration in the memory that is being "reinitialized".
Update
Per the suggestion, I went with:
// global ref to static value
pub static CFG: OnceCell<ArcSwap<Settings>> = OnceCell::new();
// getter and setters
pub fn config_get() -> Result<Guard<Arc<Settings>>, AppError> {
let cfg = CFG
.get()
.ok_or_else(|| AppError::ConfigError("Config was not initialized".to_string().into()))?
.load();
Ok(cfg)
}
pub fn config_init() -> Result<(), AppError> {
// instantiate the configuration
let new_cfg = Settings::new().map_err(|e| AppError::ConfigError(e.to_string().into()))?;
// set or get the handle to arc
if CFG.get().is_none() {
CFG.set(ArcSwap::from_pointee(new_cfg)).unwrap();
} else {
CFG.get().unwrap().store(Arc::new(new_cfg));
}
Ok(())
}
@EdmundsEcho for “ // set or get the handle to arc” bit, you can use https://docs.rs/once_cell/latest/once_cell/sync/struct.OnceCell.html#method.get_or_init
@matklad -- Thank you for that suggestion; I'll update it accordingly. FYI, the over-all solution was worth the extra effort. Being able to reload axum (in my case) to read the config files by hitting a reload endpoint greatly improves my workflow. Thank you! - E
Thanks, @EdmundsEcho, I have the exact use-case, and your solution seems to be working fine. Much appreciated!