egui icon indicating copy to clipboard operation
egui copied to clipboard

Add Support for Custom Storage Backends in eframe via a New NativeOptions Field

Open UnknownSuperficialNight opened this issue 10 months ago • 4 comments

Problem: Currently, eframe only supports saving app state using RON files. This limitation restricts developers who wish to integrate with different storage systems like SQLite or handle deserialization themselves for alternative data formats.

Solution: Introduce a customization option that allows users to provide a custom storage mechanism. This could be achieved by accepting a closure or function during initialization, enabling dynamic storage creation (e.g., SQLite, PostgreSQL).

https://github.com/emilk/egui/blob/0db56dc9f1a8459b5b9376159fab7d7048b19b65/crates/eframe/src/native/glow_integration.rs#L193-L209

https://github.com/emilk/egui/blob/0db56dc9f1a8459b5b9376159fab7d7048b19b65/crates/eframe/src/native/epi_integration.rs#L130-L147

Proposed Implementation: Modify eframe to accept a Box<dyn Fn() -> Box<dyn crate::epi::Storage>> as an optional parameter in the initialization process. This closure would allow developers to return their own custom storage implementation instead of the default FileStorage.

Examples:

pub struct NativeOptions {
    // ... other fields ...
    pub persistence_path: Option<PathBuf>,
    /// Override the default storage creation with your own custom storage implementation
    pub storage_creator: Option<Box<dyn Fn() -> Option<Box<dyn crate::epi::Storage>>>>,
}
fn init_run_state(
    &mut self,
    event_loop: &ActiveEventLoop,
) -> Result<&mut GlowWinitRunning<'app>> {
    profiling::function_scope!();

    let storage = if let Some(storage_creator) = &self.native_options.storage_creator {
        storage_creator()
    } else if let Some(file) = &self.native_options.persistence_path {
        epi_integration::create_storage_with_file(file)
    } else {
        epi_integration::create_storage(
            self.native_options
                .viewport
                .app_id
                .as_ref()
                .unwrap_or(&self.app_name),
        )
    };

    // ... rest of function
}

UnknownSuperficialNight avatar Feb 06 '25 03:02 UnknownSuperficialNight

Same problem. Currently i’m just ignoring the provided Storage ref when saving state, pointing at my own, but i’d like to not have that RON file exist in the first place and install my own Storage properly. I have an SQLite-based settings DB and have in it a table for all the eframe stuff.

Evrey avatar Feb 15 '25 22:02 Evrey

I also have a need for creating my own storage backend and would like to not go around the eframe structure to achieve it. The proposed solution from @UnknownSuperficialNight was actually what I was intuitively searching for. I was pretty surprised when I found that I can only ever get an immutable reference to the storage except in the save() function. Something like the storage creator closure in NativeOptions would also fully solve my problems.

Matzeall avatar Jun 13 '25 21:06 Matzeall

I also have a need for creating my own storage backend and would like to not go around the eframe structure to achieve it. The proposed solution from @UnknownSuperficialNight was actually what I was intuitively searching for. I was pretty surprised when I found that I can only ever get an immutable reference to the storage except in the save() function. Something like the storage creator closure in NativeOptions would also fully solve my problems.

Yep at this point ill just make a Pull Request and see what happens

UnknownSuperficialNight avatar Jun 14 '25 04:06 UnknownSuperficialNight

This would also be great for web, since there's no way to select where egui stores data at all. It stores everything in just localStorage, not even in a separate object, which clutters it. And it's especially bad when multiple egui projects are hosted on the same site (like github pages)

Ved-s avatar Nov 14 '25 04:11 Ved-s