bevy_simple_preferences 0.1.0

A simple Preferences API for Bevy
Documentation
use crate::serializable_map::{PreferencesSerializableMap, PreferencesSerializableMapSeed};
use bevy::log::*;
use serde::de::DeserializeSeed;

use crate::storage::PreferencesStorage;
use crate::Result;

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
enum GlooStorageType {
    Local,
    Session,
}

pub(crate) struct GlooStorage {
    storage_type: GlooStorageType,
    preferences_key: String,
    load_preferences:
        fn(&str, PreferencesSerializableMapSeed) -> Result<PreferencesSerializableMap>,
    save_preferences: fn(&str, map: &PreferencesSerializableMap) -> Result<()>,
}

impl GlooStorage {
    fn new<T: gloo_storage::Storage>(
        storage_type: GlooStorageType,
        preferences_key: impl Into<String>,
    ) -> Self {
        Self {
            storage_type,
            preferences_key: preferences_key.into(),
            load_preferences: load_preferences::<T>,
            save_preferences: save_preferences::<T>,
        }
    }

    pub fn local(preferences_key: impl Into<String>) -> Self {
        Self::new::<gloo_storage::LocalStorage>(GlooStorageType::Local, preferences_key)
    }

    pub fn session(preferences_key: impl Into<String>) -> Self {
        Self::new::<gloo_storage::SessionStorage>(GlooStorageType::Session, preferences_key)
    }
}

impl PreferencesStorage for GlooStorage {
    fn load_preferences(
        &self,
        seed: PreferencesSerializableMapSeed,
    ) -> Result<PreferencesSerializableMap> {
        let preferences = (self.load_preferences)(&self.preferences_key, seed)?;
        info!("Loaded preferences from {:?}Storage", self.storage_type);
        Ok(preferences)
    }

    fn save_preferences(&self, map: &PreferencesSerializableMap) -> Result<()> {
        (self.save_preferences)(&self.preferences_key, map)?;
        debug!("Saved preferences on {:?}Storage", self.storage_type);
        Ok(())
    }
}

fn load_preferences<T: gloo_storage::Storage>(
    key: &str,
    seed: PreferencesSerializableMapSeed,
) -> Result<PreferencesSerializableMap> {
    Ok(T::get_by_seed(key, seed)?)
}

fn save_preferences<T: gloo_storage::Storage>(
    key: &str,
    map: &PreferencesSerializableMap,
) -> Result<()> {
    T::set(key, map)?;
    Ok(())
}

trait GlooStorageExt {
    fn get_by_seed<S>(
        key: impl AsRef<str>,
        seed: S,
    ) -> gloo_storage::Result<<S as DeserializeSeed<'static>>::Value>
    where
        S: for<'de> DeserializeSeed<'de>;
}

impl<T> GlooStorageExt for T
where
    T: gloo_storage::Storage,
{
    fn get_by_seed<S>(
        key: impl AsRef<str>,
        seed: S,
    ) -> gloo_storage::Result<<S as DeserializeSeed<'static>>::Value>
    where
        S: for<'de> DeserializeSeed<'de>,
    {
        let key = key.as_ref();
        let item_string = T::raw()
            .get_item(key)
            .expect("unreachable: get_item does not throw an exception")
            .ok_or_else(|| gloo_storage::errors::StorageError::KeyNotFound(key.to_string()))?;

        let mut deserializer = serde_json::de::Deserializer::from_reader(item_string.as_bytes());
        let item = seed.deserialize(&mut deserializer)?;

        Ok(item)
    }
}