use bevy::prelude::*;
use bevy::reflect::FromType;
use std::sync::Arc;
use thiserror::Error;
pub mod serializable_map;
mod plugin;
mod registry;
mod resource;
pub mod storage;
pub use crate::plugin::PreferencesPlugin;
pub use crate::registry::RegisterPreferencesExt;
pub use crate::resource::{Preferences, PreferencesResource};
use crate::storage::PreferencesStorage;
#[cfg(not(target_family = "wasm"))]
use crate::storage::fs::{DefaultFileStorageFormat, FileStorageFormatFns};
#[derive(Error, Debug)]
pub enum PreferencesError {
#[cfg(not(target_family = "wasm"))]
#[error("I/O Error: {0}")]
IoError(#[from] std::io::Error),
#[error("Deserialization Error: {0}")]
DeserializationError(Box<dyn std::error::Error + Send + Sync>),
#[cfg(not(target_family = "wasm"))]
#[error("Serialization Error: {0}")]
SerializationError(Box<dyn std::error::Error + Send + Sync>),
#[error("Type {0} not registered")]
UnregisteredType(String),
#[cfg(target_family = "wasm")]
#[error("Error getting from storage: {0}")]
GlooError(#[from] gloo_storage::errors::StorageError),
}
pub(crate) type Result<T> = std::result::Result<T, PreferencesError>;
#[derive(Clone, Default)]
pub enum PreferencesStorageType {
NoStorage,
#[default]
DefaultStorage,
Custom(Arc<dyn PreferencesStorage>),
#[cfg(not(target_family = "wasm"))]
FileSystemWithParentDirectory(std::path::PathBuf),
#[cfg(not(target_family = "wasm"))]
FileSystemWithFormat(FileStorageFormatFns),
#[cfg(not(target_family = "wasm"))]
FileSystemWithParentDirectoryAndFormat(std::path::PathBuf, FileStorageFormatFns),
#[cfg(target_family = "wasm")]
LocalStorage,
#[cfg(target_family = "wasm")]
SessionStorage,
}
impl PreferencesStorageType {
#[cfg(not(target_family = "wasm"))]
fn file_storage_path(&self) -> Option<std::path::PathBuf> {
match self {
PreferencesStorageType::NoStorage => None,
PreferencesStorageType::Custom(_) => None,
PreferencesStorageType::DefaultStorage
| PreferencesStorageType::FileSystemWithFormat(_) => {
Some(dirs::preference_dir().expect("Cannot resolve preference_dir"))
}
PreferencesStorageType::FileSystemWithParentDirectory(path)
| PreferencesStorageType::FileSystemWithParentDirectoryAndFormat(path, _) => {
Some(path.clone())
}
}
}
#[cfg(not(target_family = "wasm"))]
fn file_storage_format(&self) -> Option<FileStorageFormatFns> {
match self {
PreferencesStorageType::NoStorage => None,
PreferencesStorageType::Custom(_) => None,
PreferencesStorageType::DefaultStorage
| PreferencesStorageType::FileSystemWithParentDirectory(_) => {
Some(FileStorageFormatFns::from_format::<DefaultFileStorageFormat>())
}
PreferencesStorageType::FileSystemWithFormat(format)
| PreferencesStorageType::FileSystemWithParentDirectoryAndFormat(_, format) => {
Some(*format)
}
}
}
#[cfg(target_family = "wasm")]
fn gloo_storage(
&self,
preferences_key: impl Into<String>,
) -> Option<storage::gloo::GlooStorage> {
match self {
PreferencesStorageType::NoStorage => None,
PreferencesStorageType::Custom(_) => None,
PreferencesStorageType::DefaultStorage => {
Some(storage::gloo::GlooStorage::local(preferences_key))
}
PreferencesStorageType::LocalStorage => {
Some(storage::gloo::GlooStorage::local(preferences_key))
}
PreferencesStorageType::SessionStorage => {
Some(storage::gloo::GlooStorage::session(preferences_key))
}
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, SystemSet)]
pub enum PreferencesSet {
Load,
AssignResources,
SetReflectMapValues,
Save,
}
#[diagnostic::on_unimplemented(
message = "`{Self}` can not be used as preferences",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait PreferencesType: FromReflect + TypePath {}
impl<T> PreferencesType for T where T: FromReflect + TypePath {}
#[derive(Clone)]
pub struct ReflectPreferences;
impl<T: PreferencesType> FromType<T> for ReflectPreferences {
fn from_type() -> Self {
Self
}
}