From 90e1afa3e1a3450871b1b512bd6e8d7e7bea7da0 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 10 Oct 2024 18:19:36 +1300 Subject: [PATCH 01/39] loading maybe working --- crates/bevy_editor_settings/Bevy.toml | 0 crates/bevy_editor_settings/Cargo.toml | 7 - .../src/file_system/load.rs | 164 ++++++++++++++++++ .../src/file_system/mod.rs | 39 +++++ crates/bevy_editor_settings/src/lib.rs | 97 +++++------ .../bevy_editor_settings/src/modals/editor.rs | 14 -- crates/bevy_editor_settings/src/modals/mod.rs | 2 - .../src/modals/project.rs | 21 --- .../bevy_editor_settings/src/modals/user.rs | 11 +- .../src/modals/workspace.rs | 12 +- crates/bevy_editor_settings/src/persistent.rs | 60 ------- 11 files changed, 251 insertions(+), 176 deletions(-) create mode 100644 crates/bevy_editor_settings/Bevy.toml create mode 100644 crates/bevy_editor_settings/src/file_system/load.rs create mode 100644 crates/bevy_editor_settings/src/file_system/mod.rs delete mode 100644 crates/bevy_editor_settings/src/modals/editor.rs delete mode 100644 crates/bevy_editor_settings/src/modals/project.rs delete mode 100644 crates/bevy_editor_settings/src/persistent.rs diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml new file mode 100644 index 00000000..e69de29b diff --git a/crates/bevy_editor_settings/Cargo.toml b/crates/bevy_editor_settings/Cargo.toml index 0badc32c..b4b11542 100644 --- a/crates/bevy_editor_settings/Cargo.toml +++ b/crates/bevy_editor_settings/Cargo.toml @@ -3,19 +3,12 @@ name = "bevy_editor_settings" version = "0.1.0" edition = "2021" -[features] -default = [] -schema = ["schemars"] [dependencies] bevy.workspace = true -serde.workspace = true thiserror.workspace = true toml = "0.8.19" directories = "5.0.1" -# used for generating a json schema which can be used with toml -schemars = { version = "0.8.21", features = ["semver"], optional = true} - [lints] workspace = true diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs new file mode 100644 index 00000000..01f45fd8 --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -0,0 +1,164 @@ +use std::any::TypeId; + +use bevy::{ + prelude::*, + reflect::{ + DynamicEnum, DynamicTuple, DynamicVariant, Enum, EnumInfo, ReflectFromPtr, ReflectMut, + TypeInfo, ValueInfo, VariantInfo, + }, + scene::ron::{de, value}, +}; + +use crate::{SettingsTags, SettingsType}; + +/// Load a toml file from the given path +pub fn load_toml_file(path: impl AsRef) -> Result { + let path = path.as_ref(); + let file = std::fs::read_to_string(path)?; + Ok(toml::from_str(&file)?) +} + +/// Errors that can occur when loading a TOML file. +#[derive(Debug, thiserror::Error)] +pub enum LoadError { + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + #[error("TOML deserialization error: {0}")] + TomlDe(#[from] toml::de::Error), +} + +/// check that the settings type matchs the settings type of the file +/// if they don't match, skip the settings +macro_rules! check_settings_type { + ($settings_type:expr, $file_settings_type:expr) => { + if $settings_type != $file_settings_type { + continue; + } + }; +} + +pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: SettingsType) { + let registry = world.get_resource::().unwrap().clone(); + // get all resources that + let resources = world + .iter_resources() + .filter_map(|(res, _)| res.type_id().map(|type_id| (type_id, res.id()))) + .collect::>(); + + for (type_id, res_id) in resources { + if let Some(type_reg) = registry.read().get(type_id) { + match type_reg.type_info() { + TypeInfo::Struct(struct_info) => { + let s_type = struct_info.custom_attributes().get::(); + if let Some(s_type) = s_type { + check_settings_type!(settings_type, *s_type); + let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); + let reflect_from_ptr = type_reg.data::().unwrap(); + // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for + #[allow(unsafe_code)] + let ReflectMut::Struct(strct) = + unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() + else { + panic!("Expected Struct"); + }; + load_struct(®istry, strct, &table); + } + } + + // Other types cannot be preferences since they don't have attributes. + _ => {} + } + } + // println!("Saving preferences for {:?}", res.name()); + } +} + +fn load_struct( + registry: &AppTypeRegistry, + strct: &mut dyn Struct, + table: &toml::Table, +) { + for i in 0..strct.field_len() { + let key = strct.name_at(i).unwrap().to_string(); + let field_mut = strct.field_at_mut(i).unwrap(); + match field_mut.get_represented_type_info().unwrap() { + TypeInfo::Value(value_info) => { + if let Some(value) = table.get(&key) { + load_value(field_mut, value_info, value) + } + } + TypeInfo::Struct(_) => { + if let Some(table) = table.get(&key).and_then(|v| v.as_table()) { + let ReflectMut::Struct(strct) = field_mut.reflect_mut() else { + warn!("Preferences: Expected Struct"); + continue; + }; + load_struct(registry, strct, table); + } + } + TypeInfo::Enum(_) => {} + _ => { + warn!( + "Preferences: Unsupported type: {:?}", + field_mut.get_represented_type_info() + ); + } + } + } +} + +fn load_value(field: &mut dyn PartialReflect, value_info: &ValueInfo, value: &toml::Value) { + match value { + toml::Value::String(str_val) => { + if value_info.is::() { + field.apply(str_val); + } else { + warn!("Preferences: Expected {:?}, got String", value_info); + } + } + toml::Value::Integer(int_val) => { + if value_info.is::() { + field.apply(&(*int_val as f64)); + } else if value_info.is::() { + field.apply(&((*int_val).clamp(f32::MIN as i64, f32::MAX as i64) as f32)); + } else if value_info.is::() { + field.apply(int_val); + } else if value_info.is::() { + field.apply(&((*int_val).clamp(i32::MIN as i64, i32::MAX as i64) as i32)); + } else if value_info.is::() { + field.apply(&((*int_val).clamp(i16::MIN as i64, i16::MAX as i64) as i16)); + } else if value_info.is::() { + field.apply(&((*int_val).clamp(i8::MIN as i64, i8::MAX as i64) as i8)); + } else if value_info.is::() { + field.apply(&((*int_val).max(0) as u64)); + } else if value_info.is::() { + field.apply(&((*int_val).max(0) as u32)); + } else if value_info.is::() { + field.apply(&((*int_val).max(0) as u16)); + } else if value_info.is::() { + field.apply(&((*int_val).max(0) as u8)); + } else { + warn!("Preferences: Expected {:?}, got Integer", value_info); + } + } + toml::Value::Float(float_val) => { + if value_info.is::() { + field.apply(float_val); + } else if value_info.is::() { + field.apply(&(float_val.clamp(f32::MIN as f64, f32::MAX as f64) as f32)); + } else { + warn!("Preferences: Expected {:?}, got Float", value_info); + } + } + toml::Value::Boolean(bool_val) => { + if value_info.is::() { + field.apply(bool_val); + } else { + warn!("Preferences: Expected {:?}, got Bool", value_info); + } + } + _ => { + warn!("Preferences: Unsupported type: {:?}", value); + } + } +} diff --git a/crates/bevy_editor_settings/src/file_system/mod.rs b/crates/bevy_editor_settings/src/file_system/mod.rs new file mode 100644 index 00000000..d9d0a4da --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/mod.rs @@ -0,0 +1,39 @@ +use bevy::log::{error, warn}; + +use crate::{GlobalSettingsPath, SettingsType}; + +pub mod load; + +const SETTINGS_BASE_DIR: &str = "bevy_editor"; + +pub fn global_settings_path() -> Option { + let path = directories::BaseDirs::new()?; + let config_dir = path.config_dir(); + let path = config_dir.join(SETTINGS_BASE_DIR); + + if !path.exists() { + if let Err(e) = std::fs::create_dir_all(&path) { + error!("Failed to create global settings directory: {}", e); + return None; + } + } + Some(path) +} + +pub fn load_settings(app: &mut bevy::app::App) { + if app.world().get_resource::().is_some() { + load_global_settings(app); + } +} + +pub fn load_global_settings(app: &mut bevy::app::App) { + let path = &app.world().get_resource::().unwrap().0; + let Ok(file) = load::load_toml_file(path.join("global.toml")) else { + warn!("Failed to load global settings"); + return; + }; + + load::load_preferences(app.world_mut(), file, SettingsType::Global); + +} + diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index f395c495..5de2491c 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -2,8 +2,36 @@ use bevy::prelude::*; +mod file_system; pub mod modals; -mod persistent; + +/// Annotation for a type to show which type of settings it belongs to. +#[derive(Debug, Clone, PartialEq, Eq, Reflect)] +pub enum SettingsType { + /// These are settings that are saved in the os user's configuration directory. \ + /// These settings are global to the user and are not tied to a specific project. \ + /// Settings are along the lines of hotkeys etc. + Global, + /// Workspace preferences use the global preferences by default. End users can modify them, customizing their layout, theming and hotkeys. \ + /// The file is created when the user applies changes to their workspace preferences within the editor. \ + /// Workspace preferences can be shared between multiple projects and are not isolated to project folders.* + Workspace, + /// Project preference overrides are empty and stored within the project settings. \ + /// When a project overrides a global/workspace preference, it is no longer possible to change them. \ + /// In order to modify the preference, users must modify the project settings instead. + /// There are two states that overrides can be in: + /// - Inheriting - No override is set. Users can freely change the preference. Users can use what they have set within the global/workspace preferences. + /// - Modified - When an override has been set, users can no longer change the preference without modifying the project settings. You can switch between inheriting and modified at any time without consequence. + Project, +} + +#[derive(Debug, Clone, Reflect)] +/// Annotation for a type to add tags to the settings. these tags can be used to filter settings in the editor. +pub struct SettingsTags(pub Vec<&'static str>); + +#[derive(Resource)] +/// Store the path for the global preferences directory. +pub struct GlobalSettingsPath(pub std::path::PathBuf); /// A Bevy plugin for editor settings. /// This plugin loads the workspace settings, user settings, and project settings. @@ -14,64 +42,25 @@ pub struct EditorSettingsPlugin; /// This includes workspace settings, user settings, and project settings. pub struct Settings { /// Settings for the workspace - pub workspace_settings: Option, + pub workspace_settings: modals::workspace::WorkspaceSettings, /// Settings for the user - pub user_settings: Option, - /// default project settings used when no workspace or user settings are present for a given setting - pub project_settings: modals::project::ProjectSettings, -} - -impl Settings { - /// Get the project settings. - /// - /// TODO this needs to do some kind of merging of settings - /// the order of precedence should be from highest to lowest: - /// 1. user settings - /// 2. workspace settings - /// 3. default project settings - pub fn project_settings(&self) -> &modals::project::ProjectSettings { - self.user_settings - .as_ref() - .map(|settings| &settings.project_settings) - .or_else(|| { - self.workspace_settings - .as_ref() - .map(|settings| &settings.editor_settings) - }) - .unwrap_or(&self.project_settings) - } - - /// Save the user settings. - pub fn save_user_settings(&self) -> Result<(), persistent::PersistentError> { - if let Some(user_settings) = &self.user_settings { - persistent::save_user_settings(user_settings)?; - Ok(()) - } else { - warn!("No user settings to save."); - Ok(()) - } - } + pub user_settings: modals::user::UserSettings, } impl Plugin for EditorSettingsPlugin { fn build(&self, app: &mut App) { - let workspace_settings = persistent::load_workspace_settings() - .inspect_err(|error| { - error!("Error loading workspace settings: {:?}", error); - }) - .ok(); - let user_settings = persistent::load_user_settings() - .inspect_err(|error| { - error!("Error loading user settings: {:?}", error); - }) - .ok(); - - let project_settings = modals::project::ProjectSettings::default(); + match file_system::global_settings_path() { + Some(path) => { + debug!("Global settings path: {:?}", path); + app.insert_resource(GlobalSettingsPath(path)); + }, + None => { + warn!("Failed to load global settings"); + } + }; + } - app.insert_resource(Settings { - workspace_settings, - user_settings, - project_settings, - }); + fn finish(&self, app: &mut App) { + file_system::load_settings(app); } } diff --git a/crates/bevy_editor_settings/src/modals/editor.rs b/crates/bevy_editor_settings/src/modals/editor.rs deleted file mode 100644 index 380c886a..00000000 --- a/crates/bevy_editor_settings/src/modals/editor.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! Editor settings - -use bevy::reflect::Reflect; -use serde::{Deserialize, Serialize}; - -use super::project::ProjectSettings; - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Reflect)] -#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] -/// Settings for the editor -pub struct EditorSettings { - /// current project settings - pub project_settings: ProjectSettings, -} diff --git a/crates/bevy_editor_settings/src/modals/mod.rs b/crates/bevy_editor_settings/src/modals/mod.rs index 63e05ebe..e9d27ece 100644 --- a/crates/bevy_editor_settings/src/modals/mod.rs +++ b/crates/bevy_editor_settings/src/modals/mod.rs @@ -1,6 +1,4 @@ //! Modals for the editor settings. -pub mod editor; -pub mod project; pub mod user; pub mod workspace; diff --git a/crates/bevy_editor_settings/src/modals/project.rs b/crates/bevy_editor_settings/src/modals/project.rs deleted file mode 100644 index 435be7bd..00000000 --- a/crates/bevy_editor_settings/src/modals/project.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Project settings for the editor - -use bevy::reflect::Reflect; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Reflect)] -#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] -/// Settings for the editor -#[serde(default)] -pub struct ProjectSettings { - /// The name of the project - name: String, -} - -impl Default for ProjectSettings { - fn default() -> Self { - Self { - name: "My Project".to_string(), - } - } -} diff --git a/crates/bevy_editor_settings/src/modals/user.rs b/crates/bevy_editor_settings/src/modals/user.rs index bf290523..c714dc50 100644 --- a/crates/bevy_editor_settings/src/modals/user.rs +++ b/crates/bevy_editor_settings/src/modals/user.rs @@ -1,14 +1,7 @@ //! this is for the user to override workspace settings use bevy::reflect::Reflect; -use serde::{Deserialize, Serialize}; -use super::project::ProjectSettings; - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Reflect)] -#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect)] /// Settings for the user -pub struct UserSettings { - /// project settings for the user - pub project_settings: ProjectSettings, -} +pub struct UserSettings {} diff --git a/crates/bevy_editor_settings/src/modals/workspace.rs b/crates/bevy_editor_settings/src/modals/workspace.rs index 397c409a..9161390f 100644 --- a/crates/bevy_editor_settings/src/modals/workspace.rs +++ b/crates/bevy_editor_settings/src/modals/workspace.rs @@ -1,24 +1,18 @@ //! Workspace settings use bevy::reflect::Reflect; -use serde::{Deserialize, Serialize}; -use super::project::ProjectSettings; - -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Reflect)] -#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect)] /// Settings for the entire workspace /// This should be in the root of your project pub struct WorkspaceSettings { /// Settings for the editor per workspace - pub editor_settings: ProjectSettings, + pub editor: String, /// Settings for building the project pub build: Build, } -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Reflect)] -#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] -#[serde(default)] +#[derive(Debug, Clone, PartialEq, Eq, Reflect)] /// Settings for building the project pub struct Build { /// The Command for building the project in debug mode diff --git a/crates/bevy_editor_settings/src/persistent.rs b/crates/bevy_editor_settings/src/persistent.rs deleted file mode 100644 index 60894f32..00000000 --- a/crates/bevy_editor_settings/src/persistent.rs +++ /dev/null @@ -1,60 +0,0 @@ -/// Load a type implementing `serde::Deserialize` from a TOML file. -pub fn load(path: impl AsRef) -> Result -where - T: serde::de::DeserializeOwned, -{ - let path = path.as_ref(); - let file = std::fs::read_to_string(path).unwrap(); - Ok(toml::from_str(&file)?) -} - -#[inline] -/// TODO: when the editor is an external application this should be moved to the user's configuration directory -fn user_settings_path() -> Result { - Ok(std::env::var("CARGO_MANIFEST_DIR") - .map(std::path::PathBuf::from) - .map_err(|_| PersistentError::WorkspaceConfigDirs)? - .join("user.toml")) -} - -/// Save the user settings to the default location. -pub fn save_user_settings( - settings: &crate::modals::user::UserSettings, -) -> Result<(), PersistentError> { - let path = user_settings_path()?; - let toml_string = toml::to_string(settings)?; - - std::fs::write(path, toml_string)?; - - Ok(()) -} - -/// Load the user settings from the default location. -pub fn load_user_settings() -> Result { - let path = user_settings_path()?; - - load(path) -} - -/// Load the workspace settings from the default location. -pub fn load_workspace_settings( -) -> Result { - let path = std::env::var("CARGO_MANIFEST_DIR") - .map(std::path::PathBuf::from) - .map_err(|_| PersistentError::WorkspaceConfigDirs)?; - - load(path.join("Bevy.toml")) -} - -/// Errors that can occur when loading a TOML file. -#[derive(Debug, thiserror::Error)] -pub enum PersistentError { - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - #[error("TOML deserialization error: {0}")] - TomlDe(#[from] toml::de::Error), - #[error("TOML serialization error: {0}")] - TomlSer(#[from] toml::ser::Error), - #[error("Error reading CARGO_MANIFEST_DIR required for workspace settings")] - WorkspaceConfigDirs, -} From 75e16e0c46e00086b6baf7129f5c751004b44c76 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Thu, 10 Oct 2024 19:06:47 +1300 Subject: [PATCH 02/39] kinda working --- crates/bevy_editor_settings/Bevy.toml | 3 ++ crates/bevy_editor_settings/Cargo.toml | 1 + .../src/file_system/load.rs | 14 ++++---- .../src/file_system/mod.rs | 22 +++++++++--- crates/bevy_editor_settings/src/lib.rs | 34 ++++++++++++++++++- 5 files changed, 63 insertions(+), 11 deletions(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index e69de29b..f9d170f0 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -0,0 +1,3 @@ + +[basic_settings] +name = "bevy_editor_settings" \ No newline at end of file diff --git a/crates/bevy_editor_settings/Cargo.toml b/crates/bevy_editor_settings/Cargo.toml index b4b11542..1ef05722 100644 --- a/crates/bevy_editor_settings/Cargo.toml +++ b/crates/bevy_editor_settings/Cargo.toml @@ -9,6 +9,7 @@ bevy.workspace = true thiserror.workspace = true toml = "0.8.19" directories = "5.0.1" +heck = "0.5.0" [lints] workspace = true diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index 01f45fd8..6d76059b 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -8,6 +8,7 @@ use bevy::{ }, scene::ron::{de, value}, }; +use heck::ToSnakeCase; use crate::{SettingsTags, SettingsType}; @@ -61,7 +62,12 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se else { panic!("Expected Struct"); }; - load_struct(®istry, strct, &table); + + let name = strct.reflect_type_ident().unwrap().to_snake_case(); + + if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { + load_struct(®istry, strct, table); + } } } @@ -73,11 +79,7 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se } } -fn load_struct( - registry: &AppTypeRegistry, - strct: &mut dyn Struct, - table: &toml::Table, -) { +fn load_struct(registry: &AppTypeRegistry, strct: &mut dyn Struct, table: &toml::Table) { for i in 0..strct.field_len() { let key = strct.name_at(i).unwrap().to_string(); let field_mut = strct.field_at_mut(i).unwrap(); diff --git a/crates/bevy_editor_settings/src/file_system/mod.rs b/crates/bevy_editor_settings/src/file_system/mod.rs index d9d0a4da..088b9ba2 100644 --- a/crates/bevy_editor_settings/src/file_system/mod.rs +++ b/crates/bevy_editor_settings/src/file_system/mod.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use bevy::log::{error, warn}; use crate::{GlobalSettingsPath, SettingsType}; @@ -22,18 +24,30 @@ pub fn global_settings_path() -> Option { pub fn load_settings(app: &mut bevy::app::App) { if app.world().get_resource::().is_some() { - load_global_settings(app); + load_global_settings(app.world_mut()); } + load_project_settings(app.world_mut()); } -pub fn load_global_settings(app: &mut bevy::app::App) { - let path = &app.world().get_resource::().unwrap().0; +pub fn load_project_settings(world: &mut bevy::prelude::World) { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let Ok(file) = load::load_toml_file(path.join("Bevy.toml")) else { + warn!("Failed to load project settings"); + return; + }; + + load::load_preferences(world, file, SettingsType::Project); +} + +pub fn load_global_settings(world: &mut bevy::prelude::World) { + let path = &world.get_resource::().unwrap().0; let Ok(file) = load::load_toml_file(path.join("global.toml")) else { warn!("Failed to load global settings"); return; }; - load::load_preferences(app.world_mut(), file, SettingsType::Global); + load::load_preferences(world, file, SettingsType::Global); } + diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index 5de2491c..69de41cf 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -53,7 +53,7 @@ impl Plugin for EditorSettingsPlugin { Some(path) => { debug!("Global settings path: {:?}", path); app.insert_resource(GlobalSettingsPath(path)); - }, + } None => { warn!("Failed to load global settings"); } @@ -64,3 +64,35 @@ impl Plugin for EditorSettingsPlugin { file_system::load_settings(app); } } + +#[cfg(test)] +mod tests { + + use super::*; + + #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] + #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] + struct BasicSettings { + pub name: String, + pub age: u32, + } + + #[test] + fn loading() { + let mut app = App::new(); + + app.register_type::(); + + app.insert_resource(BasicSettings { + name: "John".to_string(), + age: 25, + }); + + file_system::load_project_settings(app.world_mut()); + + let settings = app.world().get_resource::().unwrap(); + + assert_eq!(settings.name, "bevy_editor_settings"); + assert_eq!(settings.age, 25); + } +} From 7e70f5207ce92a48660662ce6b5945383268e5bf Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Fri, 11 Oct 2024 03:21:52 +1300 Subject: [PATCH 03/39] start on list --- crates/bevy_editor_settings/Bevy.toml | 9 ++- .../src/file_system/load.rs | 28 +++++++++- crates/bevy_editor_settings/src/lib.rs | 55 ++++++++++++++++++- .../bevy_editor_settings/src/local_prefs.rs | 30 ++++++++++ 4 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 crates/bevy_editor_settings/src/local_prefs.rs diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index f9d170f0..519a25a4 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -1,3 +1,10 @@ [basic_settings] -name = "bevy_editor_settings" \ No newline at end of file +name = "bevy_editor_settings" + + +[list_testing] +list = ["three", "four"] + +[list_testing_append] +list = ["three", "four"] \ No newline at end of file diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index 6d76059b..7b921306 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -3,8 +3,8 @@ use std::any::TypeId; use bevy::{ prelude::*, reflect::{ - DynamicEnum, DynamicTuple, DynamicVariant, Enum, EnumInfo, ReflectFromPtr, ReflectMut, - TypeInfo, ValueInfo, VariantInfo, + Array, ArrayInfo, DynamicEnum, DynamicTuple, DynamicVariant, Enum, EnumInfo, List, + ListInfo, ReflectFromPtr, ReflectMut, TypeInfo, ValueInfo, VariantInfo, }, scene::ron::{de, value}, }; @@ -98,7 +98,24 @@ fn load_struct(registry: &AppTypeRegistry, strct: &mut dyn Struct, table: &toml: load_struct(registry, strct, table); } } - TypeInfo::Enum(_) => {} + TypeInfo::List(list_info) => { + if let Some(table) = table.get(&key).and_then(|v| v.as_array()) { + let ReflectMut::List(list) = field_mut.reflect_mut() else { + warn!("Preferences: Expected List"); + continue; + }; + load_list(list, list_info, table); + } + } + TypeInfo::Array(array_info) => { + if let Some(table) = table.get(&key).and_then(|v| v.as_array()) { + let ReflectMut::Array(array) = field_mut.reflect_mut() else { + warn!("Preferences: Expected Array"); + continue; + }; + load_array(array, array_info, table); + } + } _ => { warn!( "Preferences: Unsupported type: {:?}", @@ -109,6 +126,11 @@ fn load_struct(registry: &AppTypeRegistry, strct: &mut dyn Struct, table: &toml: } } +fn load_list(list: &mut dyn List, list_info: &ListInfo, table: &toml::value::Array) {} + +fn load_array(array: &mut dyn Array, array_info: &ArrayInfo, table: &toml::value::Array) { +} + fn load_value(field: &mut dyn PartialReflect, value_info: &ValueInfo, value: &toml::Value) { match value { toml::Value::String(str_val) => { diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index 69de41cf..a95ac864 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -4,6 +4,7 @@ use bevy::prelude::*; mod file_system; pub mod modals; +mod local_prefs; /// Annotation for a type to show which type of settings it belongs to. #[derive(Debug, Clone, PartialEq, Eq, Reflect)] @@ -25,6 +26,17 @@ pub enum SettingsType { Project, } +#[derive(Debug, Clone, Reflect, Default)] +/// Annotation for a type to show how to merge lists when loading settings. +/// if not set, the default is to replace the existing list. +pub enum ListLoad { + #[default] + /// When Mergeing the list, the new list will replace the existing list. + Replace, + /// When Mergeing the list, the new list will be appended to the existing list. + Append, +} + #[derive(Debug, Clone, Reflect)] /// Annotation for a type to add tags to the settings. these tags can be used to filter settings in the editor. pub struct SettingsTags(pub Vec<&'static str>); @@ -78,7 +90,7 @@ mod tests { } #[test] - fn loading() { + fn basic_test() { let mut app = App::new(); app.register_type::(); @@ -95,4 +107,45 @@ mod tests { assert_eq!(settings.name, "bevy_editor_settings"); assert_eq!(settings.age, 25); } + + + #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] + #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] + struct ListTesing { + pub list: Vec, + } + + #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] + #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] + struct ListTesingAppend { + #[reflect(@ListLoad::Append)] + pub list: Vec, + } + + #[test] + fn test_lists() { + let mut app = App::new(); + + app.register_type::(); + app.register_type::(); + + app.insert_resource(ListTesing { + list: vec!["one".to_string(), "two".to_string()], + }); + + app.insert_resource(ListTesingAppend { + list: vec!["one".to_string(), "two".to_string()], + }); + + file_system::load_project_settings(app.world_mut()); + + let settings = app.world().get_resource::().unwrap(); + + assert_eq!(settings.list, vec!["three".to_string(), "four".to_string()]); + + let settings = app.world().get_resource::().unwrap(); + + assert_eq!(settings.list, vec!["one".to_string(), "two".to_string(), "three".to_string(), "four".to_string()]); + } + } diff --git a/crates/bevy_editor_settings/src/local_prefs.rs b/crates/bevy_editor_settings/src/local_prefs.rs new file mode 100644 index 00000000..f23d8c3d --- /dev/null +++ b/crates/bevy_editor_settings/src/local_prefs.rs @@ -0,0 +1,30 @@ +use bevy::{prelude::Resource, reflect::Reflect}; + +use crate::{SettingsTags, SettingsType}; + + + +#[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] +#[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] +/// Settings for building the project +pub struct Build { + /// The Command for building the project in debug mode + debug: String, + /// The Command for building the project in release mode + release: String, + /// The Command for running the project in debug mode + run_debug: String, + /// The Command for running the project in release mode + run_release: String, +} + +impl Default for Build { + fn default() -> Self { + Self { + debug: "cargo build".to_string(), + release: "cargo build --release".to_string(), + run_debug: "cargo run".to_string(), + run_release: "cargo run --release".to_string(), + } + } +} From 9659404d7681730f45a2829d04c7fd6d2ae29d55 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Fri, 11 Oct 2024 04:02:30 +1300 Subject: [PATCH 04/39] working vec string --- .../src/file_system/load.rs | 55 ++++++++++++++++--- crates/bevy_editor_settings/src/lib.rs | 16 +++--- 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index 7b921306..7050c277 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -3,14 +3,15 @@ use std::any::TypeId; use bevy::{ prelude::*, reflect::{ - Array, ArrayInfo, DynamicEnum, DynamicTuple, DynamicVariant, Enum, EnumInfo, List, - ListInfo, ReflectFromPtr, ReflectMut, TypeInfo, ValueInfo, VariantInfo, + attributes::CustomAttributes, Array, ArrayInfo, DynamicEnum, DynamicTuple, DynamicVariant, + Enum, EnumInfo, List, ListInfo, ReflectFromPtr, ReflectMut, StructInfo, TypeInfo, + ValueInfo, VariantInfo, }, scene::ron::{de, value}, }; use heck::ToSnakeCase; -use crate::{SettingsTags, SettingsType}; +use crate::{ListLoad, SettingsTags, SettingsType}; /// Load a toml file from the given path pub fn load_toml_file(path: impl AsRef) -> Result { @@ -66,7 +67,7 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se let name = strct.reflect_type_ident().unwrap().to_snake_case(); if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { - load_struct(®istry, strct, table); + load_struct(strct, struct_info, table); } } } @@ -79,10 +80,11 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se } } -fn load_struct(registry: &AppTypeRegistry, strct: &mut dyn Struct, table: &toml::Table) { +fn load_struct(strct: &mut dyn Struct, struct_info: &StructInfo, table: &toml::Table) { for i in 0..strct.field_len() { let key = strct.name_at(i).unwrap().to_string(); let field_mut = strct.field_at_mut(i).unwrap(); + let field_attrs = struct_info.field_at(i).unwrap().custom_attributes(); match field_mut.get_represented_type_info().unwrap() { TypeInfo::Value(value_info) => { if let Some(value) = table.get(&key) { @@ -95,7 +97,7 @@ fn load_struct(registry: &AppTypeRegistry, strct: &mut dyn Struct, table: &toml: warn!("Preferences: Expected Struct"); continue; }; - load_struct(registry, strct, table); + load_struct(strct, struct_info, table); } } TypeInfo::List(list_info) => { @@ -104,7 +106,7 @@ fn load_struct(registry: &AppTypeRegistry, strct: &mut dyn Struct, table: &toml: warn!("Preferences: Expected List"); continue; }; - load_list(list, list_info, table); + load_list(list, list_info, table, field_attrs); } } TypeInfo::Array(array_info) => { @@ -126,9 +128,46 @@ fn load_struct(registry: &AppTypeRegistry, strct: &mut dyn Struct, table: &toml: } } -fn load_list(list: &mut dyn List, list_info: &ListInfo, table: &toml::value::Array) {} +fn load_list( + list: &mut dyn List, + list_info: &ListInfo, + array: &toml::value::Array, + attrs: &CustomAttributes, +) { + let default = ListLoad::default(); + let merge_strategy = attrs.get::().unwrap_or(&default); + + if list_info + .item_info() + .is_some_and(|info| info.is::()) + && array.iter().all(|v| v.is_str()) + { + let items = array + .iter() + .map(|v| v.as_str().unwrap().to_string()) + .collect::>(); + match merge_strategy { + ListLoad::Replace => { + while list.len() > 0 { + list.remove(list.len() - 1); + } + for item in items { + list.push(Box::new(item)); + } + } + ListLoad::Append => { + for item in items { + list.push(Box::new(item)); + } + } + } + } else { + warn!("Preferences: Unsupported list type"); + } +} fn load_array(array: &mut dyn Array, array_info: &ArrayInfo, table: &toml::value::Array) { + warn!("Preferences: Arrays are not supported yet"); } fn load_value(field: &mut dyn PartialReflect, value_info: &ValueInfo, value: &toml::Value) { diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index a95ac864..a31ceda5 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -111,13 +111,13 @@ mod tests { #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] - struct ListTesing { + struct ListTesting { pub list: Vec, } #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] - struct ListTesingAppend { + struct ListTestingAppend { #[reflect(@ListLoad::Append)] pub list: Vec, } @@ -126,24 +126,24 @@ mod tests { fn test_lists() { let mut app = App::new(); - app.register_type::(); - app.register_type::(); + app.register_type::(); + app.register_type::(); - app.insert_resource(ListTesing { + app.insert_resource(ListTesting { list: vec!["one".to_string(), "two".to_string()], }); - app.insert_resource(ListTesingAppend { + app.insert_resource(ListTestingAppend { list: vec!["one".to_string(), "two".to_string()], }); file_system::load_project_settings(app.world_mut()); - let settings = app.world().get_resource::().unwrap(); + let settings = app.world().get_resource::().unwrap(); assert_eq!(settings.list, vec!["three".to_string(), "four".to_string()]); - let settings = app.world().get_resource::().unwrap(); + let settings = app.world().get_resource::().unwrap(); assert_eq!(settings.list, vec!["one".to_string(), "two".to_string(), "three".to_string(), "four".to_string()]); } From 0ea5303c5fcf21c20b6ec9c6406b641a66a2f65b Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 13 Oct 2024 03:46:28 +1300 Subject: [PATCH 05/39] working string/number/bool arrays --- crates/bevy_editor_settings/Bevy.toml | 2 +- .../src/file_system/load.rs | 93 +++++++++++++++---- crates/bevy_editor_settings/src/lib.rs | 6 +- 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index 519a25a4..19627006 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -7,4 +7,4 @@ name = "bevy_editor_settings" list = ["three", "four"] [list_testing_append] -list = ["three", "four"] \ No newline at end of file +list = [3,4] \ No newline at end of file diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index 7050c277..dd3c2a09 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -137,32 +137,91 @@ fn load_list( let default = ListLoad::default(); let merge_strategy = attrs.get::().unwrap_or(&default); - if list_info - .item_info() - .is_some_and(|info| info.is::()) - && array.iter().all(|v| v.is_str()) - { - let items = array - .iter() - .map(|v| v.as_str().unwrap().to_string()) - .collect::>(); + if let Some(item_info) = list_info.item_info() { match merge_strategy { ListLoad::Replace => { while list.len() > 0 { list.remove(list.len() - 1); } - for item in items { - list.push(Box::new(item)); - } } ListLoad::Append => { - for item in items { - list.push(Box::new(item)); - } + // do nothing + } + } + for value in array.iter() { + load_list_value(list, list_info, value, item_info); + } + } +} + +fn load_list_value( + list: &mut dyn List, + list_info: &ListInfo, + value: &toml::Value, + value_info: &TypeInfo, +) { + match value { + toml::Value::String(str_val) => { + if value_info.is::() { + list.push(Box::new(str_val.clone())); + } else { + warn!("Preferences: Expected {:?}, got String", list_info); } } - } else { - warn!("Preferences: Unsupported list type"); + toml::Value::Integer(int_val) => { + if value_info.is::() { + list.push(Box::new(*int_val as f64)); + } else if value_info.is::() { + list.push(Box::new( + (*int_val).clamp(f32::MIN as i64, f32::MAX as i64) as f32 + )); + } else if value_info.is::() { + list.push(Box::new(*int_val)); + } else if value_info.is::() { + list.push(Box::new( + (*int_val).clamp(i32::MIN as i64, i32::MAX as i64) as i32 + )); + } else if value_info.is::() { + list.push(Box::new( + (*int_val).clamp(i16::MIN as i64, i16::MAX as i64) as i16 + )); + } else if value_info.is::() { + list.push(Box::new( + (*int_val).clamp(i8::MIN as i64, i8::MAX as i64) as i8 + )); + } else if value_info.is::() { + list.push(Box::new((*int_val).max(0) as u64)); + } else if value_info.is::() { + list.push(Box::new((*int_val).max(0) as u32)); + } else if value_info.is::() { + list.push(Box::new((*int_val).max(0) as u16)); + } else if value_info.is::() { + list.push(Box::new((*int_val).max(0) as u8)); + } else { + warn!("Preferences: Expected {:?}, got Integer", list_info); + } + } + toml::Value::Float(float_val) => { + if value_info.is::() { + list.push(Box::new(*float_val)); + } else if value_info.is::() { + list.push(Box::new( + float_val.clamp(f32::MIN as f64, f32::MAX as f64) as f32 + )); + } else { + warn!("Preferences: Expected {:?}, got Float", list_info); + } + } + toml::Value::Boolean(bool_val) => { + if value_info.is::() { + list.push(Box::new(*bool_val)); + } else { + warn!("Preferences: Expected {:?}, got Bool", list_info); + } + } + _ => { + warn!("Preferences: Unsupported type: {:?}", value); + } } } diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index a31ceda5..35a7a58e 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -119,7 +119,7 @@ mod tests { #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] struct ListTestingAppend { #[reflect(@ListLoad::Append)] - pub list: Vec, + pub list: Vec, } #[test] @@ -134,7 +134,7 @@ mod tests { }); app.insert_resource(ListTestingAppend { - list: vec!["one".to_string(), "two".to_string()], + list: vec![1, 2], }); file_system::load_project_settings(app.world_mut()); @@ -145,7 +145,7 @@ mod tests { let settings = app.world().get_resource::().unwrap(); - assert_eq!(settings.list, vec!["one".to_string(), "two".to_string(), "three".to_string(), "four".to_string()]); + assert_eq!(settings.list, vec![1, 2, 3, 4]); } } From 3f26299e95fab7e90a30903a22b7becb85e1c72e Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 20 Oct 2024 16:05:38 +1300 Subject: [PATCH 06/39] change list loading --- .../src/file_system/load.rs | 83 +++++++++++-------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index dd3c2a09..83f6a6d5 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -91,7 +91,7 @@ fn load_struct(strct: &mut dyn Struct, struct_info: &StructInfo, table: &toml::T load_value(field_mut, value_info, value) } } - TypeInfo::Struct(_) => { + TypeInfo::Struct(struct_info) => { if let Some(table) = table.get(&key).and_then(|v| v.as_table()) { let ReflectMut::Struct(strct) = field_mut.reflect_mut() else { warn!("Preferences: Expected Struct"); @@ -158,77 +158,92 @@ fn load_list_value( list: &mut dyn List, list_info: &ListInfo, value: &toml::Value, - value_info: &TypeInfo, + item_info: &TypeInfo, ) { + match item_info { + TypeInfo::Value(value_info) => { + let value = load_value_boxed(value_info, value); + if let Some(value) = value { + list.push(value); + } + } + _ => { + warn!("Preferences: Unsupported type: {:?}", item_info); + } + } +} + + + +fn load_array(array: &mut dyn Array, array_info: &ArrayInfo, table: &toml::value::Array) { + warn!("Preferences: Arrays are not supported yet"); +} + +fn load_value_boxed( + value_info: &ValueInfo, + value: &toml::Value, +) -> Option> { + match value { toml::Value::String(str_val) => { if value_info.is::() { - list.push(Box::new(str_val.clone())); + Some(Box::new(str_val.clone())) } else { - warn!("Preferences: Expected {:?}, got String", list_info); + warn!("Preferences: Expected {:?}, got String", value_info); + None } } toml::Value::Integer(int_val) => { if value_info.is::() { - list.push(Box::new(*int_val as f64)); + Some(Box::new(*int_val as f64)) } else if value_info.is::() { - list.push(Box::new( - (*int_val).clamp(f32::MIN as i64, f32::MAX as i64) as f32 - )); + Some(Box::new((*int_val).clamp(f32::MIN as i64, f32::MAX as i64) as f32)) } else if value_info.is::() { - list.push(Box::new(*int_val)); + Some(Box::new(*int_val)) } else if value_info.is::() { - list.push(Box::new( - (*int_val).clamp(i32::MIN as i64, i32::MAX as i64) as i32 - )); + Some(Box::new((*int_val).clamp(i32::MIN as i64, i32::MAX as i64) as i32)) } else if value_info.is::() { - list.push(Box::new( - (*int_val).clamp(i16::MIN as i64, i16::MAX as i64) as i16 - )); + Some(Box::new((*int_val).clamp(i16::MIN as i64, i16::MAX as i64) as i16)) } else if value_info.is::() { - list.push(Box::new( - (*int_val).clamp(i8::MIN as i64, i8::MAX as i64) as i8 - )); + Some(Box::new((*int_val).clamp(i8::MIN as i64, i8::MAX as i64) as i8)) } else if value_info.is::() { - list.push(Box::new((*int_val).max(0) as u64)); + Some(Box::new((*int_val).max(0) as u64)) } else if value_info.is::() { - list.push(Box::new((*int_val).max(0) as u32)); + Some(Box::new((*int_val).max(0) as u32)) } else if value_info.is::() { - list.push(Box::new((*int_val).max(0) as u16)); + Some(Box::new((*int_val).max(0) as u16)) } else if value_info.is::() { - list.push(Box::new((*int_val).max(0) as u8)); + Some(Box::new((*int_val).max(0) as u8)) } else { - warn!("Preferences: Expected {:?}, got Integer", list_info); + warn!("Preferences: Expected {:?}, got Integer", value_info); + None } } toml::Value::Float(float_val) => { if value_info.is::() { - list.push(Box::new(*float_val)); + Some(Box::new(*float_val)) } else if value_info.is::() { - list.push(Box::new( - float_val.clamp(f32::MIN as f64, f32::MAX as f64) as f32 - )); + Some(Box::new(float_val.clamp(f32::MIN as f64, f32::MAX as f64) as f32)) } else { - warn!("Preferences: Expected {:?}, got Float", list_info); + warn!("Preferences: Expected {:?}, got Float", value_info); + None } } toml::Value::Boolean(bool_val) => { if value_info.is::() { - list.push(Box::new(*bool_val)); + Some(Box::new(*bool_val)) } else { - warn!("Preferences: Expected {:?}, got Bool", list_info); + warn!("Preferences: Expected {:?}, got Bool", value_info); + None } } _ => { warn!("Preferences: Unsupported type: {:?}", value); + None } } } -fn load_array(array: &mut dyn Array, array_info: &ArrayInfo, table: &toml::value::Array) { - warn!("Preferences: Arrays are not supported yet"); -} - fn load_value(field: &mut dyn PartialReflect, value_info: &ValueInfo, value: &toml::Value) { match value { toml::Value::String(str_val) => { From e145146d6da188cb78172d9d403e1d8085d90664 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 20 Oct 2024 16:06:00 +1300 Subject: [PATCH 07/39] rename --- crates/bevy_editor_settings/src/file_system/load.rs | 10 +++++----- crates/bevy_editor_settings/src/lib.rs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index 83f6a6d5..904be016 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -11,7 +11,7 @@ use bevy::{ }; use heck::ToSnakeCase; -use crate::{ListLoad, SettingsTags, SettingsType}; +use crate::{MergeStrategy, SettingsTags, SettingsType}; /// Load a toml file from the given path pub fn load_toml_file(path: impl AsRef) -> Result { @@ -134,17 +134,17 @@ fn load_list( array: &toml::value::Array, attrs: &CustomAttributes, ) { - let default = ListLoad::default(); - let merge_strategy = attrs.get::().unwrap_or(&default); + let default = MergeStrategy::default(); + let merge_strategy = attrs.get::().unwrap_or(&default); if let Some(item_info) = list_info.item_info() { match merge_strategy { - ListLoad::Replace => { + MergeStrategy::Replace => { while list.len() > 0 { list.remove(list.len() - 1); } } - ListLoad::Append => { + MergeStrategy::Append => { // do nothing } } diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index 35a7a58e..a7a004cd 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -29,7 +29,7 @@ pub enum SettingsType { #[derive(Debug, Clone, Reflect, Default)] /// Annotation for a type to show how to merge lists when loading settings. /// if not set, the default is to replace the existing list. -pub enum ListLoad { +pub enum MergeStrategy { #[default] /// When Mergeing the list, the new list will replace the existing list. Replace, @@ -118,7 +118,7 @@ mod tests { #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] struct ListTestingAppend { - #[reflect(@ListLoad::Append)] + #[reflect(@MergeStrategy::Append)] pub list: Vec, } From 47bcf29ff334e7b39ae1af81f700347a1d84968c Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 20 Oct 2024 16:07:13 +1300 Subject: [PATCH 08/39] add todo --- crates/bevy_editor_settings/src/file_system/load.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index 904be016..917b5eb7 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -167,6 +167,7 @@ fn load_list_value( list.push(value); } } + // TODO support more then values in lists _ => { warn!("Preferences: Unsupported type: {:?}", item_info); } From 329ba5e8a583fb4bb61c283c547e59a6735fbe93 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 20 Oct 2024 16:47:45 +1300 Subject: [PATCH 09/39] working unit enums --- crates/bevy_editor_settings/Bevy.toml | 5 +- .../src/file_system/load.rs | 77 ++++++++++++++++--- crates/bevy_editor_settings/src/lib.rs | 24 ++++++ 3 files changed, 95 insertions(+), 11 deletions(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index 19627006..15dd49d6 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -7,4 +7,7 @@ name = "bevy_editor_settings" list = ["three", "four"] [list_testing_append] -list = [3,4] \ No newline at end of file +list = [3,4] + +[enum_testing] +variant = "Two" \ No newline at end of file diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index 917b5eb7..6d874271 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -71,9 +71,31 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se } } } + TypeInfo::Enum(enum_info) => { + let s_type = enum_info.custom_attributes().get::(); + if let Some(s_type) = s_type { + check_settings_type!(settings_type, *s_type); + let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); + let reflect_from_ptr = type_reg.data::().unwrap(); + // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for + #[allow(unsafe_code)] + let ReflectMut::Enum(enm) = + unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() + else { + panic!("Expected Struct"); + }; + + let name = enm.reflect_type_ident().unwrap().to_snake_case(); + + if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { + load_enum(enm, enum_info, table); + } + } + } - // Other types cannot be preferences since they don't have attributes. - _ => {} + _ => { + warn!("Preferences: Unsupported type: {:?}", type_reg.type_info()); + } } } // println!("Saving preferences for {:?}", res.name()); @@ -118,6 +140,15 @@ fn load_struct(strct: &mut dyn Struct, struct_info: &StructInfo, table: &toml::T load_array(array, array_info, table); } } + TypeInfo::Enum(enum_info) => { + let ReflectMut::Enum(enm) = field_mut.reflect_mut() else { + warn!("Preferences: Expected Enum"); + continue; + }; + if let Some(table) = table.get(&key).and_then(|v| v.as_table()) { + load_enum(enm, enum_info, table); + } + } _ => { warn!( "Preferences: Unsupported type: {:?}", @@ -128,6 +159,25 @@ fn load_struct(strct: &mut dyn Struct, struct_info: &StructInfo, table: &toml::T } } +fn load_enum(enm: &mut dyn Enum, enum_info: &EnumInfo, table: &toml::Table) { + if let Some(toml_value) = table.get("variant") { + match toml_value { + toml::Value::String(str_val) => { + if let Some(VariantInfo::Unit(variant)) = enum_info.variant(str_val) { + let dyn_enum = DynamicEnum::new(variant.name(), DynamicVariant::Unit); + enm.apply(&dyn_enum); + } else { + warn!("Preferences: Unknown variant: {}", str_val); + } + } + toml::Value::Table(table) => {} + _ => { + warn!("Preferences: Unsupported type: {:?}", toml_value); + } + } + } +} + fn load_list( list: &mut dyn List, list_info: &ListInfo, @@ -174,8 +224,6 @@ fn load_list_value( } } - - fn load_array(array: &mut dyn Array, array_info: &ArrayInfo, table: &toml::value::Array) { warn!("Preferences: Arrays are not supported yet"); } @@ -184,7 +232,6 @@ fn load_value_boxed( value_info: &ValueInfo, value: &toml::Value, ) -> Option> { - match value { toml::Value::String(str_val) => { if value_info.is::() { @@ -198,15 +245,23 @@ fn load_value_boxed( if value_info.is::() { Some(Box::new(*int_val as f64)) } else if value_info.is::() { - Some(Box::new((*int_val).clamp(f32::MIN as i64, f32::MAX as i64) as f32)) + Some(Box::new( + (*int_val).clamp(f32::MIN as i64, f32::MAX as i64) as f32 + )) } else if value_info.is::() { Some(Box::new(*int_val)) } else if value_info.is::() { - Some(Box::new((*int_val).clamp(i32::MIN as i64, i32::MAX as i64) as i32)) + Some(Box::new( + (*int_val).clamp(i32::MIN as i64, i32::MAX as i64) as i32 + )) } else if value_info.is::() { - Some(Box::new((*int_val).clamp(i16::MIN as i64, i16::MAX as i64) as i16)) + Some(Box::new( + (*int_val).clamp(i16::MIN as i64, i16::MAX as i64) as i16 + )) } else if value_info.is::() { - Some(Box::new((*int_val).clamp(i8::MIN as i64, i8::MAX as i64) as i8)) + Some(Box::new( + (*int_val).clamp(i8::MIN as i64, i8::MAX as i64) as i8 + )) } else if value_info.is::() { Some(Box::new((*int_val).max(0) as u64)) } else if value_info.is::() { @@ -224,7 +279,9 @@ fn load_value_boxed( if value_info.is::() { Some(Box::new(*float_val)) } else if value_info.is::() { - Some(Box::new(float_val.clamp(f32::MIN as f64, f32::MAX as f64) as f32)) + Some(Box::new( + float_val.clamp(f32::MIN as f64, f32::MAX as f64) as f32 + )) } else { warn!("Preferences: Expected {:?}, got Float", value_info); None diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index a7a004cd..7d0930fe 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -148,4 +148,28 @@ mod tests { assert_eq!(settings.list, vec![1, 2, 3, 4]); } + + #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] + #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] + enum EnumTesting { + One, + Two, + Three, + } + + #[test] + fn test_enum() { + let mut app = App::new(); + + app.register_type::(); + + app.insert_resource(EnumTesting::One); + + file_system::load_project_settings(app.world_mut()); + + let settings = app.world().get_resource::().unwrap(); + + assert_eq!(*settings, EnumTesting::Two); + } + } From 2410082035c8dc7d7474ffba89debcf840fbb61d Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 20 Oct 2024 16:51:26 +1300 Subject: [PATCH 10/39] add a struct with enum varient test --- crates/bevy_editor_settings/Bevy.toml | 10 +++++++++- crates/bevy_editor_settings/src/lib.rs | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index 15dd49d6..b520ab66 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -1,13 +1,21 @@ +# basic struct [basic_settings] name = "bevy_editor_settings" +# list with replace [list_testing] list = ["three", "four"] +# list with append [list_testing_append] list = [3,4] +# top level enum [enum_testing] -variant = "Two" \ No newline at end of file +variant = "Two" + +# enum in a struct +[enum_settings] +setting = { variant = "Three" } \ No newline at end of file diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index 7d0930fe..3e4bcf0f 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -157,19 +157,35 @@ mod tests { Three, } + #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] + #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] + struct EnumSettings { + pub setting: EnumTesting, + } + #[test] fn test_enum() { let mut app = App::new(); app.register_type::(); + app.register_type::(); app.insert_resource(EnumTesting::One); + app.insert_resource(EnumSettings { + setting: EnumTesting::Two, + }); file_system::load_project_settings(app.world_mut()); let settings = app.world().get_resource::().unwrap(); assert_eq!(*settings, EnumTesting::Two); + + let settings = app.world().get_resource::().unwrap(); + + assert_eq!(*settings, EnumSettings { + setting: EnumTesting::Three, + }); } } From 86951c606ae9a38657ec099e4abac2092b949550 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 20 Oct 2024 16:52:08 +1300 Subject: [PATCH 11/39] add more comments to testing file --- crates/bevy_editor_settings/Bevy.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index b520ab66..842619ab 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -18,4 +18,7 @@ variant = "Two" # enum in a struct [enum_settings] -setting = { variant = "Three" } \ No newline at end of file +setting = { variant = "Three" } +# can also be written as +# [enum_settings.setting] +# variant = "Three" \ No newline at end of file From 4ee04b9d7a5ec297b840a1009ba173ffd7629e63 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 20 Oct 2024 17:17:24 +1300 Subject: [PATCH 12/39] working enum in list --- Cargo.toml | 2 + crates/bevy_editor_settings/Bevy.toml | 9 ++- crates/bevy_editor_settings/Cargo.toml | 4 ++ .../src/file_system/load.rs | 70 +++++++++---------- crates/bevy_editor_settings/src/lib.rs | 20 ++++++ 5 files changed, 65 insertions(+), 40 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d2fcd598..2b7c4fe5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,3 +28,5 @@ unused_qualifications = "warn" bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "9386bd0114c44c9f00a2e9c41db1225aaa78d159" } thiserror = "1" serde = { version = "1", features = ["derive"] } +tracing-test = "0.2.5" +tracing = "0.1.40" diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index 842619ab..4e5996b5 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -10,7 +10,7 @@ list = ["three", "four"] # list with append [list_testing_append] -list = [3,4] +list = [3, 4] # top level enum [enum_testing] @@ -18,7 +18,10 @@ variant = "Two" # enum in a struct [enum_settings] -setting = { variant = "Three" } +setting = "Three" # can also be written as # [enum_settings.setting] -# variant = "Three" \ No newline at end of file +# variant = "Three" + +[enum_settings_list] +settings = ["Three"] \ No newline at end of file diff --git a/crates/bevy_editor_settings/Cargo.toml b/crates/bevy_editor_settings/Cargo.toml index 1ef05722..78a0230f 100644 --- a/crates/bevy_editor_settings/Cargo.toml +++ b/crates/bevy_editor_settings/Cargo.toml @@ -11,5 +11,9 @@ toml = "0.8.19" directories = "5.0.1" heck = "0.5.0" +[dev-dependencies] +tracing.workspace = true +tracing-test.workspace = true + [lints] workspace = true diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index 6d874271..4499695c 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -88,7 +88,9 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se let name = enm.reflect_type_ident().unwrap().to_snake_case(); if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { - load_enum(enm, enum_info, table); + if let Some(value) = table.get("variant") { + load_enum(enm, enum_info, value); + } } } } @@ -145,8 +147,8 @@ fn load_struct(strct: &mut dyn Struct, struct_info: &StructInfo, table: &toml::T warn!("Preferences: Expected Enum"); continue; }; - if let Some(table) = table.get(&key).and_then(|v| v.as_table()) { - load_enum(enm, enum_info, table); + if let Some(value) = table.get(&key) { + load_enum(enm, enum_info, value); } } _ => { @@ -159,22 +161,20 @@ fn load_struct(strct: &mut dyn Struct, struct_info: &StructInfo, table: &toml::T } } -fn load_enum(enm: &mut dyn Enum, enum_info: &EnumInfo, table: &toml::Table) { - if let Some(toml_value) = table.get("variant") { - match toml_value { - toml::Value::String(str_val) => { - if let Some(VariantInfo::Unit(variant)) = enum_info.variant(str_val) { - let dyn_enum = DynamicEnum::new(variant.name(), DynamicVariant::Unit); - enm.apply(&dyn_enum); - } else { - warn!("Preferences: Unknown variant: {}", str_val); - } - } - toml::Value::Table(table) => {} - _ => { - warn!("Preferences: Unsupported type: {:?}", toml_value); +fn load_enum(enm: &mut dyn Enum, enum_info: &EnumInfo, toml_value: &toml::Value) { + match toml_value { + toml::Value::String(str_val) => { + if let Some(VariantInfo::Unit(variant)) = enum_info.variant(str_val) { + let dyn_enum = DynamicEnum::new(variant.name(), DynamicVariant::Unit); + enm.apply(&dyn_enum); + } else { + warn!("Preferences: Unknown variant: {}", str_val); } } + toml::Value::Table(table) => {} + _ => { + warn!("Preferences: Unsupported type: {:?}", toml_value); + } } } @@ -199,28 +199,24 @@ fn load_list( } } for value in array.iter() { - load_list_value(list, list_info, value, item_info); - } - } -} - -fn load_list_value( - list: &mut dyn List, - list_info: &ListInfo, - value: &toml::Value, - item_info: &TypeInfo, -) { - match item_info { - TypeInfo::Value(value_info) => { - let value = load_value_boxed(value_info, value); - if let Some(value) = value { - list.push(value); + match item_info { + TypeInfo::Value(value_info) => { + let value = load_value_boxed(value_info, value); + if let Some(value) = value { + list.push(value); + } + } + TypeInfo::Enum(enum_info) => { + let mut enum_value = DynamicEnum::default(); + load_enum(&mut enum_value, enum_info, value); + list.push(Box::new(enum_value)); + } + // TODO support more then values in lists + _ => { + warn!("Preferences: Unsupported type: {:?}", item_info); + } } } - // TODO support more then values in lists - _ => { - warn!("Preferences: Unsupported type: {:?}", item_info); - } } } diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index 3e4bcf0f..b6df3709 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -81,6 +81,7 @@ impl Plugin for EditorSettingsPlugin { mod tests { use super::*; + use tracing_test::traced_test; #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] @@ -89,6 +90,7 @@ mod tests { pub age: u32, } + #[traced_test] #[test] fn basic_test() { let mut app = App::new(); @@ -122,6 +124,7 @@ mod tests { pub list: Vec, } + #[traced_test] #[test] fn test_lists() { let mut app = App::new(); @@ -163,17 +166,30 @@ mod tests { pub setting: EnumTesting, } + #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] + #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] + struct EnumSettingsList { + #[reflect(@MergeStrategy::Append)] + pub settings: Vec, + } + + #[traced_test] #[test] fn test_enum() { let mut app = App::new(); app.register_type::(); app.register_type::(); + app.register_type::(); app.insert_resource(EnumTesting::One); app.insert_resource(EnumSettings { setting: EnumTesting::Two, }); + app.insert_resource(EnumSettingsList { + settings: vec![EnumTesting::One, EnumTesting::Two], + }); + file_system::load_project_settings(app.world_mut()); @@ -186,6 +202,10 @@ mod tests { assert_eq!(*settings, EnumSettings { setting: EnumTesting::Three, }); + + let settings = app.world().get_resource::().unwrap(); + + assert_eq!(settings.settings, vec![EnumTesting::One, EnumTesting::Two, EnumTesting::Three]); } } From f1b368b23cc1f4ea76a09a7fe08b530c073475f9 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 20 Oct 2024 17:21:08 +1300 Subject: [PATCH 13/39] remove wrong comment --- crates/bevy_editor_settings/Bevy.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index 4e5996b5..5277baf7 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -19,9 +19,6 @@ variant = "Two" # enum in a struct [enum_settings] setting = "Three" -# can also be written as -# [enum_settings.setting] -# variant = "Three" [enum_settings_list] settings = ["Three"] \ No newline at end of file From c7903911be896862533ab254dde62f616a33203b Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Tue, 22 Oct 2024 17:32:33 +1300 Subject: [PATCH 14/39] support all base types --- crates/bevy_editor_settings/Bevy.toml | 6 +- .../src/file_system/load.rs | 57 ++++++++++++++++++- crates/bevy_editor_settings/src/lib.rs | 21 +++++++ 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index 5277baf7..48186b01 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -21,4 +21,8 @@ variant = "Two" setting = "Three" [enum_settings_list] -settings = ["Three"] \ No newline at end of file +settings = ["Three"] + + +[tuple_struct] +fields = [2, "two"] \ No newline at end of file diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index 4499695c..14934c08 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -4,8 +4,8 @@ use bevy::{ prelude::*, reflect::{ attributes::CustomAttributes, Array, ArrayInfo, DynamicEnum, DynamicTuple, DynamicVariant, - Enum, EnumInfo, List, ListInfo, ReflectFromPtr, ReflectMut, StructInfo, TypeInfo, - ValueInfo, VariantInfo, + Enum, EnumInfo, List, ListInfo, ReflectFromPtr, ReflectMut, StructInfo, TupleStructInfo, + TypeInfo, ValueInfo, VariantInfo, }, scene::ron::{de, value}, }; @@ -94,6 +94,29 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se } } } + TypeInfo::TupleStruct(tuple_struct_info) => { + let s_type = tuple_struct_info.custom_attributes().get::(); + if let Some(s_type) = s_type { + check_settings_type!(settings_type, *s_type); + let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); + let reflect_from_ptr = type_reg.data::().unwrap(); + // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for + #[allow(unsafe_code)] + let ReflectMut::TupleStruct(tuple_struct) = + unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() + else { + panic!("Expected TupleStruct"); + }; + + let name = tuple_struct.reflect_type_ident().unwrap().to_snake_case(); + + if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { + if let Some(array_value) = table.get("fields").and_then(|v| v.as_array()) { + load_tuple_struct(tuple_struct, tuple_struct_info, array_value); + } + } + } + } _ => { warn!("Preferences: Unsupported type: {:?}", type_reg.type_info()); @@ -104,6 +127,36 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se } } +fn load_tuple_struct( + tuple_struct: &mut dyn TupleStruct, + tuple_struct_info: &TupleStructInfo, + table: &toml::value::Array, +) { + for i in 0..tuple_struct.field_len() { + let field_mut = tuple_struct.field_mut(i).unwrap(); + let field_attrs = tuple_struct_info.field_at(i).unwrap().custom_attributes(); + match field_mut.get_represented_type_info().unwrap() { + TypeInfo::Value(value_info) => { + if let Some(value) = table.get(i) { + load_value(field_mut, value_info, value) + } + } + // TypeInfo::Enum(enum_info) => { + // let mut enum_value = DynamicEnum::default(); + // load_enum(&mut enum_value, enum_info, &table[i]); + // field_mut.apply(Box::new(enum_value)); + // } + _ => { + warn!( + "Preferences: Unsupported type: {:?}", + field_mut.get_represented_type_info() + ); + } + } + + } +} + fn load_struct(strct: &mut dyn Struct, struct_info: &StructInfo, table: &toml::Table) { for i in 0..strct.field_len() { let key = strct.name_at(i).unwrap().to_string(); diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index b6df3709..401281c0 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -208,4 +208,25 @@ mod tests { assert_eq!(settings.settings, vec![EnumTesting::One, EnumTesting::Two, EnumTesting::Three]); } + + #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] + #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] + struct TupleStruct(i32, String); + + #[traced_test] + #[test] + fn test_tuple_struct() { + let mut app = App::new(); + + app.register_type::(); + + app.insert_resource(TupleStruct(1, "one".to_string())); + + file_system::load_project_settings(app.world_mut()); + + let settings = app.world().get_resource::().unwrap(); + + assert_eq!(*settings, TupleStruct(2, "two".to_string())); + } + } From 15fe326852f3a0e3552e49759f6bdd5b1d12dadd Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Tue, 22 Oct 2024 17:37:02 +1300 Subject: [PATCH 15/39] support struct with tuple --- crates/bevy_editor_settings/Bevy.toml | 5 ++++- .../bevy_editor_settings/src/file_system/load.rs | 9 +++++++++ crates/bevy_editor_settings/src/lib.rs | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index 48186b01..56d04f10 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -25,4 +25,7 @@ settings = ["Three"] [tuple_struct] -fields = [2, "two"] \ No newline at end of file +fields = [2, "two"] + +[struct_with_tuple] +tuple = [3, "three"] \ No newline at end of file diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index 14934c08..ce466a1e 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -204,6 +204,15 @@ fn load_struct(strct: &mut dyn Struct, struct_info: &StructInfo, table: &toml::T load_enum(enm, enum_info, value); } } + TypeInfo::TupleStruct(tuple_struct_info) => { + let ReflectMut::TupleStruct(tuple_struct) = field_mut.reflect_mut() else { + warn!("Preferences: Expected TupleStruct"); + continue; + }; + if let Some(array_value) = table.get(&key).and_then(|v| v.as_array()) { + load_tuple_struct(tuple_struct, tuple_struct_info, array_value); + } + } _ => { warn!( "Preferences: Unsupported type: {:?}", diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index 401281c0..b6081d57 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -213,20 +213,36 @@ mod tests { #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] struct TupleStruct(i32, String); + #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] + #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] + struct StructWithTuple { + pub tuple: TupleStruct, + } + #[traced_test] #[test] fn test_tuple_struct() { let mut app = App::new(); app.register_type::(); + app.register_type::(); app.insert_resource(TupleStruct(1, "one".to_string())); + app.insert_resource(StructWithTuple { + tuple: TupleStruct(2, "two".to_string()), + }); file_system::load_project_settings(app.world_mut()); let settings = app.world().get_resource::().unwrap(); assert_eq!(*settings, TupleStruct(2, "two".to_string())); + + let settings = app.world().get_resource::().unwrap(); + + assert_eq!(*settings, StructWithTuple { + tuple: TupleStruct(3, "three".to_string()), + }); } } From 265c83f92e94d9ab35fb1837401cd7f52de14dc6 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Tue, 22 Oct 2024 22:43:08 +1300 Subject: [PATCH 16/39] enum tuple in struct --- crates/bevy_editor_settings/Bevy.toml | 4 +- .../src/file_system/load.rs | 49 +++++++++++++++++-- crates/bevy_editor_settings/src/lib.rs | 13 +++-- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index 56d04f10..395d193c 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -17,8 +17,10 @@ list = [3, 4] variant = "Two" # enum in a struct +# and enum tuple [enum_settings] -setting = "Three" +setting = {Some = ["hello", 42]} + [enum_settings_list] settings = ["Three"] diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index ce466a1e..f0aacb07 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -111,7 +111,9 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se let name = tuple_struct.reflect_type_ident().unwrap().to_snake_case(); if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { - if let Some(array_value) = table.get("fields").and_then(|v| v.as_array()) { + if let Some(array_value) = + table.get("fields").and_then(|v| v.as_array()) + { load_tuple_struct(tuple_struct, tuple_struct_info, array_value); } } @@ -153,7 +155,6 @@ fn load_tuple_struct( ); } } - } } @@ -233,7 +234,49 @@ fn load_enum(enm: &mut dyn Enum, enum_info: &EnumInfo, toml_value: &toml::Value) warn!("Preferences: Unknown variant: {}", str_val); } } - toml::Value::Table(table) => {} + toml::Value::Table(table) => { + if let Some(value) = enum_info + .variant_names() + .iter() + .find(|name| table.contains_key(**name)) + { + let maybe_variant = enum_info.variant(value); + let maybe_value = table.get(*value).and_then(|v| v.as_array()); + + match (maybe_variant, maybe_value) { + (Some(VariantInfo::Tuple(variant)), Some(array)) => { + let mut dyn_tuple = DynamicTuple::default(); + + for i in 0..variant.field_len() { + let Some(value) = array.get(i) else { + warn!("Preferences: Missing field in tuple variant"); + continue; + }; + + let field_at = variant.field_at(i).unwrap(); + match field_at.type_info().unwrap() { + TypeInfo::Value(value_info) => { + if let Some(value) = load_value_boxed(value_info, value) { + dyn_tuple.insert_boxed(value); + } + } + _ => { + warn!("Preferences: Unsupported type: {:?}", value,); + } + } + } + + let dyn_enum = DynamicEnum::new(variant.name(), DynamicVariant::Tuple(dyn_tuple)); + enm.apply(&dyn_enum); + } + _ => { + warn!("Preferences: Unknown variant: {:?}", table); + } + } + } else { + warn!("Preferences: Unknown variant: {:?}", table); + } + } _ => { warn!("Preferences: Unsupported type: {:?}", toml_value); } diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index b6081d57..1297ddc1 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -160,10 +160,17 @@ mod tests { Three, } + #[derive(Debug, Clone, PartialEq, Eq, Reflect)] + #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] + enum EnumTestingField { + None, + Some(String, i32), + } + #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] struct EnumSettings { - pub setting: EnumTesting, + pub setting: EnumTestingField, } #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] @@ -184,7 +191,7 @@ mod tests { app.insert_resource(EnumTesting::One); app.insert_resource(EnumSettings { - setting: EnumTesting::Two, + setting: EnumTestingField::None, }); app.insert_resource(EnumSettingsList { settings: vec![EnumTesting::One, EnumTesting::Two], @@ -200,7 +207,7 @@ mod tests { let settings = app.world().get_resource::().unwrap(); assert_eq!(*settings, EnumSettings { - setting: EnumTesting::Three, + setting: EnumTestingField::Some("hello".to_string(), 42), }); let settings = app.world().get_resource::().unwrap(); From 1e5c24bf1518ca8652e94f234d769857d9370c8c Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Tue, 22 Oct 2024 22:54:52 +1300 Subject: [PATCH 17/39] struct enum --- crates/bevy_editor_settings/Bevy.toml | 6 +++- .../src/file_system/load.rs | 35 +++++++++++++++---- crates/bevy_editor_settings/src/lib.rs | 17 ++++++--- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index 395d193c..2b06e47e 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -19,7 +19,11 @@ variant = "Two" # enum in a struct # and enum tuple [enum_settings] -setting = {Some = ["hello", 42]} +test1 = {Tuple = ["hello", 42]} + +[enum_settings.test2.Struct] +name = "four" +age = 4 [enum_settings_list] diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs index f0aacb07..19776f8c 100644 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ b/crates/bevy_editor_settings/src/file_system/load.rs @@ -3,9 +3,7 @@ use std::any::TypeId; use bevy::{ prelude::*, reflect::{ - attributes::CustomAttributes, Array, ArrayInfo, DynamicEnum, DynamicTuple, DynamicVariant, - Enum, EnumInfo, List, ListInfo, ReflectFromPtr, ReflectMut, StructInfo, TupleStructInfo, - TypeInfo, ValueInfo, VariantInfo, + attributes::CustomAttributes, Array, ArrayInfo, DynamicEnum, DynamicStruct, DynamicTuple, DynamicVariant, Enum, EnumInfo, List, ListInfo, ReflectFromPtr, ReflectMut, StructInfo, TupleStructInfo, TypeInfo, ValueInfo, VariantInfo }, scene::ron::{de, value}, }; @@ -241,16 +239,16 @@ fn load_enum(enm: &mut dyn Enum, enum_info: &EnumInfo, toml_value: &toml::Value) .find(|name| table.contains_key(**name)) { let maybe_variant = enum_info.variant(value); - let maybe_value = table.get(*value).and_then(|v| v.as_array()); + let maybe_value = table.get(*value); match (maybe_variant, maybe_value) { - (Some(VariantInfo::Tuple(variant)), Some(array)) => { + (Some(VariantInfo::Tuple(variant)), Some(toml::Value::Array(array))) => { let mut dyn_tuple = DynamicTuple::default(); for i in 0..variant.field_len() { let Some(value) = array.get(i) else { warn!("Preferences: Missing field in tuple variant"); - continue; + return; }; let field_at = variant.field_at(i).unwrap(); @@ -269,6 +267,31 @@ fn load_enum(enm: &mut dyn Enum, enum_info: &EnumInfo, toml_value: &toml::Value) let dyn_enum = DynamicEnum::new(variant.name(), DynamicVariant::Tuple(dyn_tuple)); enm.apply(&dyn_enum); } + (Some(VariantInfo::Struct(variant)), Some(toml::Value::Table(map))) => { + let mut dyn_struct = DynamicStruct::default(); + + for i in 0..variant.field_len() { + let field_at = variant.field_at(i).unwrap(); + let Some(value) = map.get(field_at.name()) else { + warn!("Preferences: Missing field in struct variant"); + return; + }; + + match field_at.type_info().unwrap() { + TypeInfo::Value(value_info) => { + if let Some(value) = load_value_boxed(value_info, value) { + dyn_struct.insert_boxed(field_at.name(), value); + } + } + _ => { + warn!("Preferences: Unsupported type: {:?}", value,); + } + } + } + + let dyn_enum = DynamicEnum::new(variant.name(), DynamicVariant::Struct(dyn_struct)); + enm.apply(&dyn_enum); + } _ => { warn!("Preferences: Unknown variant: {:?}", table); } diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index 1297ddc1..8b457c94 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -163,14 +163,16 @@ mod tests { #[derive(Debug, Clone, PartialEq, Eq, Reflect)] #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] enum EnumTestingField { - None, - Some(String, i32), + Unit, + Tuple(String, i32), + Struct { name: String, age: i32 }, } #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] struct EnumSettings { - pub setting: EnumTestingField, + pub test1: EnumTestingField, + pub test2: EnumTestingField, } #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] @@ -191,7 +193,8 @@ mod tests { app.insert_resource(EnumTesting::One); app.insert_resource(EnumSettings { - setting: EnumTestingField::None, + test1: EnumTestingField::Unit, + test2: EnumTestingField::Unit, }); app.insert_resource(EnumSettingsList { settings: vec![EnumTesting::One, EnumTesting::Two], @@ -207,7 +210,11 @@ mod tests { let settings = app.world().get_resource::().unwrap(); assert_eq!(*settings, EnumSettings { - setting: EnumTestingField::Some("hello".to_string(), 42), + test1: EnumTestingField::Tuple("hello".to_string(), 42), + test2: EnumTestingField::Struct { + name: "four".to_string(), + age: 4, + }, }); let settings = app.world().get_resource::().unwrap(); From cdfd04d870084f85258d35702e708ad3d2611fd8 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Tue, 22 Oct 2024 23:30:42 +1300 Subject: [PATCH 18/39] add comments to example config --- crates/bevy_editor_settings/Bevy.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index 2b06e47e..785b32db 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -21,17 +21,20 @@ variant = "Two" [enum_settings] test1 = {Tuple = ["hello", 42]} +# a struct enum on a struct [enum_settings.test2.Struct] name = "four" age = 4 - +# a struct with a list of enums [enum_settings_list] settings = ["Three"] - +# top level tuple struct +# adds the fields field to the tuple sturct. this is ONLY done for a top level tuple struct [tuple_struct] fields = [2, "two"] +# tuple struct in a struct [struct_with_tuple] tuple = [3, "three"] \ No newline at end of file From aa365c6b269dc887abbf8f146e0e2faefb55814e Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 02:22:10 +1300 Subject: [PATCH 19/39] working value loading --- .../src/file_system/de/value.rs | 302 ++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 crates/bevy_editor_settings/src/file_system/de/value.rs diff --git a/crates/bevy_editor_settings/src/file_system/de/value.rs b/crates/bevy_editor_settings/src/file_system/de/value.rs new file mode 100644 index 00000000..77a93295 --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/value.rs @@ -0,0 +1,302 @@ +use bevy::prelude::warn; +use bevy::reflect::{PartialReflect, ValueInfo}; + +struct LoadValue<'a> { + pub value_info: &'a ValueInfo, + pub toml_value: &'a toml::Value, + pub value: &'a mut dyn PartialReflect, +} + +impl<'a> LoadValue<'a> { + pub fn load_value(self) { + let value_info = self.value_info; + match self.toml_value { + toml::Value::String(str_val) => { + if value_info.is::() { + self.value.apply(str_val); + } else { + warn!("Preferences: Expected {:?}, got String", value_info); + } + } + toml::Value::Integer(int_val) => { + if value_info.is::() { + self.value.apply(&(*int_val as f64)); + } else if value_info.is::() { + self.value + .apply(&((*int_val as f64).clamp(f32::MIN as f64, f32::MAX as f64) as f32)); + } else if value_info.is::() { + self.value.apply(int_val); + } else if value_info.is::() { + self.value.apply(&(*int_val as i32)); + } else if value_info.is::() { + self.value.apply(&(*int_val as i16)); + } else if value_info.is::() { + self.value.apply(&(*int_val as i8)); + } else if value_info.is::() { + self.value.apply(&((*int_val).max(0) as u64)); + } else if value_info.is::() { + self.value.apply(&((*int_val).max(0) as u32)); + } else if value_info.is::() { + self.value.apply(&((*int_val).max(0) as u16)); + } else if value_info.is::() { + self.value.apply(&((*int_val).max(0) as u8)); + } else { + warn!("Preferences: Expected {:?}, got Integer", value_info); + } + } + toml::Value::Float(float_val) => { + if value_info.is::() { + self.value.apply(float_val); + } else if value_info.is::() { + self.value + .apply(&(float_val.clamp(f32::MIN as f64, f32::MAX as f64) as f32)); + } else { + warn!("Preferences: Expected {:?}, got Float", value_info); + } + } + toml::Value::Boolean(bool_val) => { + if value_info.is::() { + self.value.apply(bool_val); + } else { + warn!("Preferences: Expected {:?}, got Bool", value_info); + } + } + value => { + warn!("Preferences: Unsupported type: {:?}", value); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tracing_test::traced_test] + #[test] + fn load_str() { + let mut value = "".to_string(); + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::String("Hello".to_string()); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, "Hello"); + } + + #[tracing_test::traced_test] + #[test] + fn load_float_f64() { + let mut value = 0.0; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Float(3.14); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 3.14); + } + + #[tracing_test::traced_test] + #[test] + fn load_float_f32() { + let mut value = 0.0_f32; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Float(3.14); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 3.14); + } + + #[tracing_test::traced_test] + #[test] + fn load_bool() { + let mut value = false; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Boolean(true); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, true); + } + + #[tracing_test::traced_test] + #[test] + fn load_float_from_int_f64() { + let mut value = 0.0; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Integer(42); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 42.0); + } + + #[tracing_test::traced_test] + #[test] + fn load_float_from_int_f32() { + let mut value = 0.0_f32; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Integer(42); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 42.0); + } + + + #[tracing_test::traced_test] + #[test] + fn load_int() { + let mut value = 0; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Integer(42); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 42); + } + + #[tracing_test::traced_test] + #[test] + fn load_u8() { + let mut value = 0_u8; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Integer(42); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 42); + } + + #[tracing_test::traced_test] + #[test] + fn load_u16() { + let mut value = 0_u16; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Integer(42); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 42); + } + + #[tracing_test::traced_test] + #[test] + fn load_u32() { + let mut value = 0_u32; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Integer(42); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 42); + } + + #[tracing_test::traced_test] + #[test] + fn load_u64() { + let mut value = 0_u64; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Integer(42); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 42); + } + + #[tracing_test::traced_test] + #[test] + fn load_i8() { + let mut value = 0_i8; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Integer(42); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 42); + } + + #[tracing_test::traced_test] + #[test] + fn load_i16() { + let mut value = 0_i16; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Integer(42); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 42); + } + + #[tracing_test::traced_test] + #[test] + fn load_i32() { + let mut value = 0_i32; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Integer(42); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 42); + } + + #[tracing_test::traced_test] + #[test] + fn load_i64() { + let mut value = 0_i64; + let value_info = &ValueInfo::new::(); + let toml_value = &toml::Value::Integer(42); + LoadValue { + value_info, + toml_value, + value: &mut value, + } + .load_value(); + assert_eq!(value, 42); + } + +} + From 3d3dfc95c06fd1d10986a64004c9d4b596fab9dd Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 02:45:41 +1300 Subject: [PATCH 20/39] better value tests --- .../src/file_system/de/value.rs | 49 +++++++------------ 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/value.rs b/crates/bevy_editor_settings/src/file_system/de/value.rs index 77a93295..464e5f1c 100644 --- a/crates/bevy_editor_settings/src/file_system/de/value.rs +++ b/crates/bevy_editor_settings/src/file_system/de/value.rs @@ -1,7 +1,7 @@ use bevy::prelude::warn; use bevy::reflect::{PartialReflect, ValueInfo}; -struct LoadValue<'a> { +pub struct LoadValue<'a> { pub value_info: &'a ValueInfo, pub toml_value: &'a toml::Value, pub value: &'a mut dyn PartialReflect, @@ -70,16 +70,17 @@ impl<'a> LoadValue<'a> { #[cfg(test)] mod tests { + use bevy::reflect::DynamicTyped as _; + use super::*; #[tracing_test::traced_test] #[test] fn load_str() { let mut value = "".to_string(); - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::String("Hello".to_string()); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -91,10 +92,9 @@ mod tests { #[test] fn load_float_f64() { let mut value = 0.0; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Float(3.14); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -106,10 +106,9 @@ mod tests { #[test] fn load_float_f32() { let mut value = 0.0_f32; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Float(3.14); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -121,10 +120,9 @@ mod tests { #[test] fn load_bool() { let mut value = false; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Boolean(true); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -136,10 +134,9 @@ mod tests { #[test] fn load_float_from_int_f64() { let mut value = 0.0; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Integer(42); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -151,10 +148,9 @@ mod tests { #[test] fn load_float_from_int_f32() { let mut value = 0.0_f32; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Integer(42); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -167,10 +163,9 @@ mod tests { #[test] fn load_int() { let mut value = 0; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Integer(42); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -182,10 +177,9 @@ mod tests { #[test] fn load_u8() { let mut value = 0_u8; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Integer(42); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -197,10 +191,9 @@ mod tests { #[test] fn load_u16() { let mut value = 0_u16; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Integer(42); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -212,10 +205,9 @@ mod tests { #[test] fn load_u32() { let mut value = 0_u32; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Integer(42); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -227,10 +219,9 @@ mod tests { #[test] fn load_u64() { let mut value = 0_u64; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Integer(42); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -242,10 +233,9 @@ mod tests { #[test] fn load_i8() { let mut value = 0_i8; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Integer(42); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -257,10 +247,9 @@ mod tests { #[test] fn load_i16() { let mut value = 0_i16; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Integer(42); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -272,10 +261,9 @@ mod tests { #[test] fn load_i32() { let mut value = 0_i32; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Integer(42); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } @@ -287,10 +275,9 @@ mod tests { #[test] fn load_i64() { let mut value = 0_i64; - let value_info = &ValueInfo::new::(); let toml_value = &toml::Value::Integer(42); LoadValue { - value_info, + value_info: value.reflect_type_info().as_value().unwrap(), toml_value, value: &mut value, } From b1839b1d4a9ec61fc51f8d171b20233bbb2aa4f0 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 05:53:06 +1300 Subject: [PATCH 21/39] remove old load file --- .../src/file_system/load.rs | 483 ------------------ 1 file changed, 483 deletions(-) delete mode 100644 crates/bevy_editor_settings/src/file_system/load.rs diff --git a/crates/bevy_editor_settings/src/file_system/load.rs b/crates/bevy_editor_settings/src/file_system/load.rs deleted file mode 100644 index 19776f8c..00000000 --- a/crates/bevy_editor_settings/src/file_system/load.rs +++ /dev/null @@ -1,483 +0,0 @@ -use std::any::TypeId; - -use bevy::{ - prelude::*, - reflect::{ - attributes::CustomAttributes, Array, ArrayInfo, DynamicEnum, DynamicStruct, DynamicTuple, DynamicVariant, Enum, EnumInfo, List, ListInfo, ReflectFromPtr, ReflectMut, StructInfo, TupleStructInfo, TypeInfo, ValueInfo, VariantInfo - }, - scene::ron::{de, value}, -}; -use heck::ToSnakeCase; - -use crate::{MergeStrategy, SettingsTags, SettingsType}; - -/// Load a toml file from the given path -pub fn load_toml_file(path: impl AsRef) -> Result { - let path = path.as_ref(); - let file = std::fs::read_to_string(path)?; - Ok(toml::from_str(&file)?) -} - -/// Errors that can occur when loading a TOML file. -#[derive(Debug, thiserror::Error)] -pub enum LoadError { - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - #[error("TOML deserialization error: {0}")] - TomlDe(#[from] toml::de::Error), -} - -/// check that the settings type matchs the settings type of the file -/// if they don't match, skip the settings -macro_rules! check_settings_type { - ($settings_type:expr, $file_settings_type:expr) => { - if $settings_type != $file_settings_type { - continue; - } - }; -} - -pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: SettingsType) { - let registry = world.get_resource::().unwrap().clone(); - // get all resources that - let resources = world - .iter_resources() - .filter_map(|(res, _)| res.type_id().map(|type_id| (type_id, res.id()))) - .collect::>(); - - for (type_id, res_id) in resources { - if let Some(type_reg) = registry.read().get(type_id) { - match type_reg.type_info() { - TypeInfo::Struct(struct_info) => { - let s_type = struct_info.custom_attributes().get::(); - if let Some(s_type) = s_type { - check_settings_type!(settings_type, *s_type); - let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); - let reflect_from_ptr = type_reg.data::().unwrap(); - // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for - #[allow(unsafe_code)] - let ReflectMut::Struct(strct) = - unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() - else { - panic!("Expected Struct"); - }; - - let name = strct.reflect_type_ident().unwrap().to_snake_case(); - - if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { - load_struct(strct, struct_info, table); - } - } - } - TypeInfo::Enum(enum_info) => { - let s_type = enum_info.custom_attributes().get::(); - if let Some(s_type) = s_type { - check_settings_type!(settings_type, *s_type); - let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); - let reflect_from_ptr = type_reg.data::().unwrap(); - // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for - #[allow(unsafe_code)] - let ReflectMut::Enum(enm) = - unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() - else { - panic!("Expected Struct"); - }; - - let name = enm.reflect_type_ident().unwrap().to_snake_case(); - - if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { - if let Some(value) = table.get("variant") { - load_enum(enm, enum_info, value); - } - } - } - } - TypeInfo::TupleStruct(tuple_struct_info) => { - let s_type = tuple_struct_info.custom_attributes().get::(); - if let Some(s_type) = s_type { - check_settings_type!(settings_type, *s_type); - let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); - let reflect_from_ptr = type_reg.data::().unwrap(); - // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for - #[allow(unsafe_code)] - let ReflectMut::TupleStruct(tuple_struct) = - unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() - else { - panic!("Expected TupleStruct"); - }; - - let name = tuple_struct.reflect_type_ident().unwrap().to_snake_case(); - - if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { - if let Some(array_value) = - table.get("fields").and_then(|v| v.as_array()) - { - load_tuple_struct(tuple_struct, tuple_struct_info, array_value); - } - } - } - } - - _ => { - warn!("Preferences: Unsupported type: {:?}", type_reg.type_info()); - } - } - } - // println!("Saving preferences for {:?}", res.name()); - } -} - -fn load_tuple_struct( - tuple_struct: &mut dyn TupleStruct, - tuple_struct_info: &TupleStructInfo, - table: &toml::value::Array, -) { - for i in 0..tuple_struct.field_len() { - let field_mut = tuple_struct.field_mut(i).unwrap(); - let field_attrs = tuple_struct_info.field_at(i).unwrap().custom_attributes(); - match field_mut.get_represented_type_info().unwrap() { - TypeInfo::Value(value_info) => { - if let Some(value) = table.get(i) { - load_value(field_mut, value_info, value) - } - } - // TypeInfo::Enum(enum_info) => { - // let mut enum_value = DynamicEnum::default(); - // load_enum(&mut enum_value, enum_info, &table[i]); - // field_mut.apply(Box::new(enum_value)); - // } - _ => { - warn!( - "Preferences: Unsupported type: {:?}", - field_mut.get_represented_type_info() - ); - } - } - } -} - -fn load_struct(strct: &mut dyn Struct, struct_info: &StructInfo, table: &toml::Table) { - for i in 0..strct.field_len() { - let key = strct.name_at(i).unwrap().to_string(); - let field_mut = strct.field_at_mut(i).unwrap(); - let field_attrs = struct_info.field_at(i).unwrap().custom_attributes(); - match field_mut.get_represented_type_info().unwrap() { - TypeInfo::Value(value_info) => { - if let Some(value) = table.get(&key) { - load_value(field_mut, value_info, value) - } - } - TypeInfo::Struct(struct_info) => { - if let Some(table) = table.get(&key).and_then(|v| v.as_table()) { - let ReflectMut::Struct(strct) = field_mut.reflect_mut() else { - warn!("Preferences: Expected Struct"); - continue; - }; - load_struct(strct, struct_info, table); - } - } - TypeInfo::List(list_info) => { - if let Some(table) = table.get(&key).and_then(|v| v.as_array()) { - let ReflectMut::List(list) = field_mut.reflect_mut() else { - warn!("Preferences: Expected List"); - continue; - }; - load_list(list, list_info, table, field_attrs); - } - } - TypeInfo::Array(array_info) => { - if let Some(table) = table.get(&key).and_then(|v| v.as_array()) { - let ReflectMut::Array(array) = field_mut.reflect_mut() else { - warn!("Preferences: Expected Array"); - continue; - }; - load_array(array, array_info, table); - } - } - TypeInfo::Enum(enum_info) => { - let ReflectMut::Enum(enm) = field_mut.reflect_mut() else { - warn!("Preferences: Expected Enum"); - continue; - }; - if let Some(value) = table.get(&key) { - load_enum(enm, enum_info, value); - } - } - TypeInfo::TupleStruct(tuple_struct_info) => { - let ReflectMut::TupleStruct(tuple_struct) = field_mut.reflect_mut() else { - warn!("Preferences: Expected TupleStruct"); - continue; - }; - if let Some(array_value) = table.get(&key).and_then(|v| v.as_array()) { - load_tuple_struct(tuple_struct, tuple_struct_info, array_value); - } - } - _ => { - warn!( - "Preferences: Unsupported type: {:?}", - field_mut.get_represented_type_info() - ); - } - } - } -} - -fn load_enum(enm: &mut dyn Enum, enum_info: &EnumInfo, toml_value: &toml::Value) { - match toml_value { - toml::Value::String(str_val) => { - if let Some(VariantInfo::Unit(variant)) = enum_info.variant(str_val) { - let dyn_enum = DynamicEnum::new(variant.name(), DynamicVariant::Unit); - enm.apply(&dyn_enum); - } else { - warn!("Preferences: Unknown variant: {}", str_val); - } - } - toml::Value::Table(table) => { - if let Some(value) = enum_info - .variant_names() - .iter() - .find(|name| table.contains_key(**name)) - { - let maybe_variant = enum_info.variant(value); - let maybe_value = table.get(*value); - - match (maybe_variant, maybe_value) { - (Some(VariantInfo::Tuple(variant)), Some(toml::Value::Array(array))) => { - let mut dyn_tuple = DynamicTuple::default(); - - for i in 0..variant.field_len() { - let Some(value) = array.get(i) else { - warn!("Preferences: Missing field in tuple variant"); - return; - }; - - let field_at = variant.field_at(i).unwrap(); - match field_at.type_info().unwrap() { - TypeInfo::Value(value_info) => { - if let Some(value) = load_value_boxed(value_info, value) { - dyn_tuple.insert_boxed(value); - } - } - _ => { - warn!("Preferences: Unsupported type: {:?}", value,); - } - } - } - - let dyn_enum = DynamicEnum::new(variant.name(), DynamicVariant::Tuple(dyn_tuple)); - enm.apply(&dyn_enum); - } - (Some(VariantInfo::Struct(variant)), Some(toml::Value::Table(map))) => { - let mut dyn_struct = DynamicStruct::default(); - - for i in 0..variant.field_len() { - let field_at = variant.field_at(i).unwrap(); - let Some(value) = map.get(field_at.name()) else { - warn!("Preferences: Missing field in struct variant"); - return; - }; - - match field_at.type_info().unwrap() { - TypeInfo::Value(value_info) => { - if let Some(value) = load_value_boxed(value_info, value) { - dyn_struct.insert_boxed(field_at.name(), value); - } - } - _ => { - warn!("Preferences: Unsupported type: {:?}", value,); - } - } - } - - let dyn_enum = DynamicEnum::new(variant.name(), DynamicVariant::Struct(dyn_struct)); - enm.apply(&dyn_enum); - } - _ => { - warn!("Preferences: Unknown variant: {:?}", table); - } - } - } else { - warn!("Preferences: Unknown variant: {:?}", table); - } - } - _ => { - warn!("Preferences: Unsupported type: {:?}", toml_value); - } - } -} - -fn load_list( - list: &mut dyn List, - list_info: &ListInfo, - array: &toml::value::Array, - attrs: &CustomAttributes, -) { - let default = MergeStrategy::default(); - let merge_strategy = attrs.get::().unwrap_or(&default); - - if let Some(item_info) = list_info.item_info() { - match merge_strategy { - MergeStrategy::Replace => { - while list.len() > 0 { - list.remove(list.len() - 1); - } - } - MergeStrategy::Append => { - // do nothing - } - } - for value in array.iter() { - match item_info { - TypeInfo::Value(value_info) => { - let value = load_value_boxed(value_info, value); - if let Some(value) = value { - list.push(value); - } - } - TypeInfo::Enum(enum_info) => { - let mut enum_value = DynamicEnum::default(); - load_enum(&mut enum_value, enum_info, value); - list.push(Box::new(enum_value)); - } - // TODO support more then values in lists - _ => { - warn!("Preferences: Unsupported type: {:?}", item_info); - } - } - } - } -} - -fn load_array(array: &mut dyn Array, array_info: &ArrayInfo, table: &toml::value::Array) { - warn!("Preferences: Arrays are not supported yet"); -} - -fn load_value_boxed( - value_info: &ValueInfo, - value: &toml::Value, -) -> Option> { - match value { - toml::Value::String(str_val) => { - if value_info.is::() { - Some(Box::new(str_val.clone())) - } else { - warn!("Preferences: Expected {:?}, got String", value_info); - None - } - } - toml::Value::Integer(int_val) => { - if value_info.is::() { - Some(Box::new(*int_val as f64)) - } else if value_info.is::() { - Some(Box::new( - (*int_val).clamp(f32::MIN as i64, f32::MAX as i64) as f32 - )) - } else if value_info.is::() { - Some(Box::new(*int_val)) - } else if value_info.is::() { - Some(Box::new( - (*int_val).clamp(i32::MIN as i64, i32::MAX as i64) as i32 - )) - } else if value_info.is::() { - Some(Box::new( - (*int_val).clamp(i16::MIN as i64, i16::MAX as i64) as i16 - )) - } else if value_info.is::() { - Some(Box::new( - (*int_val).clamp(i8::MIN as i64, i8::MAX as i64) as i8 - )) - } else if value_info.is::() { - Some(Box::new((*int_val).max(0) as u64)) - } else if value_info.is::() { - Some(Box::new((*int_val).max(0) as u32)) - } else if value_info.is::() { - Some(Box::new((*int_val).max(0) as u16)) - } else if value_info.is::() { - Some(Box::new((*int_val).max(0) as u8)) - } else { - warn!("Preferences: Expected {:?}, got Integer", value_info); - None - } - } - toml::Value::Float(float_val) => { - if value_info.is::() { - Some(Box::new(*float_val)) - } else if value_info.is::() { - Some(Box::new( - float_val.clamp(f32::MIN as f64, f32::MAX as f64) as f32 - )) - } else { - warn!("Preferences: Expected {:?}, got Float", value_info); - None - } - } - toml::Value::Boolean(bool_val) => { - if value_info.is::() { - Some(Box::new(*bool_val)) - } else { - warn!("Preferences: Expected {:?}, got Bool", value_info); - None - } - } - _ => { - warn!("Preferences: Unsupported type: {:?}", value); - None - } - } -} - -fn load_value(field: &mut dyn PartialReflect, value_info: &ValueInfo, value: &toml::Value) { - match value { - toml::Value::String(str_val) => { - if value_info.is::() { - field.apply(str_val); - } else { - warn!("Preferences: Expected {:?}, got String", value_info); - } - } - toml::Value::Integer(int_val) => { - if value_info.is::() { - field.apply(&(*int_val as f64)); - } else if value_info.is::() { - field.apply(&((*int_val).clamp(f32::MIN as i64, f32::MAX as i64) as f32)); - } else if value_info.is::() { - field.apply(int_val); - } else if value_info.is::() { - field.apply(&((*int_val).clamp(i32::MIN as i64, i32::MAX as i64) as i32)); - } else if value_info.is::() { - field.apply(&((*int_val).clamp(i16::MIN as i64, i16::MAX as i64) as i16)); - } else if value_info.is::() { - field.apply(&((*int_val).clamp(i8::MIN as i64, i8::MAX as i64) as i8)); - } else if value_info.is::() { - field.apply(&((*int_val).max(0) as u64)); - } else if value_info.is::() { - field.apply(&((*int_val).max(0) as u32)); - } else if value_info.is::() { - field.apply(&((*int_val).max(0) as u16)); - } else if value_info.is::() { - field.apply(&((*int_val).max(0) as u8)); - } else { - warn!("Preferences: Expected {:?}, got Integer", value_info); - } - } - toml::Value::Float(float_val) => { - if value_info.is::() { - field.apply(float_val); - } else if value_info.is::() { - field.apply(&(float_val.clamp(f32::MIN as f64, f32::MAX as f64) as f32)); - } else { - warn!("Preferences: Expected {:?}, got Float", value_info); - } - } - toml::Value::Boolean(bool_val) => { - if value_info.is::() { - field.apply(bool_val); - } else { - warn!("Preferences: Expected {:?}, got Bool", value_info); - } - } - _ => { - warn!("Preferences: Unsupported type: {:?}", value); - } - } -} From 8868f4efc94396443d5e576f251aa2f1460c262b Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 05:53:21 +1300 Subject: [PATCH 22/39] full deserilizing support --- .../src/file_system/de/array.rs | 63 ++++ .../src/file_system/de/default.rs | 116 +++++++ .../src/file_system/de/enums.rs | 180 +++++++++++ .../src/file_system/de/list.rs | 106 +++++++ .../src/file_system/de/map.rs | 73 +++++ .../src/file_system/de/mod.rs | 294 ++++++++++++++++++ .../src/file_system/de/set.rs | 59 ++++ .../src/file_system/de/struct_utils.rs | 46 +++ .../src/file_system/de/structs.rs | 201 ++++++++++++ .../src/file_system/de/tuple.rs | 79 +++++ .../src/file_system/de/tuple_struct.rs | 89 ++++++ .../src/file_system/de/tuple_utils.rs | 36 +++ .../src/file_system/de/value.rs | 37 +-- .../src/file_system/mod.rs | 18 +- 14 files changed, 1367 insertions(+), 30 deletions(-) create mode 100644 crates/bevy_editor_settings/src/file_system/de/array.rs create mode 100644 crates/bevy_editor_settings/src/file_system/de/default.rs create mode 100644 crates/bevy_editor_settings/src/file_system/de/enums.rs create mode 100644 crates/bevy_editor_settings/src/file_system/de/list.rs create mode 100644 crates/bevy_editor_settings/src/file_system/de/map.rs create mode 100644 crates/bevy_editor_settings/src/file_system/de/mod.rs create mode 100644 crates/bevy_editor_settings/src/file_system/de/set.rs create mode 100644 crates/bevy_editor_settings/src/file_system/de/struct_utils.rs create mode 100644 crates/bevy_editor_settings/src/file_system/de/structs.rs create mode 100644 crates/bevy_editor_settings/src/file_system/de/tuple.rs create mode 100644 crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs create mode 100644 crates/bevy_editor_settings/src/file_system/de/tuple_utils.rs diff --git a/crates/bevy_editor_settings/src/file_system/de/array.rs b/crates/bevy_editor_settings/src/file_system/de/array.rs new file mode 100644 index 00000000..44ad2ea1 --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/array.rs @@ -0,0 +1,63 @@ +use bevy::{ + prelude::warn, + reflect::{Array, ArrayInfo}, +}; + +use super::LoadStructure; + +pub struct LoadArray<'a> { + pub array_info: &'a ArrayInfo, + pub array: &'a mut dyn Array, + pub toml_array: &'a toml::value::Array, +} + +impl<'a> LoadArray<'a> { + pub fn load_array(self) { + if self.toml_array.len() != self.array_info.capacity() { + warn!( + "Preferences: Expected Array length {}, got {}", + self.array_info.capacity(), + self.toml_array.len() + ); + return; + } + + for i in 0..self.array_info.capacity() { + let Some(toml_value) = self.toml_array.get(i) else { + continue; + }; + + let field_mut = self.array.get_mut(i).unwrap(); + + LoadStructure { + type_info: field_mut.get_represented_type_info().unwrap(), + table: toml_value, + structure: field_mut, + custom_attributes: None, + } + .load(); + } + } +} + +#[cfg(test)] +mod tests { + use bevy::reflect::{DynamicTyped as _, Reflect}; + + use super::*; + + #[tracing_test::traced_test] + #[test] + fn load_array() { + let mut array = [0, 0]; + + let toml_value = toml::Value::Array(vec![toml::Value::Integer(1), toml::Value::Integer(2)]); + LoadArray { + array_info: array.reflect_type_info().as_array().unwrap(), + toml_array: toml_value.as_array().unwrap(), + array: &mut array, + } + .load_array(); + assert_eq!(array, [1, 2]); + } +} diff --git a/crates/bevy_editor_settings/src/file_system/de/default.rs b/crates/bevy_editor_settings/src/file_system/de/default.rs new file mode 100644 index 00000000..cf310000 --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/default.rs @@ -0,0 +1,116 @@ +use bevy::reflect::{ + ArrayInfo, DynamicArray, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple, ListInfo, MapInfo, PartialReflect, SetInfo, Type, TypeInfo, ValueInfo +}; + +use super::{struct_utils::StructLikeInfo, tuple_utils::TupleLikeInfo}; + +pub fn default_data_type(type_info: &TypeInfo) -> Option> { + match type_info { + TypeInfo::Value(value_info) => default_value(value_info.ty()), + TypeInfo::Struct(struct_info) => { + default_struct(struct_info).map(|s| Box::new(s) as Box) + } + TypeInfo::TupleStruct(tuple_struct_info) => { + default_tuple(tuple_struct_info).map(|t| Box::new(t) as Box) + } + TypeInfo::Tuple(tuple_info) => { + default_tuple(tuple_info).map(|t| Box::new(t) as Box) + } + TypeInfo::Array(type_info) => { + default_array(type_info).map(|a| Box::new(a) as Box) + } + TypeInfo::List(type_info) => { + default_list(type_info).map(|l| Box::new(l) as Box) + } + TypeInfo::Map(type_info) => { + default_map(type_info).map(|m| Box::new(m) as Box) + } + TypeInfo::Set(type_info) => { + default_set(type_info).map(|s| Box::new(s) as Box) + } + TypeInfo::Enum(_) => None, + } +} + +pub fn default_set(_type_info: &SetInfo) -> Option { + let output = DynamicSet::default(); + Some(output) +} + +pub fn default_map(_type_info: &MapInfo) -> Option { + let output = DynamicMap::default(); + Some(output) +} + +pub fn default_list(_type_info: &ListInfo) -> Option { + let output = DynamicList::default(); + Some(output) +} + +pub fn default_array(_type_info: &ArrayInfo) -> Option { + let output = DynamicList::default(); + Some(output) +} + +pub fn default_value(type_info: &Type) -> Option> { + if type_info.is::() { + Some(Box::new(String::default())) + } else if type_info.is::() { + Some(Box::new(f64::default())) + } else if type_info.is::() { + Some(Box::new(f32::default())) + } else if type_info.is::() { + Some(Box::new(i64::default())) + } else if type_info.is::() { + Some(Box::new(i32::default())) + } else if type_info.is::() { + Some(Box::new(i16::default())) + } else if type_info.is::() { + Some(Box::new(i8::default())) + } else if type_info.is::() { + Some(Box::new(u64::default())) + } else if type_info.is::() { + Some(Box::new(u32::default())) + } else if type_info.is::() { + Some(Box::new(u16::default())) + } else if type_info.is::() { + Some(Box::new(u8::default())) + } else if type_info.is::() { + Some(Box::new(bool::default())) + } else { + None + } +} + +pub fn default_struct(type_info: &S) -> Option { + let mut dyn_struct = DynamicStruct::default(); + // dyn_struct.set_represented_type(type_info); + + for i in 0..type_info.field_len() { + let field_at = type_info.field_at(i).unwrap(); + + let Some(value) = default_data_type(field_at.type_info().unwrap()) else { + return None; + }; + + dyn_struct.insert_boxed(field_at.name(), value); + } + + Some(dyn_struct) +} + +pub fn default_tuple(type_info: &S) -> Option { + let mut tuple = DynamicTuple::default(); + + for i in 0..type_info.field_len() { + let field_at = type_info.field_at(i).unwrap(); + + let Some(value) = default_data_type(field_at.type_info().unwrap()) else { + return None; + }; + + tuple.insert_boxed(value); + } + + Some(tuple) +} diff --git a/crates/bevy_editor_settings/src/file_system/de/enums.rs b/crates/bevy_editor_settings/src/file_system/de/enums.rs new file mode 100644 index 00000000..687391ab --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/enums.rs @@ -0,0 +1,180 @@ +use bevy::{ + prelude::*, + reflect::{ + DynamicEnum, DynamicStruct, DynamicTuple, DynamicVariant, Enum, EnumInfo, TypeInfo, + VariantInfo, + }, +}; + +use super::{structs::LoadStruct, tuple::LoadTuple, tuple_struct::LoadTupleStruct, LoadStructure}; + +pub struct LoadEnum<'a> { + pub enum_info: &'a EnumInfo, + pub toml_value: &'a toml::Value, + pub enm: &'a mut dyn Enum, +} + +impl<'a> LoadEnum<'a> { + pub fn load_enum(self) { + match self.toml_value { + toml::Value::String(str_val) => { + if let Some(VariantInfo::Unit(variant)) = self.enum_info.variant(str_val) { + let dyn_enum = DynamicEnum::new(variant.name(), DynamicVariant::Unit); + self.enm.apply(&dyn_enum); + } else { + warn!("Preferences: Unknown variant: {}", str_val); + } + } + toml::Value::Table(table) => { + if let Some(value) = self + .enum_info + .variant_names() + .iter() + .find(|name| table.contains_key(**name)) + { + let variant_info = self.enum_info.variant(value).unwrap(); + let value = table.get(*value).unwrap(); + + match variant_info { + VariantInfo::Unit(variant) => { + let dyn_enum = DynamicEnum::new(variant.name(), DynamicVariant::Unit); + self.enm.apply(&dyn_enum); + } + VariantInfo::Struct(struct_info) => { + let Some(map) = value.as_table() else { + warn!("Preferences: Table"); + return; + }; + + let Some(mut dyn_struct) = super::default::default_struct(struct_info) + else { + warn!("Preferences: Expected Struct"); + return; + }; + + LoadStruct { + struct_info, + table: map, + strct: &mut dyn_struct, + } + .load_struct(); + + let dyn_enum = DynamicEnum::new( + variant_info.name(), + DynamicVariant::Struct(dyn_struct), + ); + self.enm.apply(&dyn_enum); + } + VariantInfo::Tuple(tuple_variant_info) + if tuple_variant_info.field_len() == 1 && !value.is_array() => { + // TODO: This is a hack to support single field tuple structs + } + VariantInfo::Tuple(tuple_variant_info) => { + let Some(array) = value.as_array() else { + warn!("Preferences: Expected Array"); + return; + }; + + let Some(mut dyn_tuple) = + super::default::default_tuple(tuple_variant_info) + else { + warn!("Preferences: Expected TupleStruct"); + return; + }; + + LoadTuple { + tuple_info: tuple_variant_info, + table: array, + tuple: &mut dyn_tuple, + } + .load_tuple(); + + let dyn_enum = DynamicEnum::new( + variant_info.name(), + DynamicVariant::Tuple(dyn_tuple), + ); + self.enm.apply(&dyn_enum); + } + } + } + } + _ => { + warn!("Preferences: Unsupported type: {:?}", self.toml_value); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bevy::reflect::DynamicTyped as _; + + #[derive(Debug, Clone, PartialEq, Reflect, Default)] + enum TestEnum { + #[default] + Variant1, + Variant2(u32), + Variant3 { + name: String, + age: u32, + }, + Variant4(u32, u32), + } + + + + #[tracing_test::traced_test] + #[test] + fn load_enum_unit() { + let mut enum_test = TestEnum::Variant2(0); + + let toml_value = toml::Value::String("Variant1".to_string()); + LoadEnum { + enum_info: enum_test.reflect_type_info().as_enum().unwrap(), + toml_value: &toml_value, + enm: &mut enum_test, + } + .load_enum(); + + assert_eq!(enum_test, TestEnum::Variant1); + } + + + fn enum_test_toml() -> toml::Value { + let mut table = toml::value::Table::new(); + let mut var3 = toml::value::Table::new(); + var3.insert("name".to_string(), toml::Value::String("John".to_string())); + var3.insert("age".to_string(), toml::Value::Integer(10)); + table.insert("Variant3".to_string(), toml::Value::Table(var3)); + toml::Value::Table(table) + } + + #[tracing_test::traced_test] + #[test] + fn load_enum_struct() { + let mut enum_test = TestEnum::default(); + + let toml_value = enum_test_toml(); + LoadEnum { + enum_info: enum_test.reflect_type_info().as_enum().unwrap(), + toml_value: &toml_value, + enm: &mut enum_test, + } + .load_enum(); + + assert_eq!( + enum_test, + TestEnum::Variant3 { + name: "John".to_string(), + age: 10, + } + ); + } + + fn enum_test_tuple_toml() -> toml::Value { + let mut table = toml::value::Table::new(); + table.insert("Variant4".to_string(), toml::Value::Array(vec![toml::Value::Integer(1), toml::Value::Integer(2)])); + toml::Value::Table(table) + } +} diff --git a/crates/bevy_editor_settings/src/file_system/de/list.rs b/crates/bevy_editor_settings/src/file_system/de/list.rs new file mode 100644 index 00000000..29a6c165 --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/list.rs @@ -0,0 +1,106 @@ +use bevy::{ + prelude::warn, + reflect::{attributes::CustomAttributes, List, ListInfo}, +}; + +use crate::MergeStrategy; + +use super::LoadStructure; + +pub struct LoadList<'a> { + pub list_info: &'a ListInfo, + pub list: &'a mut dyn List, + pub toml_array: &'a toml::value::Array, + pub custom_attributes: Option<&'a CustomAttributes>, +} + +impl<'a> LoadList<'a> { + pub fn load_list(self) { + let merge_strategy = self + .custom_attributes + .and_then(|attrs| attrs.get::()) + .cloned() + .unwrap_or_default(); + + let Some(item_info) = self.list_info.item_info() else { + warn!("Preferences: Expected List item info"); + return; + }; + + if let MergeStrategy::Replace = merge_strategy { + while self.list.len() > 0 { + self.list.remove(self.list.len() - 1); + } + } + + for toml_value in self.toml_array.iter() { + let Some(mut value) = super::default::default_data_type(item_info) else { + warn!("Unable to create default value for list item"); + return; + }; + + LoadStructure { + type_info: item_info, + table: toml_value, + structure: value.as_mut(), + custom_attributes: None, + } + .load(); + + self.list.push(value); + } + } +} + +#[cfg(test)] +mod tests { + use bevy::reflect::{DynamicTyped as _, Reflect, Struct}; + + use super::*; + + #[tracing_test::traced_test] + #[test] + fn load_list() { + let mut list: Vec = Vec::new(); + + let toml_value = toml::Value::Array(vec![toml::Value::Integer(1), toml::Value::Integer(2)]); + LoadList { + list_info: list.reflect_type_info().as_list().unwrap(), + list: &mut list, + toml_array: toml_value.as_array().unwrap(), + custom_attributes: None, + } + .load_list(); + assert_eq!(list, vec![1, 2]); + } + + #[derive(Debug, Clone, PartialEq, Reflect, Default)] + struct TestMergeStrategy { + #[reflect(@MergeStrategy::Append)] + pub list: Vec, + } + + fn list_test_toml() -> toml::Value { + toml::Value::Array(vec![toml::Value::Integer(3), toml::Value::Integer(4)]) + } + + #[tracing_test::traced_test] + #[test] + fn load_list_with_merge_strategy() { + let mut list = TestMergeStrategy::default(); + list.list.push(1); + list.list.push(2); + + let attrs = list.reflect_type_info().as_struct().unwrap().field_at(0).unwrap().custom_attributes(); + + let toml_value = list_test_toml(); + LoadList { + list_info: list.list.reflect_type_info().as_list().unwrap(), + list: &mut list.list, + toml_array: toml_value.as_array().unwrap(), + custom_attributes: Some(attrs), + } + .load_list(); + assert_eq!(list.list, vec![1, 2, 3, 4]); + } +} diff --git a/crates/bevy_editor_settings/src/file_system/de/map.rs b/crates/bevy_editor_settings/src/file_system/de/map.rs new file mode 100644 index 00000000..bd968e5d --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/map.rs @@ -0,0 +1,73 @@ +use bevy::{ + prelude::warn, + reflect::{Map, MapInfo}, +}; + +use super::LoadStructure; + +pub struct LoadMap<'a> { + pub map: &'a mut dyn Map, + pub map_info: &'a MapInfo, + pub table: &'a toml::value::Table, +} + +impl<'a> LoadMap<'a> { + pub fn load_map(self) { + if !self + .map_info + .key_info() + .map(|info| info.is::()) + .unwrap_or(false) + { + warn!("Preferences: Map key must be a String"); + return; + } + + for (key, toml_value) in self.table.iter() { + let Some(value_info) = self.map_info.value_info() else { + warn!("Preferences: Expected Map value info"); + return; + }; + + let Some(mut value) = super::default::default_data_type(value_info) else { + warn!("Unable to create default value for map item"); + return; + }; + + LoadStructure { + type_info: value_info, + table: toml_value, + structure: value.as_mut(), + custom_attributes: None, + } + .load(); + + self.map.insert_boxed(Box::new(key.clone()), value); + } + } +} + +#[cfg(test)] +mod tests { + use bevy::reflect::{DynamicTyped as _, Reflect, Struct}; + + use super::*; + + #[tracing_test::traced_test] + #[test] + fn load_map() { + let mut map: std::collections::HashMap = std::collections::HashMap::new(); + + let mut table = toml::value::Table::default(); + table.insert("key".to_string(), toml::Value::Integer(1)); + + LoadMap { + map_info: map.reflect_type_info().as_map().unwrap(), + map: &mut map, + table: &table, + } + .load_map(); + + assert_eq!(map.get("key"), Some(&1)); + } +} diff --git a/crates/bevy_editor_settings/src/file_system/de/mod.rs b/crates/bevy_editor_settings/src/file_system/de/mod.rs new file mode 100644 index 00000000..c0610723 --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/mod.rs @@ -0,0 +1,294 @@ +mod array; +mod default; +mod enums; +mod list; +mod map; +mod set; +mod struct_utils; +mod structs; +mod tuple; +mod tuple_struct; +mod tuple_utils; +mod value; + +use array::LoadArray; +use bevy::{ + prelude::*, + reflect::{ + attributes::CustomAttributes, Array, ArrayInfo, DynamicEnum, DynamicStruct, DynamicTuple, + DynamicVariant, Enum, EnumInfo, List, ListInfo, ReflectFromPtr, ReflectMut, StructInfo, + TupleStructInfo, TypeInfo, ValueInfo, VariantInfo, + }, +}; +use enums::LoadEnum; +use heck::ToSnakeCase; +use list::LoadList; +use map::LoadMap; +use set::LoadSet; +use structs::LoadStruct; +use tuple::LoadTuple; +use tuple_struct::LoadTupleStruct; +use value::LoadValue; + +use crate::{MergeStrategy, SettingsTags, SettingsType}; + +/// Errors that can occur when loading a TOML file. +#[derive(Debug, thiserror::Error)] +pub enum LoadError { + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + #[error("TOML deserialization error: {0}")] + TomlDe(#[from] toml::de::Error), +} + +/// Load a toml file from the given path +pub fn load_toml_file(path: impl AsRef) -> Result { + let path = path.as_ref(); + let file = std::fs::read_to_string(path)?; + Ok(toml::from_str(&file)?) +} + +pub struct LoadStructure<'a> { + pub type_info: &'static TypeInfo, + pub table: &'a toml::Value, + pub structure: &'a mut dyn PartialReflect, + pub custom_attributes: Option<&'a CustomAttributes>, +} + +impl<'a> LoadStructure<'a> { + pub fn load(self) { + match self.type_info { + TypeInfo::Value(value_info) => { + LoadValue { + value_info: value_info.ty(), + toml_value: self.table, + value: self.structure, + } + .load_value(); + } + TypeInfo::Struct(struct_info) => { + if let Some(table) = self.table.as_table() { + let ReflectMut::Struct(strct) = self.structure.reflect_mut() else { + warn!("Preferences: Expected Struct"); + return; + }; + LoadStruct { + struct_info, + table, + strct, + } + .load_struct(); + } + } + TypeInfo::TupleStruct(tuple_struct_info) => { + if let Some(array_value) = self.table.as_array() { + let ReflectMut::TupleStruct(tuple_struct) = self.structure.reflect_mut() else { + warn!("Preferences: Expected TupleStruct"); + return; + }; + LoadTupleStruct { + tuple_struct_info, + table: array_value, + tuple_struct, + } + .load_tuple_struct(); + } + } + TypeInfo::Tuple(tuple_info) => { + if let Some(array_value) = self.table.as_array() { + let ReflectMut::Tuple(tuple) = self.structure.reflect_mut() else { + warn!("Preferences: Expected Tuple"); + return; + }; + LoadTuple { + tuple_info, + table: array_value, + tuple, + } + .load_tuple(); + } + } + TypeInfo::List(list_info) => { + if let Some(array_value) = self.table.as_array() { + let ReflectMut::List(list) = self.structure.reflect_mut() else { + warn!("Preferences: Expected List"); + return; + }; + LoadList { + list_info, + list, + toml_array: array_value, + custom_attributes: self.custom_attributes, + } + .load_list(); + } + } + TypeInfo::Array(array_info) => { + if let Some(array_value) = self.table.as_array() { + let ReflectMut::Array(array) = self.structure.reflect_mut() else { + warn!("Preferences: Expected Array"); + return; + }; + LoadArray { + array_info, + array, + toml_array: array_value, + } + .load_array(); + } + } + TypeInfo::Map(map_info) => { + if let Some(toml_map) = self.table.as_table() { + let ReflectMut::Map(map) = self.structure.reflect_mut() else { + warn!("Preferences: Expected Map"); + return; + }; + LoadMap { + map_info, + map, + table: toml_map, + } + .load_map(); + } + } + TypeInfo::Set(set_info) => { + if let Some(toml_array) = self.table.as_array() { + let ReflectMut::Set(set) = self.structure.reflect_mut() else { + warn!("Preferences: Expected Set"); + return; + }; + LoadSet { + set_info, + set, + toml_array, + } + .load_set(); + } + } + TypeInfo::Enum(enum_info) => { + let ReflectMut::Enum(enm) = self.structure.reflect_mut() else { + warn!("Preferences: Expected Enum"); + return; + }; + + LoadEnum { + enum_info, + enm, + toml_value: self.table, + } + .load_enum(); + } + } + } +} + +pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: SettingsType) { + let registry = world.get_resource::().unwrap().clone(); + // get all resources that + let resources = world + .iter_resources() + .filter_map(|(res, _)| res.type_id().map(|type_id| (type_id, res.id()))) + .collect::>(); + + for (type_id, res_id) in resources { + if let Some(type_reg) = registry.read().get(type_id) { + match type_reg.type_info() { + TypeInfo::Struct(struct_info) => { + let s_type = struct_info.custom_attributes().get::(); + if let Some(s_type) = s_type { + if settings_type != *s_type { + continue; + } + let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); + let reflect_from_ptr = type_reg.data::().unwrap(); + // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for + #[allow(unsafe_code)] + let ReflectMut::Struct(strct) = + unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() + else { + panic!("Expected Struct"); + }; + + let name = strct.reflect_type_ident().unwrap().to_snake_case(); + + if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { + LoadStruct { + struct_info, + table, + strct, + } + .load_struct(); + } + } + } + TypeInfo::Enum(enum_info) => { + let s_type = enum_info.custom_attributes().get::(); + if let Some(s_type) = s_type { + if settings_type != *s_type { + continue; + } + let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); + let reflect_from_ptr = type_reg.data::().unwrap(); + // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for + #[allow(unsafe_code)] + let ReflectMut::Enum(enm) = + unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() + else { + panic!("Expected Struct"); + }; + + let name = enm.reflect_type_ident().unwrap().to_snake_case(); + + if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { + if let Some(value) = table.get("variant") { + LoadEnum { + enum_info, + enm, + toml_value: value, + } + .load_enum(); + } + } + } + } + TypeInfo::TupleStruct(tuple_struct_info) => { + let s_type = tuple_struct_info.custom_attributes().get::(); + if let Some(s_type) = s_type { + if settings_type != *s_type { + continue; + } + let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); + let reflect_from_ptr = type_reg.data::().unwrap(); + // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for + #[allow(unsafe_code)] + let ReflectMut::TupleStruct(tuple_struct) = + unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() + else { + panic!("Expected TupleStruct"); + }; + + let name = tuple_struct.reflect_type_ident().unwrap().to_snake_case(); + + if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { + if let Some(array_value) = + table.get("fields").and_then(|v| v.as_array()) + { + LoadTupleStruct { + tuple_struct_info, + table: array_value, + tuple_struct, + } + .load_tuple_struct(); + } + } + } + } + + _ => { + warn!("Preferences: Unsupported type: {:?}", type_reg.type_info()); + } + } + } + // println!("Saving preferences for {:?}", res.name()); + } +} diff --git a/crates/bevy_editor_settings/src/file_system/de/set.rs b/crates/bevy_editor_settings/src/file_system/de/set.rs new file mode 100644 index 00000000..273c96af --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/set.rs @@ -0,0 +1,59 @@ +use bevy::{ + prelude::warn, + reflect::{Set, SetInfo}, +}; + +use super::value::LoadValue; + +pub struct LoadSet<'a> { + pub set: &'a mut dyn Set, + pub set_info: &'a SetInfo, + pub toml_array: &'a toml::value::Array, +} + +impl<'a> LoadSet<'a> { + pub fn load_set(self) { + for toml_value in self.toml_array.iter() { + let mut value = super::default::default_value(&self.set_info.value_ty()).unwrap(); + + LoadValue { + value_info: &self.set_info.value_ty(), + toml_value, + value: value.as_mut(), + } + .load_value(); + + self.set.insert_boxed(value); + } + } +} + +#[cfg(test)] +mod tests { + use bevy::reflect::{DynamicTyped as _, Struct, TypeInfo}; + + use super::*; + + #[tracing_test::traced_test] + #[test] + fn load_set() { + let mut set: std::collections::HashSet = std::collections::HashSet::new(); + + let toml_value = toml::Value::Array(vec![toml::Value::Integer(1), toml::Value::Integer(2)]); + + let TypeInfo::Set(set_info) = set.reflect_type_info() else { + panic!("Expected Set TypeInfo"); + }; + + LoadSet { + set_info, + toml_array: toml_value.as_array().unwrap(), + set: &mut set, + } + .load_set(); + + assert_eq!(set.len(), 2); + assert!(set.contains(&1)); + assert!(set.contains(&2)); + } +} diff --git a/crates/bevy_editor_settings/src/file_system/de/struct_utils.rs b/crates/bevy_editor_settings/src/file_system/de/struct_utils.rs new file mode 100644 index 00000000..4ae8d0ee --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/struct_utils.rs @@ -0,0 +1,46 @@ +use bevy::reflect::{NamedField, StructInfo, StructVariantInfo}; +use core::slice::Iter; + +/// A helper trait for accessing type information from struct-like types. +pub(super) trait StructLikeInfo { + fn field(&self, name: &str) -> Option<&NamedField>; + fn field_at(&self, index: usize) -> Option<&NamedField>; + fn field_len(&self) -> usize; + fn iter_fields(&self) -> Iter<'_, NamedField>; +} + +impl StructLikeInfo for StructInfo { + fn field(&self, name: &str) -> Option<&NamedField> { + Self::field(self, name) + } + + fn field_at(&self, index: usize) -> Option<&NamedField> { + Self::field_at(self, index) + } + + fn field_len(&self) -> usize { + Self::field_len(self) + } + + fn iter_fields(&self) -> Iter<'_, NamedField> { + self.iter() + } +} + +impl StructLikeInfo for StructVariantInfo { + fn field(&self, name: &str) -> Option<&NamedField> { + Self::field(self, name) + } + + fn field_at(&self, index: usize) -> Option<&NamedField> { + Self::field_at(self, index) + } + + fn field_len(&self) -> usize { + Self::field_len(self) + } + + fn iter_fields(&self) -> Iter<'_, NamedField> { + self.iter() + } +} diff --git a/crates/bevy_editor_settings/src/file_system/de/structs.rs b/crates/bevy_editor_settings/src/file_system/de/structs.rs new file mode 100644 index 00000000..3bef7e48 --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/structs.rs @@ -0,0 +1,201 @@ +use bevy::{ + prelude::warn, + reflect::{ReflectMut, Struct, TypeInfo}, +}; + +use super::{struct_utils::StructLikeInfo, value::LoadValue, LoadStructure}; + +pub struct LoadStruct<'a> { + pub struct_info: &'a dyn StructLikeInfo, + pub table: &'a toml::Table, + pub strct: &'a mut dyn Struct, +} + +impl<'a> LoadStruct<'a> { + pub fn load_struct(self) { + let struct_info = self.struct_info; + let table = self.table; + let strct = self.strct; + for i in 0..struct_info.field_len() { + let field = struct_info.field_at(i).unwrap(); + let key = field.name(); + + let Some(toml_value) = table.get(key) else { + continue; + }; + + let field_mut = strct.field_at_mut(i).unwrap(); + let field_attrs = field.custom_attributes(); + LoadStructure { + type_info: field_mut.get_represented_type_info().unwrap(), + table: toml_value, + structure: field_mut, + custom_attributes: Some(field_attrs), + } + .load(); + } + } +} + +#[cfg(test)] +mod tests { + use bevy::reflect::{DynamicTyped, Reflect}; + + use super::*; + + #[derive(Debug, Clone, Reflect, Default, PartialEq)] + struct Values { + pub string: String, + pub float: f64, + pub float32: f32, + } + + fn values_toml() -> toml::value::Table { + let mut table = toml::value::Table::default(); + table.insert( + "string".to_string(), + toml::Value::String("Hello".to_string()), + ); + table.insert("float".to_string(), toml::Value::Float(3.14)); + table.insert("float32".to_string(), toml::Value::Float(3.14)); + table + } + + #[tracing_test::traced_test] + #[test] + fn load_struct_basic_values() { + let mut struct_info = Values::default(); + let table = values_toml(); + + LoadStruct { + struct_info: struct_info.reflect_type_info().as_struct().unwrap(), + table: &table, + strct: &mut struct_info, + } + .load_struct(); + + assert_eq!( + struct_info, + Values { + string: "Hello".to_string(), + float: 3.14, + float32: 3.14, + } + ); + } + + #[derive(Debug, Clone, Reflect, Default, PartialEq)] + struct StructWithStruct { + values: Values, + } + + fn load_struct_with_struct_toml() -> toml::value::Table { + let mut table = toml::value::Table::default(); + table.insert("values".to_string(), toml::Value::Table(values_toml())); + table + } + + #[tracing_test::traced_test] + #[test] + fn load_struct_with_struct() { + let mut struct_info = StructWithStruct::default(); + + let table = load_struct_with_struct_toml(); + + LoadStruct { + struct_info: struct_info.reflect_type_info().as_struct().unwrap(), + table: &table, + strct: &mut struct_info, + } + .load_struct(); + + assert_eq!( + struct_info, + StructWithStruct { + values: Values { + string: "Hello".to_string(), + float: 3.14, + float32: 3.14, + }, + } + ); + } +} + +// fn load_struct( +// strct: &mut dyn Struct, +// struct_info: &'static S, +// table: &toml::Table, +// ) { +// let mut dynamic_struct = DynamicStruct::default(); +// for i in 0..struct_info.field_len() { +// let field = struct_info.field_at(i).unwrap(); +// let key = field.name(); + +// let Some(toml_value) = table.get(key) else { +// continue; +// }; + +// let field_mut = strct.field_at_mut(i).unwrap(); +// let field_attrs = field.custom_attributes(); +// match field.type_info().unwrap() { +// TypeInfo::Value(value_info) => { +// let value = load_value_boxed(value_info, toml_value); +// if let Some(value) = value { +// field_mut.apply(value.as_ref()); +// } +// // load_value(field_mut, value_info, value) +// } +// TypeInfo::Struct(struct_info) => { +// if let Some(table) = toml_value.as_table() { +// let ReflectMut::Struct(strct) = field_mut.reflect_mut() else { +// warn!("Preferences: Expected Struct"); +// continue; +// }; +// load_struct(strct, struct_info, table); +// } +// } +// TypeInfo::List(list_info) => { +// if let Some(table) = toml_value.as_array() { +// let ReflectMut::List(list) = field_mut.reflect_mut() else { +// warn!("Preferences: Expected List"); +// continue; +// }; +// load_list(list, list_info, table, field_attrs); +// } +// } +// TypeInfo::Array(array_info) => { +// if let Some(table) = toml_value.as_array() { +// let ReflectMut::Array(array) = field_mut.reflect_mut() else { +// warn!("Preferences: Expected Array"); +// continue; +// }; +// load_array(array, array_info, table); +// } +// } +// TypeInfo::Enum(enum_info) => { +// let ReflectMut::Enum(enm) = field_mut.reflect_mut() else { +// warn!("Preferences: Expected Enum"); +// continue; +// }; + +// load_enum(enm, enum_info, toml_value); +// } +// TypeInfo::TupleStruct(tuple_struct_info) => { +// let ReflectMut::TupleStruct(tuple_struct) = field_mut.reflect_mut() else { +// warn!("Preferences: Expected TupleStruct"); +// continue; +// }; +// if let Some(array_value) = toml_value.as_array() { +// load_tuple_struct(tuple_struct, tuple_struct_info, array_value); +// } +// } +// _ => { +// warn!( +// "Preferences: Unsupported type: {:?}", +// field_mut.get_represented_type_info() +// ); +// } +// } +// } +// } diff --git a/crates/bevy_editor_settings/src/file_system/de/tuple.rs b/crates/bevy_editor_settings/src/file_system/de/tuple.rs new file mode 100644 index 00000000..5bf15e33 --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/tuple.rs @@ -0,0 +1,79 @@ +use bevy::{ + prelude::*, + reflect::{ReflectMut, Tuple, TupleStruct, TupleStructInfo, TypeInfo}, +}; + +use super::{structs::LoadStruct, tuple_utils::TupleLikeInfo, value::LoadValue, LoadStructure}; + +pub struct LoadTuple<'a> { + pub tuple_info: &'a dyn TupleLikeInfo, + pub table: &'a toml::value::Array, + pub tuple: &'a mut dyn Tuple, +} + +impl<'a> LoadTuple<'a> { + pub fn load_tuple(self) { + for i in 0..self.tuple_info.field_len() { + let Some(toml_value) = self.table.get(i) else { + continue; + }; + + let field_mut = self.tuple.field_mut(i).unwrap(); + let field_attrs = self.tuple_info.field_at(i).unwrap().custom_attributes(); + + LoadStructure { + type_info: field_mut.get_represented_type_info().unwrap(), + table: toml_value, + structure: field_mut, + custom_attributes: Some(field_attrs), + } + .load(); + } + } +} + +#[cfg(test)] +mod tests { + use bevy::reflect::DynamicTyped as _; + + use super::*; + + fn tuple_test_toml() -> toml::Value { + toml::Value::Array(vec![toml::Value::Integer(1), toml::Value::Integer(2)]) + } + + #[tracing_test::traced_test] + #[test] + fn load_tuple() { + let mut tuple = (0, 0); + + let toml_value = tuple_test_toml(); + LoadTuple { + tuple_info: tuple.reflect_type_info().as_tuple().unwrap(), + table: toml_value.as_array().unwrap(), + tuple: &mut tuple, + } + .load_tuple(); + assert_eq!(tuple, (1, 2)); + } + + fn tuple_struct_struct_toml() -> toml::Value { + toml::Value::Array(vec![tuple_test_toml(), tuple_test_toml()]) + } + + #[tracing_test::traced_test] + #[test] + fn load_tuple_struct_struct() { + let mut tuple = ((0, 0), (0, 0)); + + let toml_value = tuple_struct_struct_toml(); + LoadTuple { + tuple_info: tuple.reflect_type_info().as_tuple().unwrap(), + table: toml_value.as_array().unwrap(), + tuple: &mut tuple, + } + .load_tuple(); + + assert_eq!(tuple, ((1, 2), (1, 2))); + } +} diff --git a/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs b/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs new file mode 100644 index 00000000..02bedf38 --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs @@ -0,0 +1,89 @@ +use bevy::{ + prelude::*, + reflect::{ReflectMut, TupleStruct, TupleStructInfo, TypeInfo}, +}; + +use super::{structs::LoadStruct, tuple_utils::TupleLikeInfo, value::LoadValue, LoadStructure}; + +pub struct LoadTupleStruct<'a> { + pub tuple_struct_info: &'a dyn TupleLikeInfo, + pub table: &'a toml::value::Array, + pub tuple_struct: &'a mut dyn TupleStruct, +} + +impl<'a> LoadTupleStruct<'a> { + pub fn load_tuple_struct(self) { + for i in 0..self.tuple_struct_info.field_len() { + let Some(toml_value) = self.table.get(i) else { + continue; + }; + + let field_mut = self.tuple_struct.field_mut(i).unwrap(); + let field_attrs = self + .tuple_struct_info + .field_at(i) + .unwrap() + .custom_attributes(); + + LoadStructure { + type_info: field_mut.get_represented_type_info().unwrap(), + table: toml_value, + structure: field_mut, + custom_attributes: Some(field_attrs), + } + .load(); + } + } +} + +#[cfg(test)] +mod tests { + use bevy::reflect::DynamicTyped as _; + + use super::*; + + #[derive(Debug, Clone, PartialEq, Reflect, Default)] + struct TupleStructTest(u32, u32); + + fn tuple_struct_test_toml() -> toml::Value { + toml::Value::Array(vec![toml::Value::Integer(1), toml::Value::Integer(2)]) + } + + #[tracing_test::traced_test] + #[test] + fn load_tuple_struct() { + let mut tuple_struct = TupleStructTest::default(); + + let toml_value = tuple_struct_test_toml(); + LoadTupleStruct { + tuple_struct_info: tuple_struct.reflect_type_info().as_tuple_struct().unwrap(), + table: toml_value.as_array().unwrap(), + tuple_struct: &mut tuple_struct, + } + .load_tuple_struct(); + assert_eq!(tuple_struct, TupleStructTest(1, 2)); + } + + #[derive(Debug, Clone, PartialEq, Reflect, Default)] + struct TupleStructStruct(TupleStructTest); + + fn tuple_struct_struct_toml() -> toml::Value { + toml::Value::Array(vec![tuple_struct_test_toml()]) + } + + #[tracing_test::traced_test] + #[test] + fn load_tuple_struct_struct() { + let mut tuple_struct = TupleStructStruct::default(); + + let toml_value = tuple_struct_struct_toml(); + LoadTupleStruct { + tuple_struct_info: tuple_struct.reflect_type_info().as_tuple_struct().unwrap(), + table: toml_value.as_array().unwrap(), + tuple_struct: &mut tuple_struct, + } + .load_tuple_struct(); + + assert_eq!(tuple_struct, TupleStructStruct(TupleStructTest(1, 2))); + } +} diff --git a/crates/bevy_editor_settings/src/file_system/de/tuple_utils.rs b/crates/bevy_editor_settings/src/file_system/de/tuple_utils.rs new file mode 100644 index 00000000..f3b1aa99 --- /dev/null +++ b/crates/bevy_editor_settings/src/file_system/de/tuple_utils.rs @@ -0,0 +1,36 @@ +use bevy::reflect::{TupleInfo, TupleStructInfo, TupleVariantInfo, UnnamedField}; + +pub(super) trait TupleLikeInfo { + fn field_at(&self, index: usize) -> Option<&UnnamedField>; + fn field_len(&self) -> usize; +} + +impl TupleLikeInfo for TupleInfo { + fn field_len(&self) -> usize { + Self::field_len(self) + } + + fn field_at(&self, index: usize) -> Option<&UnnamedField> { + Self::field_at(self, index) + } +} + +impl TupleLikeInfo for TupleStructInfo { + fn field_len(&self) -> usize { + Self::field_len(self) + } + + fn field_at(&self, index: usize) -> Option<&UnnamedField> { + Self::field_at(self, index) + } +} + +impl TupleLikeInfo for TupleVariantInfo { + fn field_len(&self) -> usize { + Self::field_len(self) + } + + fn field_at(&self, index: usize) -> Option<&UnnamedField> { + Self::field_at(self, index) + } +} diff --git a/crates/bevy_editor_settings/src/file_system/de/value.rs b/crates/bevy_editor_settings/src/file_system/de/value.rs index 464e5f1c..6588d3dd 100644 --- a/crates/bevy_editor_settings/src/file_system/de/value.rs +++ b/crates/bevy_editor_settings/src/file_system/de/value.rs @@ -1,8 +1,8 @@ use bevy::prelude::warn; -use bevy::reflect::{PartialReflect, ValueInfo}; +use bevy::reflect::{PartialReflect, Type}; pub struct LoadValue<'a> { - pub value_info: &'a ValueInfo, + pub value_info: &'a Type, pub toml_value: &'a toml::Value, pub value: &'a mut dyn PartialReflect, } @@ -80,7 +80,7 @@ mod tests { let mut value = "".to_string(); let toml_value = &toml::Value::String("Hello".to_string()); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -94,7 +94,7 @@ mod tests { let mut value = 0.0; let toml_value = &toml::Value::Float(3.14); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -108,7 +108,7 @@ mod tests { let mut value = 0.0_f32; let toml_value = &toml::Value::Float(3.14); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -122,7 +122,7 @@ mod tests { let mut value = false; let toml_value = &toml::Value::Boolean(true); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -136,7 +136,7 @@ mod tests { let mut value = 0.0; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -150,7 +150,7 @@ mod tests { let mut value = 0.0_f32; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -158,14 +158,13 @@ mod tests { assert_eq!(value, 42.0); } - #[tracing_test::traced_test] #[test] fn load_int() { let mut value = 0; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -179,7 +178,7 @@ mod tests { let mut value = 0_u8; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -193,7 +192,7 @@ mod tests { let mut value = 0_u16; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -207,7 +206,7 @@ mod tests { let mut value = 0_u32; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -221,7 +220,7 @@ mod tests { let mut value = 0_u64; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -235,7 +234,7 @@ mod tests { let mut value = 0_i8; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -249,7 +248,7 @@ mod tests { let mut value = 0_i16; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -263,7 +262,7 @@ mod tests { let mut value = 0_i32; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } @@ -277,13 +276,11 @@ mod tests { let mut value = 0_i64; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap(), + value_info: value.reflect_type_info().as_value().unwrap().ty(), toml_value, value: &mut value, } .load_value(); assert_eq!(value, 42); } - } - diff --git a/crates/bevy_editor_settings/src/file_system/mod.rs b/crates/bevy_editor_settings/src/file_system/mod.rs index 088b9ba2..9c7c4a1c 100644 --- a/crates/bevy_editor_settings/src/file_system/mod.rs +++ b/crates/bevy_editor_settings/src/file_system/mod.rs @@ -1,10 +1,11 @@ use std::path::PathBuf; use bevy::log::{error, warn}; +use de::{load_preferences, load_toml_file}; -use crate::{GlobalSettingsPath, SettingsType}; +pub mod de; -pub mod load; +use crate::{GlobalSettingsPath, SettingsType}; const SETTINGS_BASE_DIR: &str = "bevy_editor"; @@ -23,7 +24,7 @@ pub fn global_settings_path() -> Option { } pub fn load_settings(app: &mut bevy::app::App) { - if app.world().get_resource::().is_some() { + if app.world().get_resource::().is_some() { load_global_settings(app.world_mut()); } load_project_settings(app.world_mut()); @@ -31,23 +32,20 @@ pub fn load_settings(app: &mut bevy::app::App) { pub fn load_project_settings(world: &mut bevy::prelude::World) { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let Ok(file) = load::load_toml_file(path.join("Bevy.toml")) else { + let Ok(file) = load_toml_file(path.join("Bevy.toml")) else { warn!("Failed to load project settings"); return; }; - load::load_preferences(world, file, SettingsType::Project); + load_preferences(world, file, SettingsType::Project); } pub fn load_global_settings(world: &mut bevy::prelude::World) { let path = &world.get_resource::().unwrap().0; - let Ok(file) = load::load_toml_file(path.join("global.toml")) else { + let Ok(file) = load_toml_file(path.join("global.toml")) else { warn!("Failed to load global settings"); return; }; - load::load_preferences(world, file, SettingsType::Global); - + load_preferences(world, file, SettingsType::Global); } - - From 66bf1c7da39af777ac9370a5810724c5a33c02bf Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 05:59:01 +1300 Subject: [PATCH 23/39] add comment --- crates/bevy_editor_settings/src/file_system/de/enums.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/enums.rs b/crates/bevy_editor_settings/src/file_system/de/enums.rs index 687391ab..78da54aa 100644 --- a/crates/bevy_editor_settings/src/file_system/de/enums.rs +++ b/crates/bevy_editor_settings/src/file_system/de/enums.rs @@ -65,10 +65,11 @@ impl<'a> LoadEnum<'a> { ); self.enm.apply(&dyn_enum); } - VariantInfo::Tuple(tuple_variant_info) - if tuple_variant_info.field_len() == 1 && !value.is_array() => { - // TODO: This is a hack to support single field tuple structs - } + // TODO: handle single field tuple structs differently + // VariantInfo::Tuple(tuple_variant_info) + // if tuple_variant_info.field_len() == 1 && !value.is_array() => { + // // TODO: This is a hack to support single field tuple structs + // } VariantInfo::Tuple(tuple_variant_info) => { let Some(array) = value.as_array() else { warn!("Preferences: Expected Array"); From c4758dc5075e610c79f83bfe27671ab6e6587895 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 06:03:34 +1300 Subject: [PATCH 24/39] add default enum value --- .../bevy_editor_settings/src/file_system/de/default.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/default.rs b/crates/bevy_editor_settings/src/file_system/de/default.rs index cf310000..46af18c6 100644 --- a/crates/bevy_editor_settings/src/file_system/de/default.rs +++ b/crates/bevy_editor_settings/src/file_system/de/default.rs @@ -1,5 +1,5 @@ use bevy::reflect::{ - ArrayInfo, DynamicArray, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple, ListInfo, MapInfo, PartialReflect, SetInfo, Type, TypeInfo, ValueInfo + ArrayInfo, DynamicArray, DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple, EnumInfo, ListInfo, MapInfo, PartialReflect, SetInfo, Type, TypeInfo, ValueInfo }; use super::{struct_utils::StructLikeInfo, tuple_utils::TupleLikeInfo}; @@ -28,10 +28,16 @@ pub fn default_data_type(type_info: &TypeInfo) -> Option TypeInfo::Set(type_info) => { default_set(type_info).map(|s| Box::new(s) as Box) } - TypeInfo::Enum(_) => None, + TypeInfo::Enum(type_info) => { + default_enum(type_info).map(|e| Box::new(e) as Box) + } } } +pub fn default_enum(_type_info: &EnumInfo) -> Option { + Some(DynamicEnum::default()) +} + pub fn default_set(_type_info: &SetInfo) -> Option { let output = DynamicSet::default(); Some(output) From 55dbc50ed7e5161b00b38286fc532a44ecbbde64 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 06:03:51 +1300 Subject: [PATCH 25/39] fmt --- .../src/file_system/de/default.rs | 3 +- .../src/file_system/de/enums.rs | 8 ++-- .../src/file_system/de/list.rs | 8 +++- .../src/file_system/de/struct_utils.rs | 4 +- crates/bevy_editor_settings/src/lib.rs | 42 ++++++++++--------- .../bevy_editor_settings/src/local_prefs.rs | 2 - 6 files changed, 37 insertions(+), 30 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/default.rs b/crates/bevy_editor_settings/src/file_system/de/default.rs index 46af18c6..86fe24ea 100644 --- a/crates/bevy_editor_settings/src/file_system/de/default.rs +++ b/crates/bevy_editor_settings/src/file_system/de/default.rs @@ -1,5 +1,6 @@ use bevy::reflect::{ - ArrayInfo, DynamicArray, DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple, EnumInfo, ListInfo, MapInfo, PartialReflect, SetInfo, Type, TypeInfo, ValueInfo + ArrayInfo, DynamicArray, DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, + DynamicTuple, EnumInfo, ListInfo, MapInfo, PartialReflect, SetInfo, Type, TypeInfo, ValueInfo, }; use super::{struct_utils::StructLikeInfo, tuple_utils::TupleLikeInfo}; diff --git a/crates/bevy_editor_settings/src/file_system/de/enums.rs b/crates/bevy_editor_settings/src/file_system/de/enums.rs index 78da54aa..71163bb1 100644 --- a/crates/bevy_editor_settings/src/file_system/de/enums.rs +++ b/crates/bevy_editor_settings/src/file_system/de/enums.rs @@ -123,8 +123,6 @@ mod tests { Variant4(u32, u32), } - - #[tracing_test::traced_test] #[test] fn load_enum_unit() { @@ -141,7 +139,6 @@ mod tests { assert_eq!(enum_test, TestEnum::Variant1); } - fn enum_test_toml() -> toml::Value { let mut table = toml::value::Table::new(); let mut var3 = toml::value::Table::new(); @@ -175,7 +172,10 @@ mod tests { fn enum_test_tuple_toml() -> toml::Value { let mut table = toml::value::Table::new(); - table.insert("Variant4".to_string(), toml::Value::Array(vec![toml::Value::Integer(1), toml::Value::Integer(2)])); + table.insert( + "Variant4".to_string(), + toml::Value::Array(vec![toml::Value::Integer(1), toml::Value::Integer(2)]), + ); toml::Value::Table(table) } } diff --git a/crates/bevy_editor_settings/src/file_system/de/list.rs b/crates/bevy_editor_settings/src/file_system/de/list.rs index 29a6c165..5b41d566 100644 --- a/crates/bevy_editor_settings/src/file_system/de/list.rs +++ b/crates/bevy_editor_settings/src/file_system/de/list.rs @@ -91,7 +91,13 @@ mod tests { list.list.push(1); list.list.push(2); - let attrs = list.reflect_type_info().as_struct().unwrap().field_at(0).unwrap().custom_attributes(); + let attrs = list + .reflect_type_info() + .as_struct() + .unwrap() + .field_at(0) + .unwrap() + .custom_attributes(); let toml_value = list_test_toml(); LoadList { diff --git a/crates/bevy_editor_settings/src/file_system/de/struct_utils.rs b/crates/bevy_editor_settings/src/file_system/de/struct_utils.rs index 4ae8d0ee..e71122b9 100644 --- a/crates/bevy_editor_settings/src/file_system/de/struct_utils.rs +++ b/crates/bevy_editor_settings/src/file_system/de/struct_utils.rs @@ -14,7 +14,7 @@ impl StructLikeInfo for StructInfo { Self::field(self, name) } - fn field_at(&self, index: usize) -> Option<&NamedField> { + fn field_at(&self, index: usize) -> Option<&NamedField> { Self::field_at(self, index) } @@ -32,7 +32,7 @@ impl StructLikeInfo for StructVariantInfo { Self::field(self, name) } - fn field_at(&self, index: usize) -> Option<&NamedField> { + fn field_at(&self, index: usize) -> Option<&NamedField> { Self::field_at(self, index) } diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index 8b457c94..93b050d5 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -3,8 +3,8 @@ use bevy::prelude::*; mod file_system; -pub mod modals; mod local_prefs; +pub mod modals; /// Annotation for a type to show which type of settings it belongs to. #[derive(Debug, Clone, PartialEq, Eq, Reflect)] @@ -110,7 +110,6 @@ mod tests { assert_eq!(settings.age, 25); } - #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] struct ListTesting { @@ -136,9 +135,7 @@ mod tests { list: vec!["one".to_string(), "two".to_string()], }); - app.insert_resource(ListTestingAppend { - list: vec![1, 2], - }); + app.insert_resource(ListTestingAppend { list: vec![1, 2] }); file_system::load_project_settings(app.world_mut()); @@ -151,7 +148,6 @@ mod tests { assert_eq!(settings.list, vec![1, 2, 3, 4]); } - #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] enum EnumTesting { @@ -200,7 +196,6 @@ mod tests { settings: vec![EnumTesting::One, EnumTesting::Two], }); - file_system::load_project_settings(app.world_mut()); let settings = app.world().get_resource::().unwrap(); @@ -209,20 +204,25 @@ mod tests { let settings = app.world().get_resource::().unwrap(); - assert_eq!(*settings, EnumSettings { - test1: EnumTestingField::Tuple("hello".to_string(), 42), - test2: EnumTestingField::Struct { - name: "four".to_string(), - age: 4, - }, - }); + assert_eq!( + *settings, + EnumSettings { + test1: EnumTestingField::Tuple("hello".to_string(), 42), + test2: EnumTestingField::Struct { + name: "four".to_string(), + age: 4, + }, + } + ); let settings = app.world().get_resource::().unwrap(); - assert_eq!(settings.settings, vec![EnumTesting::One, EnumTesting::Two, EnumTesting::Three]); + assert_eq!( + settings.settings, + vec![EnumTesting::One, EnumTesting::Two, EnumTesting::Three] + ); } - #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] struct TupleStruct(i32, String); @@ -254,9 +254,11 @@ mod tests { let settings = app.world().get_resource::().unwrap(); - assert_eq!(*settings, StructWithTuple { - tuple: TupleStruct(3, "three".to_string()), - }); + assert_eq!( + *settings, + StructWithTuple { + tuple: TupleStruct(3, "three".to_string()), + } + ); } - } diff --git a/crates/bevy_editor_settings/src/local_prefs.rs b/crates/bevy_editor_settings/src/local_prefs.rs index f23d8c3d..155d7840 100644 --- a/crates/bevy_editor_settings/src/local_prefs.rs +++ b/crates/bevy_editor_settings/src/local_prefs.rs @@ -2,8 +2,6 @@ use bevy::{prelude::Resource, reflect::Reflect}; use crate::{SettingsTags, SettingsType}; - - #[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] #[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] /// Settings for building the project From df744ebe7f8b3b22ae5160ebfbd8e62da085b707 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 06:04:12 +1300 Subject: [PATCH 26/39] fix typo --- crates/bevy_editor_settings/Bevy.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_editor_settings/Bevy.toml b/crates/bevy_editor_settings/Bevy.toml index 785b32db..8653be26 100644 --- a/crates/bevy_editor_settings/Bevy.toml +++ b/crates/bevy_editor_settings/Bevy.toml @@ -31,7 +31,7 @@ age = 4 settings = ["Three"] # top level tuple struct -# adds the fields field to the tuple sturct. this is ONLY done for a top level tuple struct +# adds the fields field to the tuple struct. this is ONLY done for a top level tuple struct [tuple_struct] fields = [2, "two"] From fb20882ac7a0e03fb70609b1edd00c7cc76c93e7 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 18:32:35 +1300 Subject: [PATCH 27/39] cleanup --- .../src/file_system/de/default.rs | 6 +-- .../src/file_system/de/enums.rs | 2 +- .../src/file_system/de/mod.rs | 12 ++---- .../src/file_system/de/value.rs | 30 +++++++-------- crates/bevy_editor_settings/src/lib.rs | 12 ------ .../bevy_editor_settings/src/local_prefs.rs | 28 -------------- crates/bevy_editor_settings/src/modals/mod.rs | 4 -- .../bevy_editor_settings/src/modals/user.rs | 7 ---- .../src/modals/workspace.rs | 37 ------------------- 9 files changed, 23 insertions(+), 115 deletions(-) delete mode 100644 crates/bevy_editor_settings/src/local_prefs.rs delete mode 100644 crates/bevy_editor_settings/src/modals/mod.rs delete mode 100644 crates/bevy_editor_settings/src/modals/user.rs delete mode 100644 crates/bevy_editor_settings/src/modals/workspace.rs diff --git a/crates/bevy_editor_settings/src/file_system/de/default.rs b/crates/bevy_editor_settings/src/file_system/de/default.rs index 86fe24ea..197b7ca4 100644 --- a/crates/bevy_editor_settings/src/file_system/de/default.rs +++ b/crates/bevy_editor_settings/src/file_system/de/default.rs @@ -1,13 +1,13 @@ use bevy::reflect::{ - ArrayInfo, DynamicArray, DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, - DynamicTuple, EnumInfo, ListInfo, MapInfo, PartialReflect, SetInfo, Type, TypeInfo, ValueInfo, + ArrayInfo, DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple, + EnumInfo, ListInfo, MapInfo, PartialReflect, SetInfo, Type, TypeInfo, }; use super::{struct_utils::StructLikeInfo, tuple_utils::TupleLikeInfo}; pub fn default_data_type(type_info: &TypeInfo) -> Option> { match type_info { - TypeInfo::Value(value_info) => default_value(value_info.ty()), + TypeInfo::Opaque(opaque_info) => default_value(opaque_info.ty()), TypeInfo::Struct(struct_info) => { default_struct(struct_info).map(|s| Box::new(s) as Box) } diff --git a/crates/bevy_editor_settings/src/file_system/de/enums.rs b/crates/bevy_editor_settings/src/file_system/de/enums.rs index 71163bb1..d37fed64 100644 --- a/crates/bevy_editor_settings/src/file_system/de/enums.rs +++ b/crates/bevy_editor_settings/src/file_system/de/enums.rs @@ -65,7 +65,7 @@ impl<'a> LoadEnum<'a> { ); self.enm.apply(&dyn_enum); } - // TODO: handle single field tuple structs differently + // TODO: handle single field tuple structs differently this could just be a raw value instead of an array // VariantInfo::Tuple(tuple_variant_info) // if tuple_variant_info.field_len() == 1 && !value.is_array() => { // // TODO: This is a hack to support single field tuple structs diff --git a/crates/bevy_editor_settings/src/file_system/de/mod.rs b/crates/bevy_editor_settings/src/file_system/de/mod.rs index c0610723..f61fe48f 100644 --- a/crates/bevy_editor_settings/src/file_system/de/mod.rs +++ b/crates/bevy_editor_settings/src/file_system/de/mod.rs @@ -14,11 +14,7 @@ mod value; use array::LoadArray; use bevy::{ prelude::*, - reflect::{ - attributes::CustomAttributes, Array, ArrayInfo, DynamicEnum, DynamicStruct, DynamicTuple, - DynamicVariant, Enum, EnumInfo, List, ListInfo, ReflectFromPtr, ReflectMut, StructInfo, - TupleStructInfo, TypeInfo, ValueInfo, VariantInfo, - }, + reflect::{attributes::CustomAttributes, ReflectFromPtr, ReflectMut, TypeInfo}, }; use enums::LoadEnum; use heck::ToSnakeCase; @@ -30,7 +26,7 @@ use tuple::LoadTuple; use tuple_struct::LoadTupleStruct; use value::LoadValue; -use crate::{MergeStrategy, SettingsTags, SettingsType}; +use crate::SettingsType; /// Errors that can occur when loading a TOML file. #[derive(Debug, thiserror::Error)] @@ -58,9 +54,9 @@ pub struct LoadStructure<'a> { impl<'a> LoadStructure<'a> { pub fn load(self) { match self.type_info { - TypeInfo::Value(value_info) => { + TypeInfo::Opaque(opaque_info) => { LoadValue { - value_info: value_info.ty(), + value_info: opaque_info.ty(), toml_value: self.table, value: self.structure, } diff --git a/crates/bevy_editor_settings/src/file_system/de/value.rs b/crates/bevy_editor_settings/src/file_system/de/value.rs index 6588d3dd..ed890c23 100644 --- a/crates/bevy_editor_settings/src/file_system/de/value.rs +++ b/crates/bevy_editor_settings/src/file_system/de/value.rs @@ -80,7 +80,7 @@ mod tests { let mut value = "".to_string(); let toml_value = &toml::Value::String("Hello".to_string()); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -94,7 +94,7 @@ mod tests { let mut value = 0.0; let toml_value = &toml::Value::Float(3.14); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -108,7 +108,7 @@ mod tests { let mut value = 0.0_f32; let toml_value = &toml::Value::Float(3.14); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -122,7 +122,7 @@ mod tests { let mut value = false; let toml_value = &toml::Value::Boolean(true); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -136,7 +136,7 @@ mod tests { let mut value = 0.0; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -150,7 +150,7 @@ mod tests { let mut value = 0.0_f32; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -164,7 +164,7 @@ mod tests { let mut value = 0; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -178,7 +178,7 @@ mod tests { let mut value = 0_u8; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -192,7 +192,7 @@ mod tests { let mut value = 0_u16; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -206,7 +206,7 @@ mod tests { let mut value = 0_u32; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -220,7 +220,7 @@ mod tests { let mut value = 0_u64; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -234,7 +234,7 @@ mod tests { let mut value = 0_i8; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -248,7 +248,7 @@ mod tests { let mut value = 0_i16; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -262,7 +262,7 @@ mod tests { let mut value = 0_i32; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } @@ -276,7 +276,7 @@ mod tests { let mut value = 0_i64; let toml_value = &toml::Value::Integer(42); LoadValue { - value_info: value.reflect_type_info().as_value().unwrap().ty(), + value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index 93b050d5..e57b82ac 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -3,8 +3,6 @@ use bevy::prelude::*; mod file_system; -mod local_prefs; -pub mod modals; /// Annotation for a type to show which type of settings it belongs to. #[derive(Debug, Clone, PartialEq, Eq, Reflect)] @@ -49,16 +47,6 @@ pub struct GlobalSettingsPath(pub std::path::PathBuf); /// This plugin loads the workspace settings, user settings, and project settings. pub struct EditorSettingsPlugin; -#[derive(Debug, Clone, PartialEq, Eq, Resource, Reflect)] -/// Represents the settings for the editor. -/// This includes workspace settings, user settings, and project settings. -pub struct Settings { - /// Settings for the workspace - pub workspace_settings: modals::workspace::WorkspaceSettings, - /// Settings for the user - pub user_settings: modals::user::UserSettings, -} - impl Plugin for EditorSettingsPlugin { fn build(&self, app: &mut App) { match file_system::global_settings_path() { diff --git a/crates/bevy_editor_settings/src/local_prefs.rs b/crates/bevy_editor_settings/src/local_prefs.rs deleted file mode 100644 index 155d7840..00000000 --- a/crates/bevy_editor_settings/src/local_prefs.rs +++ /dev/null @@ -1,28 +0,0 @@ -use bevy::{prelude::Resource, reflect::Reflect}; - -use crate::{SettingsTags, SettingsType}; - -#[derive(Debug, Clone, PartialEq, Eq, Reflect, Resource)] -#[reflect(@SettingsType::Project, @SettingsTags(vec!["basic", "settings", "testing"]))] -/// Settings for building the project -pub struct Build { - /// The Command for building the project in debug mode - debug: String, - /// The Command for building the project in release mode - release: String, - /// The Command for running the project in debug mode - run_debug: String, - /// The Command for running the project in release mode - run_release: String, -} - -impl Default for Build { - fn default() -> Self { - Self { - debug: "cargo build".to_string(), - release: "cargo build --release".to_string(), - run_debug: "cargo run".to_string(), - run_release: "cargo run --release".to_string(), - } - } -} diff --git a/crates/bevy_editor_settings/src/modals/mod.rs b/crates/bevy_editor_settings/src/modals/mod.rs deleted file mode 100644 index e9d27ece..00000000 --- a/crates/bevy_editor_settings/src/modals/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Modals for the editor settings. - -pub mod user; -pub mod workspace; diff --git a/crates/bevy_editor_settings/src/modals/user.rs b/crates/bevy_editor_settings/src/modals/user.rs deleted file mode 100644 index c714dc50..00000000 --- a/crates/bevy_editor_settings/src/modals/user.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! this is for the user to override workspace settings - -use bevy::reflect::Reflect; - -#[derive(Debug, Clone, PartialEq, Eq, Reflect)] -/// Settings for the user -pub struct UserSettings {} diff --git a/crates/bevy_editor_settings/src/modals/workspace.rs b/crates/bevy_editor_settings/src/modals/workspace.rs deleted file mode 100644 index 9161390f..00000000 --- a/crates/bevy_editor_settings/src/modals/workspace.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! Workspace settings - -use bevy::reflect::Reflect; - -#[derive(Debug, Clone, PartialEq, Eq, Reflect)] -/// Settings for the entire workspace -/// This should be in the root of your project -pub struct WorkspaceSettings { - /// Settings for the editor per workspace - pub editor: String, - /// Settings for building the project - pub build: Build, -} - -#[derive(Debug, Clone, PartialEq, Eq, Reflect)] -/// Settings for building the project -pub struct Build { - /// The Command for building the project in debug mode - debug: String, - /// The Command for building the project in release mode - release: String, - /// The Command for running the project in debug mode - run_debug: String, - /// The Command for running the project in release mode - run_release: String, -} - -impl Default for Build { - fn default() -> Self { - Self { - debug: "cargo build".to_string(), - release: "cargo build --release".to_string(), - run_debug: "cargo run".to_string(), - run_release: "cargo run --release".to_string(), - } - } -} From fdae523f78a37599cf57707914166b656411dcf9 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 18:33:30 +1300 Subject: [PATCH 28/39] cargo fix --- crates/bevy_editor_settings/src/file_system/de/array.rs | 2 +- crates/bevy_editor_settings/src/file_system/de/enums.rs | 4 ++-- crates/bevy_editor_settings/src/file_system/de/map.rs | 2 +- crates/bevy_editor_settings/src/file_system/de/set.rs | 7 ++----- crates/bevy_editor_settings/src/file_system/de/structs.rs | 7 ++----- crates/bevy_editor_settings/src/file_system/de/tuple.rs | 4 ++-- .../src/file_system/de/tuple_struct.rs | 4 ++-- crates/bevy_editor_settings/src/file_system/mod.rs | 2 +- 8 files changed, 13 insertions(+), 19 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/array.rs b/crates/bevy_editor_settings/src/file_system/de/array.rs index 44ad2ea1..c4f131a5 100644 --- a/crates/bevy_editor_settings/src/file_system/de/array.rs +++ b/crates/bevy_editor_settings/src/file_system/de/array.rs @@ -42,7 +42,7 @@ impl<'a> LoadArray<'a> { #[cfg(test)] mod tests { - use bevy::reflect::{DynamicTyped as _, Reflect}; + use bevy::reflect::DynamicTyped as _; use super::*; diff --git a/crates/bevy_editor_settings/src/file_system/de/enums.rs b/crates/bevy_editor_settings/src/file_system/de/enums.rs index d37fed64..09bd93a4 100644 --- a/crates/bevy_editor_settings/src/file_system/de/enums.rs +++ b/crates/bevy_editor_settings/src/file_system/de/enums.rs @@ -1,12 +1,12 @@ use bevy::{ prelude::*, reflect::{ - DynamicEnum, DynamicStruct, DynamicTuple, DynamicVariant, Enum, EnumInfo, TypeInfo, + DynamicEnum, DynamicVariant, Enum, EnumInfo, VariantInfo, }, }; -use super::{structs::LoadStruct, tuple::LoadTuple, tuple_struct::LoadTupleStruct, LoadStructure}; +use super::{structs::LoadStruct, tuple::LoadTuple}; pub struct LoadEnum<'a> { pub enum_info: &'a EnumInfo, diff --git a/crates/bevy_editor_settings/src/file_system/de/map.rs b/crates/bevy_editor_settings/src/file_system/de/map.rs index bd968e5d..db92ce48 100644 --- a/crates/bevy_editor_settings/src/file_system/de/map.rs +++ b/crates/bevy_editor_settings/src/file_system/de/map.rs @@ -49,7 +49,7 @@ impl<'a> LoadMap<'a> { #[cfg(test)] mod tests { - use bevy::reflect::{DynamicTyped as _, Reflect, Struct}; + use bevy::reflect::DynamicTyped as _; use super::*; diff --git a/crates/bevy_editor_settings/src/file_system/de/set.rs b/crates/bevy_editor_settings/src/file_system/de/set.rs index 273c96af..63b6e342 100644 --- a/crates/bevy_editor_settings/src/file_system/de/set.rs +++ b/crates/bevy_editor_settings/src/file_system/de/set.rs @@ -1,7 +1,4 @@ -use bevy::{ - prelude::warn, - reflect::{Set, SetInfo}, -}; +use bevy::reflect::{Set, SetInfo}; use super::value::LoadValue; @@ -30,7 +27,7 @@ impl<'a> LoadSet<'a> { #[cfg(test)] mod tests { - use bevy::reflect::{DynamicTyped as _, Struct, TypeInfo}; + use bevy::reflect::{DynamicTyped as _, TypeInfo}; use super::*; diff --git a/crates/bevy_editor_settings/src/file_system/de/structs.rs b/crates/bevy_editor_settings/src/file_system/de/structs.rs index 3bef7e48..f190a1bd 100644 --- a/crates/bevy_editor_settings/src/file_system/de/structs.rs +++ b/crates/bevy_editor_settings/src/file_system/de/structs.rs @@ -1,9 +1,6 @@ -use bevy::{ - prelude::warn, - reflect::{ReflectMut, Struct, TypeInfo}, -}; +use bevy::reflect::Struct; -use super::{struct_utils::StructLikeInfo, value::LoadValue, LoadStructure}; +use super::{struct_utils::StructLikeInfo, LoadStructure}; pub struct LoadStruct<'a> { pub struct_info: &'a dyn StructLikeInfo, diff --git a/crates/bevy_editor_settings/src/file_system/de/tuple.rs b/crates/bevy_editor_settings/src/file_system/de/tuple.rs index 5bf15e33..f6487567 100644 --- a/crates/bevy_editor_settings/src/file_system/de/tuple.rs +++ b/crates/bevy_editor_settings/src/file_system/de/tuple.rs @@ -1,9 +1,9 @@ use bevy::{ prelude::*, - reflect::{ReflectMut, Tuple, TupleStruct, TupleStructInfo, TypeInfo}, + reflect::{Tuple, TupleStruct}, }; -use super::{structs::LoadStruct, tuple_utils::TupleLikeInfo, value::LoadValue, LoadStructure}; +use super::{tuple_utils::TupleLikeInfo, LoadStructure}; pub struct LoadTuple<'a> { pub tuple_info: &'a dyn TupleLikeInfo, diff --git a/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs b/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs index 02bedf38..738107b4 100644 --- a/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs +++ b/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs @@ -1,9 +1,9 @@ use bevy::{ prelude::*, - reflect::{ReflectMut, TupleStruct, TupleStructInfo, TypeInfo}, + reflect::TupleStruct, }; -use super::{structs::LoadStruct, tuple_utils::TupleLikeInfo, value::LoadValue, LoadStructure}; +use super::{tuple_utils::TupleLikeInfo, LoadStructure}; pub struct LoadTupleStruct<'a> { pub tuple_struct_info: &'a dyn TupleLikeInfo, diff --git a/crates/bevy_editor_settings/src/file_system/mod.rs b/crates/bevy_editor_settings/src/file_system/mod.rs index 9c7c4a1c..560f7cd8 100644 --- a/crates/bevy_editor_settings/src/file_system/mod.rs +++ b/crates/bevy_editor_settings/src/file_system/mod.rs @@ -9,7 +9,7 @@ use crate::{GlobalSettingsPath, SettingsType}; const SETTINGS_BASE_DIR: &str = "bevy_editor"; -pub fn global_settings_path() -> Option { +pub fn global_settings_path() -> Option { let path = directories::BaseDirs::new()?; let config_dir = path.config_dir(); let path = config_dir.join(SETTINGS_BASE_DIR); From 80f9d019aed3b30a484b9c5e4398798319970e7a Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 18:38:03 +1300 Subject: [PATCH 29/39] add settings key --- .../src/file_system/de/mod.rs | 17 +++++++++++++---- crates/bevy_editor_settings/src/lib.rs | 4 ++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/mod.rs b/crates/bevy_editor_settings/src/file_system/de/mod.rs index f61fe48f..bddad321 100644 --- a/crates/bevy_editor_settings/src/file_system/de/mod.rs +++ b/crates/bevy_editor_settings/src/file_system/de/mod.rs @@ -26,7 +26,7 @@ use tuple::LoadTuple; use tuple_struct::LoadTupleStruct; use value::LoadValue; -use crate::SettingsType; +use crate::{SettingKey, SettingsType}; /// Errors that can occur when loading a TOML file. #[derive(Debug, thiserror::Error)] @@ -191,6 +191,7 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se match type_reg.type_info() { TypeInfo::Struct(struct_info) => { let s_type = struct_info.custom_attributes().get::(); + let toml_key = struct_info.custom_attributes().get::(); if let Some(s_type) = s_type { if settings_type != *s_type { continue; @@ -205,7 +206,9 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se panic!("Expected Struct"); }; - let name = strct.reflect_type_ident().unwrap().to_snake_case(); + let name = toml_key + .map(|key| key.0.to_string()) + .unwrap_or_else(|| strct.reflect_type_ident().unwrap().to_snake_case()); if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { LoadStruct { @@ -219,6 +222,7 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se } TypeInfo::Enum(enum_info) => { let s_type = enum_info.custom_attributes().get::(); + let toml_key = enum_info.custom_attributes().get::(); if let Some(s_type) = s_type { if settings_type != *s_type { continue; @@ -233,7 +237,9 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se panic!("Expected Struct"); }; - let name = enm.reflect_type_ident().unwrap().to_snake_case(); + let name = toml_key + .map(|key| key.0.to_string()) + .unwrap_or_else(|| enm.reflect_type_ident().unwrap().to_snake_case()); if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { if let Some(value) = table.get("variant") { @@ -249,6 +255,7 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se } TypeInfo::TupleStruct(tuple_struct_info) => { let s_type = tuple_struct_info.custom_attributes().get::(); + let toml_key = tuple_struct_info.custom_attributes().get::(); if let Some(s_type) = s_type { if settings_type != *s_type { continue; @@ -263,7 +270,9 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se panic!("Expected TupleStruct"); }; - let name = tuple_struct.reflect_type_ident().unwrap().to_snake_case(); + let name = toml_key.map(|key| key.0.to_string()).unwrap_or_else(|| { + tuple_struct.reflect_type_ident().unwrap().to_snake_case() + }); if let Some(table) = table.get(&name).and_then(|v| v.as_table()) { if let Some(array_value) = diff --git a/crates/bevy_editor_settings/src/lib.rs b/crates/bevy_editor_settings/src/lib.rs index e57b82ac..0fdf291e 100644 --- a/crates/bevy_editor_settings/src/lib.rs +++ b/crates/bevy_editor_settings/src/lib.rs @@ -39,6 +39,10 @@ pub enum MergeStrategy { /// Annotation for a type to add tags to the settings. these tags can be used to filter settings in the editor. pub struct SettingsTags(pub Vec<&'static str>); +#[derive(Debug, Clone, Reflect)] +/// Annotation for a type to add what key the setting should be stored under. if not set the snake case of the type name will be used. +pub struct SettingKey(pub &'static str); + #[derive(Resource)] /// Store the path for the global preferences directory. pub struct GlobalSettingsPath(pub std::path::PathBuf); From 1f033801905aa2728d50ee31bb012fa7d4b34b5c Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 18:40:07 +1300 Subject: [PATCH 30/39] dont use prelude --- crates/bevy_editor_settings/src/file_system/de/enums.rs | 9 +++------ crates/bevy_editor_settings/src/file_system/de/tuple.rs | 5 +---- .../src/file_system/de/tuple_struct.rs | 7 ++----- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/enums.rs b/crates/bevy_editor_settings/src/file_system/de/enums.rs index 09bd93a4..5ee00e78 100644 --- a/crates/bevy_editor_settings/src/file_system/de/enums.rs +++ b/crates/bevy_editor_settings/src/file_system/de/enums.rs @@ -1,9 +1,6 @@ use bevy::{ - prelude::*, - reflect::{ - DynamicEnum, DynamicVariant, Enum, EnumInfo, - VariantInfo, - }, + prelude::warn, + reflect::{DynamicEnum, DynamicVariant, Enum, EnumInfo, VariantInfo}, }; use super::{structs::LoadStruct, tuple::LoadTuple}; @@ -109,7 +106,7 @@ impl<'a> LoadEnum<'a> { #[cfg(test)] mod tests { use super::*; - use bevy::reflect::DynamicTyped as _; + use bevy::reflect::{DynamicTyped as _, Reflect}; #[derive(Debug, Clone, PartialEq, Reflect, Default)] enum TestEnum { diff --git a/crates/bevy_editor_settings/src/file_system/de/tuple.rs b/crates/bevy_editor_settings/src/file_system/de/tuple.rs index f6487567..6e30aba0 100644 --- a/crates/bevy_editor_settings/src/file_system/de/tuple.rs +++ b/crates/bevy_editor_settings/src/file_system/de/tuple.rs @@ -1,7 +1,4 @@ -use bevy::{ - prelude::*, - reflect::{Tuple, TupleStruct}, -}; +use bevy::reflect::Tuple; use super::{tuple_utils::TupleLikeInfo, LoadStructure}; diff --git a/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs b/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs index 738107b4..c785c4b1 100644 --- a/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs +++ b/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs @@ -1,7 +1,4 @@ -use bevy::{ - prelude::*, - reflect::TupleStruct, -}; +use bevy::reflect::TupleStruct; use super::{tuple_utils::TupleLikeInfo, LoadStructure}; @@ -38,7 +35,7 @@ impl<'a> LoadTupleStruct<'a> { #[cfg(test)] mod tests { - use bevy::reflect::DynamicTyped as _; + use bevy::reflect::{DynamicTyped as _, Reflect}; use super::*; From 9de705776b50cd57782f167e796e78d4e2d473bd Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 18:47:44 +1300 Subject: [PATCH 31/39] fix pie warnings --- .../bevy_editor_settings/src/file_system/de/value.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/value.rs b/crates/bevy_editor_settings/src/file_system/de/value.rs index ed890c23..30f95e6f 100644 --- a/crates/bevy_editor_settings/src/file_system/de/value.rs +++ b/crates/bevy_editor_settings/src/file_system/de/value.rs @@ -92,28 +92,28 @@ mod tests { #[test] fn load_float_f64() { let mut value = 0.0; - let toml_value = &toml::Value::Float(3.14); + let toml_value = &toml::Value::Float(std::f64::consts::PI); LoadValue { value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } .load_value(); - assert_eq!(value, 3.14); + assert_eq!(value, std::f64::consts::PI); } #[tracing_test::traced_test] #[test] fn load_float_f32() { let mut value = 0.0_f32; - let toml_value = &toml::Value::Float(3.14); + let toml_value = &toml::Value::Float(std::f64::consts::PI); LoadValue { value_info: value.reflect_type_info().as_opaque().unwrap().ty(), toml_value, value: &mut value, } .load_value(); - assert_eq!(value, 3.14); + assert_eq!(value, std::f32::consts::PI); } #[tracing_test::traced_test] @@ -127,7 +127,7 @@ mod tests { value: &mut value, } .load_value(); - assert_eq!(value, true); + assert!(value); } #[tracing_test::traced_test] From a6f842444b1ae5063a172e526b967c2f3b02c3bb Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 18:49:03 +1300 Subject: [PATCH 32/39] fix pie --- .../src/file_system/de/structs.rs | 89 ++----------------- 1 file changed, 6 insertions(+), 83 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/structs.rs b/crates/bevy_editor_settings/src/file_system/de/structs.rs index f190a1bd..ae1e4140 100644 --- a/crates/bevy_editor_settings/src/file_system/de/structs.rs +++ b/crates/bevy_editor_settings/src/file_system/de/structs.rs @@ -53,8 +53,8 @@ mod tests { "string".to_string(), toml::Value::String("Hello".to_string()), ); - table.insert("float".to_string(), toml::Value::Float(3.14)); - table.insert("float32".to_string(), toml::Value::Float(3.14)); + table.insert("float".to_string(), toml::Value::Float(std::f64::consts::PI)); + table.insert("float32".to_string(), toml::Value::Float(std::f64::consts::PI)); table } @@ -75,8 +75,8 @@ mod tests { struct_info, Values { string: "Hello".to_string(), - float: 3.14, - float32: 3.14, + float: std::f64::consts::PI, + float32: std::f32::consts::PI, } ); } @@ -111,88 +111,11 @@ mod tests { StructWithStruct { values: Values { string: "Hello".to_string(), - float: 3.14, - float32: 3.14, + float: std::f64::consts::PI, + float32: std::f32::consts::PI, }, } ); } } -// fn load_struct( -// strct: &mut dyn Struct, -// struct_info: &'static S, -// table: &toml::Table, -// ) { -// let mut dynamic_struct = DynamicStruct::default(); -// for i in 0..struct_info.field_len() { -// let field = struct_info.field_at(i).unwrap(); -// let key = field.name(); - -// let Some(toml_value) = table.get(key) else { -// continue; -// }; - -// let field_mut = strct.field_at_mut(i).unwrap(); -// let field_attrs = field.custom_attributes(); -// match field.type_info().unwrap() { -// TypeInfo::Value(value_info) => { -// let value = load_value_boxed(value_info, toml_value); -// if let Some(value) = value { -// field_mut.apply(value.as_ref()); -// } -// // load_value(field_mut, value_info, value) -// } -// TypeInfo::Struct(struct_info) => { -// if let Some(table) = toml_value.as_table() { -// let ReflectMut::Struct(strct) = field_mut.reflect_mut() else { -// warn!("Preferences: Expected Struct"); -// continue; -// }; -// load_struct(strct, struct_info, table); -// } -// } -// TypeInfo::List(list_info) => { -// if let Some(table) = toml_value.as_array() { -// let ReflectMut::List(list) = field_mut.reflect_mut() else { -// warn!("Preferences: Expected List"); -// continue; -// }; -// load_list(list, list_info, table, field_attrs); -// } -// } -// TypeInfo::Array(array_info) => { -// if let Some(table) = toml_value.as_array() { -// let ReflectMut::Array(array) = field_mut.reflect_mut() else { -// warn!("Preferences: Expected Array"); -// continue; -// }; -// load_array(array, array_info, table); -// } -// } -// TypeInfo::Enum(enum_info) => { -// let ReflectMut::Enum(enm) = field_mut.reflect_mut() else { -// warn!("Preferences: Expected Enum"); -// continue; -// }; - -// load_enum(enm, enum_info, toml_value); -// } -// TypeInfo::TupleStruct(tuple_struct_info) => { -// let ReflectMut::TupleStruct(tuple_struct) = field_mut.reflect_mut() else { -// warn!("Preferences: Expected TupleStruct"); -// continue; -// }; -// if let Some(array_value) = toml_value.as_array() { -// load_tuple_struct(tuple_struct, tuple_struct_info, array_value); -// } -// } -// _ => { -// warn!( -// "Preferences: Unsupported type: {:?}", -// field_mut.get_represented_type_info() -// ); -// } -// } -// } -// } From 085fb9324ce2a9410d6fb5ee7476b4bc0db01f32 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 18:50:25 +1300 Subject: [PATCH 33/39] allow dea code for now --- crates/bevy_editor_settings/src/file_system/de/struct_utils.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/bevy_editor_settings/src/file_system/de/struct_utils.rs b/crates/bevy_editor_settings/src/file_system/de/struct_utils.rs index e71122b9..00e35f0e 100644 --- a/crates/bevy_editor_settings/src/file_system/de/struct_utils.rs +++ b/crates/bevy_editor_settings/src/file_system/de/struct_utils.rs @@ -3,9 +3,11 @@ use core::slice::Iter; /// A helper trait for accessing type information from struct-like types. pub(super) trait StructLikeInfo { + #[allow(dead_code)] fn field(&self, name: &str) -> Option<&NamedField>; fn field_at(&self, index: usize) -> Option<&NamedField>; fn field_len(&self) -> usize; + #[allow(dead_code)] fn iter_fields(&self) -> Iter<'_, NamedField>; } From 12fc7ed4f17a2a4856d669ebe902621971398c70 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 18:52:15 +1300 Subject: [PATCH 34/39] fix life times --- crates/bevy_editor_settings/src/file_system/de/array.rs | 2 +- crates/bevy_editor_settings/src/file_system/de/enums.rs | 2 +- crates/bevy_editor_settings/src/file_system/de/list.rs | 2 +- crates/bevy_editor_settings/src/file_system/de/map.rs | 2 +- crates/bevy_editor_settings/src/file_system/de/mod.rs | 2 +- crates/bevy_editor_settings/src/file_system/de/set.rs | 2 +- crates/bevy_editor_settings/src/file_system/de/structs.rs | 2 +- crates/bevy_editor_settings/src/file_system/de/tuple.rs | 2 +- crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs | 2 +- crates/bevy_editor_settings/src/file_system/de/value.rs | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/array.rs b/crates/bevy_editor_settings/src/file_system/de/array.rs index c4f131a5..9610a5e3 100644 --- a/crates/bevy_editor_settings/src/file_system/de/array.rs +++ b/crates/bevy_editor_settings/src/file_system/de/array.rs @@ -11,7 +11,7 @@ pub struct LoadArray<'a> { pub toml_array: &'a toml::value::Array, } -impl<'a> LoadArray<'a> { +impl LoadArray<'_> { pub fn load_array(self) { if self.toml_array.len() != self.array_info.capacity() { warn!( diff --git a/crates/bevy_editor_settings/src/file_system/de/enums.rs b/crates/bevy_editor_settings/src/file_system/de/enums.rs index 5ee00e78..99871e62 100644 --- a/crates/bevy_editor_settings/src/file_system/de/enums.rs +++ b/crates/bevy_editor_settings/src/file_system/de/enums.rs @@ -11,7 +11,7 @@ pub struct LoadEnum<'a> { pub enm: &'a mut dyn Enum, } -impl<'a> LoadEnum<'a> { +impl LoadEnum<'_>{ pub fn load_enum(self) { match self.toml_value { toml::Value::String(str_val) => { diff --git a/crates/bevy_editor_settings/src/file_system/de/list.rs b/crates/bevy_editor_settings/src/file_system/de/list.rs index 5b41d566..f14aec0e 100644 --- a/crates/bevy_editor_settings/src/file_system/de/list.rs +++ b/crates/bevy_editor_settings/src/file_system/de/list.rs @@ -14,7 +14,7 @@ pub struct LoadList<'a> { pub custom_attributes: Option<&'a CustomAttributes>, } -impl<'a> LoadList<'a> { +impl LoadList<'_> { pub fn load_list(self) { let merge_strategy = self .custom_attributes diff --git a/crates/bevy_editor_settings/src/file_system/de/map.rs b/crates/bevy_editor_settings/src/file_system/de/map.rs index db92ce48..d7de1f97 100644 --- a/crates/bevy_editor_settings/src/file_system/de/map.rs +++ b/crates/bevy_editor_settings/src/file_system/de/map.rs @@ -11,7 +11,7 @@ pub struct LoadMap<'a> { pub table: &'a toml::value::Table, } -impl<'a> LoadMap<'a> { +impl LoadMap<'_> { pub fn load_map(self) { if !self .map_info diff --git a/crates/bevy_editor_settings/src/file_system/de/mod.rs b/crates/bevy_editor_settings/src/file_system/de/mod.rs index bddad321..ac724ef1 100644 --- a/crates/bevy_editor_settings/src/file_system/de/mod.rs +++ b/crates/bevy_editor_settings/src/file_system/de/mod.rs @@ -51,7 +51,7 @@ pub struct LoadStructure<'a> { pub custom_attributes: Option<&'a CustomAttributes>, } -impl<'a> LoadStructure<'a> { +impl LoadStructure<'_> { pub fn load(self) { match self.type_info { TypeInfo::Opaque(opaque_info) => { diff --git a/crates/bevy_editor_settings/src/file_system/de/set.rs b/crates/bevy_editor_settings/src/file_system/de/set.rs index 63b6e342..2881062d 100644 --- a/crates/bevy_editor_settings/src/file_system/de/set.rs +++ b/crates/bevy_editor_settings/src/file_system/de/set.rs @@ -8,7 +8,7 @@ pub struct LoadSet<'a> { pub toml_array: &'a toml::value::Array, } -impl<'a> LoadSet<'a> { +impl LoadSet<'_> { pub fn load_set(self) { for toml_value in self.toml_array.iter() { let mut value = super::default::default_value(&self.set_info.value_ty()).unwrap(); diff --git a/crates/bevy_editor_settings/src/file_system/de/structs.rs b/crates/bevy_editor_settings/src/file_system/de/structs.rs index ae1e4140..3d96e4b7 100644 --- a/crates/bevy_editor_settings/src/file_system/de/structs.rs +++ b/crates/bevy_editor_settings/src/file_system/de/structs.rs @@ -8,7 +8,7 @@ pub struct LoadStruct<'a> { pub strct: &'a mut dyn Struct, } -impl<'a> LoadStruct<'a> { +impl LoadStruct<'_> { pub fn load_struct(self) { let struct_info = self.struct_info; let table = self.table; diff --git a/crates/bevy_editor_settings/src/file_system/de/tuple.rs b/crates/bevy_editor_settings/src/file_system/de/tuple.rs index 6e30aba0..13b0ca32 100644 --- a/crates/bevy_editor_settings/src/file_system/de/tuple.rs +++ b/crates/bevy_editor_settings/src/file_system/de/tuple.rs @@ -8,7 +8,7 @@ pub struct LoadTuple<'a> { pub tuple: &'a mut dyn Tuple, } -impl<'a> LoadTuple<'a> { +impl LoadTuple<'_> { pub fn load_tuple(self) { for i in 0..self.tuple_info.field_len() { let Some(toml_value) = self.table.get(i) else { diff --git a/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs b/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs index c785c4b1..17200f90 100644 --- a/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs +++ b/crates/bevy_editor_settings/src/file_system/de/tuple_struct.rs @@ -8,7 +8,7 @@ pub struct LoadTupleStruct<'a> { pub tuple_struct: &'a mut dyn TupleStruct, } -impl<'a> LoadTupleStruct<'a> { +impl LoadTupleStruct<'_> { pub fn load_tuple_struct(self) { for i in 0..self.tuple_struct_info.field_len() { let Some(toml_value) = self.table.get(i) else { diff --git a/crates/bevy_editor_settings/src/file_system/de/value.rs b/crates/bevy_editor_settings/src/file_system/de/value.rs index 30f95e6f..3d6e0979 100644 --- a/crates/bevy_editor_settings/src/file_system/de/value.rs +++ b/crates/bevy_editor_settings/src/file_system/de/value.rs @@ -7,7 +7,7 @@ pub struct LoadValue<'a> { pub value: &'a mut dyn PartialReflect, } -impl<'a> LoadValue<'a> { +impl LoadValue<'_> { pub fn load_value(self) { let value_info = self.value_info; match self.toml_value { From c019da297747ca0c6565584e5c5305d207c94f94 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 18:54:22 +1300 Subject: [PATCH 35/39] fix safty message --- crates/bevy_editor_settings/src/file_system/de/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/mod.rs b/crates/bevy_editor_settings/src/file_system/de/mod.rs index ac724ef1..84c27e45 100644 --- a/crates/bevy_editor_settings/src/file_system/de/mod.rs +++ b/crates/bevy_editor_settings/src/file_system/de/mod.rs @@ -198,9 +198,9 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se } let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); let reflect_from_ptr = type_reg.data::().unwrap(); - // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for #[allow(unsafe_code)] let ReflectMut::Struct(strct) = + // SAFETY: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() else { panic!("Expected Struct"); @@ -229,9 +229,9 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se } let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); let reflect_from_ptr = type_reg.data::().unwrap(); - // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for #[allow(unsafe_code)] let ReflectMut::Enum(enm) = + // SAFETY: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() else { panic!("Expected Struct"); @@ -262,9 +262,9 @@ pub fn load_preferences(world: &mut World, table: toml::Table, settings_type: Se } let mut ptr = world.get_resource_mut_by_id(res_id).unwrap(); let reflect_from_ptr = type_reg.data::().unwrap(); - // SAFE: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for #[allow(unsafe_code)] let ReflectMut::TupleStruct(tuple_struct) = + // SAFETY: `value` is of type `Reflected`, which the `ReflectFromPtr` was created for unsafe { reflect_from_ptr.as_reflect_mut(ptr.as_mut()) }.reflect_mut() else { panic!("Expected TupleStruct"); From 0c5c1c723f728a0d049640ceec0a231e075929a1 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 18:55:23 +1300 Subject: [PATCH 36/39] fix returns --- .../bevy_editor_settings/src/file_system/de/default.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/default.rs b/crates/bevy_editor_settings/src/file_system/de/default.rs index 197b7ca4..588e5e58 100644 --- a/crates/bevy_editor_settings/src/file_system/de/default.rs +++ b/crates/bevy_editor_settings/src/file_system/de/default.rs @@ -96,9 +96,7 @@ pub fn default_struct(type_info: &S) -> Option for i in 0..type_info.field_len() { let field_at = type_info.field_at(i).unwrap(); - let Some(value) = default_data_type(field_at.type_info().unwrap()) else { - return None; - }; + let value = default_data_type(field_at.type_info().unwrap())?; dyn_struct.insert_boxed(field_at.name(), value); } @@ -112,10 +110,7 @@ pub fn default_tuple(type_info: &S) -> Option { for i in 0..type_info.field_len() { let field_at = type_info.field_at(i).unwrap(); - let Some(value) = default_data_type(field_at.type_info().unwrap()) else { - return None; - }; - + let value = default_data_type(field_at.type_info().unwrap())?; tuple.insert_boxed(value); } From 0658999d566f6f24e840fb600055616db8648411 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 19:07:35 +1300 Subject: [PATCH 37/39] add another test --- .../src/file_system/de/enums.rs | 16 ++++++++++++++++ .../src/file_system/de/list.rs | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/enums.rs b/crates/bevy_editor_settings/src/file_system/de/enums.rs index 99871e62..c58d48f1 100644 --- a/crates/bevy_editor_settings/src/file_system/de/enums.rs +++ b/crates/bevy_editor_settings/src/file_system/de/enums.rs @@ -175,4 +175,20 @@ mod tests { ); toml::Value::Table(table) } + + #[tracing_test::traced_test] + #[test] + fn load_enum_tuple() { + let mut enum_test = TestEnum::default(); + + let toml_value = enum_test_tuple_toml(); + LoadEnum { + enum_info: enum_test.reflect_type_info().as_enum().unwrap(), + toml_value: &toml_value, + enm: &mut enum_test, + } + .load_enum(); + + assert_eq!(enum_test, TestEnum::Variant4(1, 2)); + } } diff --git a/crates/bevy_editor_settings/src/file_system/de/list.rs b/crates/bevy_editor_settings/src/file_system/de/list.rs index f14aec0e..24960b7a 100644 --- a/crates/bevy_editor_settings/src/file_system/de/list.rs +++ b/crates/bevy_editor_settings/src/file_system/de/list.rs @@ -54,7 +54,7 @@ impl LoadList<'_> { #[cfg(test)] mod tests { - use bevy::reflect::{DynamicTyped as _, Reflect, Struct}; + use bevy::reflect::{DynamicTyped as _, Reflect}; use super::*; From 27c94bbeac59b8aee9ad9aee3797bc8594e19cd6 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 19:07:48 +1300 Subject: [PATCH 38/39] fmt --- .../bevy_editor_settings/src/file_system/de/enums.rs | 2 +- .../src/file_system/de/structs.rs | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/enums.rs b/crates/bevy_editor_settings/src/file_system/de/enums.rs index c58d48f1..4f11979c 100644 --- a/crates/bevy_editor_settings/src/file_system/de/enums.rs +++ b/crates/bevy_editor_settings/src/file_system/de/enums.rs @@ -11,7 +11,7 @@ pub struct LoadEnum<'a> { pub enm: &'a mut dyn Enum, } -impl LoadEnum<'_>{ +impl LoadEnum<'_> { pub fn load_enum(self) { match self.toml_value { toml::Value::String(str_val) => { diff --git a/crates/bevy_editor_settings/src/file_system/de/structs.rs b/crates/bevy_editor_settings/src/file_system/de/structs.rs index 3d96e4b7..0b7295db 100644 --- a/crates/bevy_editor_settings/src/file_system/de/structs.rs +++ b/crates/bevy_editor_settings/src/file_system/de/structs.rs @@ -53,8 +53,14 @@ mod tests { "string".to_string(), toml::Value::String("Hello".to_string()), ); - table.insert("float".to_string(), toml::Value::Float(std::f64::consts::PI)); - table.insert("float32".to_string(), toml::Value::Float(std::f64::consts::PI)); + table.insert( + "float".to_string(), + toml::Value::Float(std::f64::consts::PI), + ); + table.insert( + "float32".to_string(), + toml::Value::Float(std::f64::consts::PI), + ); table } @@ -118,4 +124,3 @@ mod tests { ); } } - From 16dd49481ac1316739fdcd60a67ad72baf4f4021 Mon Sep 17 00:00:00 2001 From: Night_Hunter Date: Sun, 22 Dec 2024 19:12:34 +1300 Subject: [PATCH 39/39] fix clippy --- crates/bevy_editor_settings/src/file_system/de/list.rs | 4 +--- crates/bevy_editor_settings/src/file_system/de/map.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/bevy_editor_settings/src/file_system/de/list.rs b/crates/bevy_editor_settings/src/file_system/de/list.rs index 24960b7a..8b852bb6 100644 --- a/crates/bevy_editor_settings/src/file_system/de/list.rs +++ b/crates/bevy_editor_settings/src/file_system/de/list.rs @@ -28,9 +28,7 @@ impl LoadList<'_> { }; if let MergeStrategy::Replace = merge_strategy { - while self.list.len() > 0 { - self.list.remove(self.list.len() - 1); - } + self.list.drain(); } for toml_value in self.toml_array.iter() { diff --git a/crates/bevy_editor_settings/src/file_system/de/map.rs b/crates/bevy_editor_settings/src/file_system/de/map.rs index d7de1f97..6754d685 100644 --- a/crates/bevy_editor_settings/src/file_system/de/map.rs +++ b/crates/bevy_editor_settings/src/file_system/de/map.rs @@ -16,7 +16,7 @@ impl LoadMap<'_> { if !self .map_info .key_info() - .map(|info| info.is::()) + .map(bevy::reflect::TypeInfo::is::) .unwrap_or(false) { warn!("Preferences: Map key must be a String");