Skip to content

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

@UnknownSuperficialNight

Description

@UnknownSuperficialNight

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).

fn init_run_state(
&mut self,
event_loop: &ActiveEventLoop,
) -> Result<&mut GlowWinitRunning<'app>> {
profiling::function_scope!();
let storage = 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),
)
};

/// For loading/saving app state and/or egui memory to disk.
pub fn create_storage(_app_name: &str) -> Option<Box<dyn epi::Storage>> {
#[cfg(feature = "persistence")]
if let Some(storage) = super::file_storage::FileStorage::from_app_id(_app_name) {
return Some(Box::new(storage));
}
None
}
#[allow(clippy::unnecessary_wraps)]
pub fn create_storage_with_file(_file: impl Into<PathBuf>) -> Option<Box<dyn epi::Storage>> {
#[cfg(feature = "persistence")]
return Some(Box::new(
super::file_storage::FileStorage::from_ron_filepath(_file),
));
#[cfg(not(feature = "persistence"))]
None
}

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
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions