From 2f9664940dac7978d134817a293158e0ce87de29 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Wed, 31 Jul 2024 21:07:18 -0700 Subject: [PATCH] Converted all functions to return Box this is nice because it makes things a little more uniform. --- src/parser.rs | 164 +++++++++++++++++++++++++++++++++---------------- src/prelude.rs | 6 +- src/save.rs | 64 +++++++++---------- 3 files changed, 144 insertions(+), 90 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index b372196..18d7971 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,3 @@ -use nom::character::complete::hex_digit1; - use crate::prelude::*; #[derive(Error, Debug)] @@ -14,8 +12,6 @@ pub(crate) enum SaveEntityParseError { Nom(nom::Err>>), #[error("Failed to parse camera")] Camera, - #[error("Failed to parse marker component")] - Marker, } // Convert Nom error to parse error @@ -49,8 +45,9 @@ fn parse_string(i: &str) -> IResult<&str, &str> { } /// +/// Returns reflected `Transform` /// -pub(crate) fn parse_save_transform(line: &str) -> Result { +pub(crate) fn parse_save_transform(line: &str) -> Result, SaveEntityParseError> { let (rem, _) = tag("transform")(line)?; let mut transform = Transform::default(); @@ -80,7 +77,7 @@ pub(crate) fn parse_save_transform(line: &str) -> Result Result { +pub(crate) fn parse_save_name(line: &str) -> Result, SaveEntityParseError> { let (remainder, _) = tag("name")(line)?; let n = remainder.trim().to_string(); if n.is_empty() { Err(SaveEntityParseError::Name) } else { let name = Name::new(n); - Ok(name) + Ok(name.clone_value()) } } @@ -116,14 +117,20 @@ fn test_parse_name() { let parsed = parse_save_name(line).unwrap(); let expected = Name::new("Van"); - assert_eq!(parsed, expected); + assert!(expected + .clone_value() + .reflect_partial_eq(parsed.as_reflect()) + .unwrap()); } { let line = "name Big Mike"; let parsed = parse_save_name(line).unwrap(); let expected = Name::new("Big Mike"); - assert_eq!(parsed, expected); + assert!(expected + .clone_value() + .reflect_partial_eq(parsed.as_reflect()) + .unwrap()); } } @@ -134,11 +141,12 @@ pub(crate) struct EntityUuid { } /// +/// Returns a reflected `EntityUuid` /// -pub(crate) fn parse_save_uuid(line: &str) -> Result { +pub(crate) fn parse_save_uuid(line: &str) -> Result, SaveEntityParseError> { let (remainder, _) = tag("uuid")(line)?; let id = remainder.trim().into(); - Ok(EntityUuid { id }) + Ok(EntityUuid { id }.clone_value()) } #[test] @@ -149,40 +157,62 @@ fn test_parse_uuid() { id: "1c16ab9a-5f79-4340-8469-4086f69c64f2".into(), }; - assert_eq!(parsed, expected); + assert!(expected + .clone_value() + .reflect_partial_eq(parsed.as_reflect()) + .unwrap()); +} + +#[derive(Component, Debug, Default, Reflect, PartialEq)] +#[reflect(Component, PartialEq)] +pub(crate) struct SaveModel { + gltf_file: PathBuf, + scene_name: String, } /// +/// Returns a reflected `SaveModel` /// -pub(crate) fn parse_save_model(line: &str) -> Result<(String, String), SaveEntityParseError> { +pub(crate) fn parse_save_model(line: &str) -> Result, SaveEntityParseError> { let (rem, (_, _, gltf_path, _, scene_name)) = tuple((tag("model"), space1, parse_string, space1, parse_string))(line)?; debug_assert!(rem == ""); - Ok((gltf_path.into(), scene_name.into())) + Ok(SaveModel { + gltf_file: gltf_path.into(), + scene_name: scene_name.into(), + } + .clone_value()) } #[test] fn test_parse_model() { let line = "model \"models/foo.glb\" \"My Scene\""; let parsed = parse_save_model(line).unwrap(); - let expected = (String::from("models/foo.glb"), String::from("My Scene")); + let expected = SaveModel { + gltf_file: "models/foo.glb".into(), + scene_name: "My Scene".into(), + }; - assert_eq!(parsed, expected); + assert!(expected + .clone_value() + .reflect_partial_eq(parsed.as_reflect()) + .unwrap()); } #[derive(Component, Debug, Default, PartialEq, Reflect, Clone)] -#[reflect_value(Component, Default)] +#[reflect_value(Component, Default, PartialEq)] pub(crate) enum SaveCameraRenderTarget { #[default] Default, Window(Uuid), } -pub(crate) fn parse_save_camera( - line: &str, -) -> Result { +/// +/// Returns a reflected `SaveCameraRenderTarget +/// +pub(crate) fn parse_save_camera(line: &str) -> Result, SaveEntityParseError> { if let Ok((rem, _camera)) = tag::<&str, &str, ()>("camera")(line) { if let Ok((rem, (_, _target))) = tuple((space1::<&str, ()>, tag("target")))(rem) { if let Ok((rem, (_, _window))) = tuple((space1::<&str, ()>, tag("window")))(rem) { @@ -191,12 +221,12 @@ pub(crate) fn parse_save_camera( debug_assert!(rem == ""); let parsed_uuid = Uuid::parse_str(uuid)?; - Ok(SaveCameraRenderTarget::Window(parsed_uuid)) + Ok(SaveCameraRenderTarget::Window(parsed_uuid).clone_value()) // Camera + target + widow } else { debug_assert!(rem == ""); - Ok(SaveCameraRenderTarget::Default) + Ok(SaveCameraRenderTarget::Default.clone_value()) } // camera + target } else { @@ -208,7 +238,7 @@ pub(crate) fn parse_save_camera( } else { debug_assert!(rem == ""); - Ok(SaveCameraRenderTarget::Default) + Ok(SaveCameraRenderTarget::Default.clone_value()) } // Nothing parsed well } else { @@ -222,13 +252,19 @@ fn test_parse_camera() { let line = "camera"; let parsed = parse_save_camera(line).unwrap(); let expected = SaveCameraRenderTarget::Default; - assert_eq!(parsed, expected); + assert!(expected + .clone_value() + .reflect_partial_eq(parsed.as_reflect()) + .unwrap()); } { let line = "camera target window"; let parsed = parse_save_camera(line).unwrap(); let expected = SaveCameraRenderTarget::Default; - assert_eq!(parsed, expected); + assert!(expected + .clone_value() + .reflect_partial_eq(parsed.as_reflect()) + .unwrap()); } { let line = "camera target"; @@ -240,7 +276,10 @@ fn test_parse_camera() { let target_uuid = Uuid::parse_str("9a1367e0-71e5-4c79-b4ad-02aa44b68af0").unwrap(); let parsed = parse_save_camera(line).unwrap(); let expected = SaveCameraRenderTarget::Window(target_uuid); - assert_eq!(parsed, expected); + assert!(expected + .clone_value() + .reflect_partial_eq(parsed.as_reflect()) + .unwrap()); } { let line = "notcamera"; @@ -252,19 +291,23 @@ fn test_parse_camera() { /// SaveParent entity which is a reference to which entity this is a child of /// A run-time system converts this to a bevy Parent component #[derive(Component, PartialEq, Debug, Reflect, Clone)] -#[reflect_value(Component)] +#[reflect_value(Component, PartialEq)] pub(crate) struct SaveParent(String); +/// /// Parses a parent entity with this format: /// ```text /// parent some_other_file.entity /// ``` -pub(crate) fn parse_save_parent(line: &str) -> Result { +/// +/// Returns a reflected `SaveParent` +/// +pub(crate) fn parse_save_parent(line: &str) -> Result, SaveEntityParseError> { let (rem, (_, _, parent_file)) = tuple((tag("parent"), space1, parse_string))(line)?; debug_assert!(rem.is_empty()); - Ok(SaveParent(parent_file.into())) + Ok(SaveParent(parent_file.into()).clone_value()) } #[test] @@ -272,14 +315,19 @@ fn test_parse_parent() { let line = "parent \"some_other_file.entity\""; let parsed = parse_save_parent(line).unwrap(); let expected = SaveParent("some_other_file.entity".into()); - assert_eq!(parsed, expected); + assert!(expected + .clone_value() + .reflect_partial_eq(parsed.as_reflect()) + .unwrap()); } /// /// Parse the Window component (which is very big!) /// We only sparsely define the bits that we want to edit (for now) /// -pub(crate) fn parse_save_window(line: &str) -> Result { +/// Returns a reflected `Window` +/// +pub(crate) fn parse_save_window(line: &str) -> Result, SaveEntityParseError> { let (rem, (_, _, window_title)) = tuple((tag("window"), space1, parse_string))(line)?; let (rem, (_, _, _, visibility)) = tuple((space1, tag("visible"), space1, parse_bool))(rem)?; @@ -290,7 +338,8 @@ pub(crate) fn parse_save_window(line: &str) -> Result Result { +/// +/// Returns a reflected `Text` +/// +pub(crate) fn parse_save_ui_text(line: &str) -> Result, SaveEntityParseError> { let (rem, (_tag_text, _space1, text)) = tuple((tag("text"), space1, parse_string))(line)?; let (rem, (_space, _tag_color, _space1, _hash, hex_color)) = @@ -327,10 +381,7 @@ pub(crate) fn parse_save_ui_text(line: &str) -> Result( t: &str, ) -> impl FnOnce(&str) -> Result + '_ { @@ -374,7 +421,10 @@ fn test_save_tag() { let line = "testing"; let parsed = parse_save_tag::("testing")(line).unwrap(); let expected = TestingTag; - assert_eq!(parsed, expected); + assert!(expected + .clone_value() + .reflect_partial_eq(parsed.as_reflect()) + .unwrap()); } #[derive(Component, Clone, Debug, Reflect, PartialEq)] @@ -385,13 +435,15 @@ pub(crate) struct SaveTargetCamera(String); /// ```text /// target-camera "./level-camera.entity" /// ``` +/// +/// Returns reflected `SaveTargetCamera` pub(crate) fn parse_save_target_camera( line: &str, -) -> Result { +) -> Result, SaveEntityParseError> { Ok( tuple((tag("target-camera"), space1, parse_string))(line).map( |(_, (_, _, target_camera_entity_file))| { - SaveTargetCamera(target_camera_entity_file.into()) + SaveTargetCamera(target_camera_entity_file.into()).clone_value() }, )?, ) @@ -402,5 +454,9 @@ fn test_target_camera() { let line = "target-camera \"./level-camera.entity\""; let parsed = parse_save_target_camera(line).unwrap(); let expected = SaveTargetCamera("./level-camera.entity".into()); - assert_eq!(parsed, expected); + + assert!(expected + .clone_value() + .reflect_partial_eq(parsed.as_reflect()) + .unwrap()); } diff --git a/src/prelude.rs b/src/prelude.rs index ab2f5c3..f745efb 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -10,14 +10,16 @@ pub(crate) use bevy::{ window::{PrimaryWindow, WindowCloseRequested, WindowRef}, }; pub(crate) use nom::bytes::complete::take; +pub(crate) use nom::character::complete::hex_digit1; pub(crate) use nom::{ - branch::{alt, permutation}, + branch::alt, bytes::complete::{tag, take_until1}, - character::complete::{char, hex_digit1, space1}, + character::complete::{char, space1}, number::complete::float, sequence::tuple, IResult, }; +pub(crate) use std::path::PathBuf; pub(crate) use thiserror::Error; pub(crate) use uuid::Uuid; diff --git a/src/save.rs b/src/save.rs index b765af5..35ba23c 100644 --- a/src/save.rs +++ b/src/save.rs @@ -5,8 +5,7 @@ pub(crate) struct SavePlugin; impl Plugin for SavePlugin { fn build(&self, app: &mut App) { - app - .register_type::() + app.register_type::() .register_type::() .register_type::() .init_asset::() @@ -33,33 +32,34 @@ pub(crate) struct SaveEntity { impl SaveEntity { fn parse( text: &str, - load_context: &mut LoadContext, + _load_context: &mut LoadContext, ) -> Result { let lines = text.split('\n'); let mut entity = SaveEntity { ..default() }; + let fns = [ + parse_save_name, + parse_save_transform, + parse_save_uuid, + parse_save_model, + parse_save_camera, + parse_save_parent, + parse_save_window, + parse_save_target_camera, + ]; lines.into_iter().for_each(|line| { + // track if this line matched any components + let mut good = false; + + // Run line against all parsers + for f in fns { + if let Ok(v) = f(line) { + entity.components.push(v); + good = true; + } + } - if let Ok(name) = parse_save_name(line) { - entity.components.push(name.clone_value()); - } else if let Ok(transform) = parse_save_transform(line) { - entity.components.push(transform.clone_value()); - } else if let Ok(uuid) = parse_save_uuid(line) { - entity.components.push(uuid.clone_value()); - } else if let Ok((gltf_file, scene_name)) = parse_save_model(line) { - let gltf_scene = GltfScene { gltf: load_context.load(gltf_file), name: scene_name }; - entity.components.push(gltf_scene.clone_value()); - } else if let Ok(target) = parse_save_camera(line) { - entity.components.push(target.clone_value()); - } else if let Ok(parent) = parse_save_parent(line) { - entity.components.push(parent.clone_value()); - } else if let Ok(window) = parse_save_window(line) { - entity.components.push(window.clone_value()); - // } else if let Ok(ui_text_bundle) = parse_save_ui_text(line) { - // entity.components.push(ui_text_bundle.clone_value()); - } else if let Ok(target_camera) = parse_save_target_camera(line) { - entity.components.push(target_camera.clone_value()); - } else { - error!("Failed to parse line component `{:?}`", line); + if !good { + error!("failed to parse component from line {:?}", line); } }); Ok(entity) @@ -129,11 +129,11 @@ impl AssetLoader for SaveSceneLoader { let asset_path = load_context.path().to_path_buf(); let parent_dir = asset_path.parent().unwrap(); - let _sub_assets: Vec> = s.lines().map(|line| { - parent_dir.join(line) - }).map(|path| { - load_context.load(path) - }).collect(); + let _sub_assets: Vec> = s + .lines() + .map(|line| parent_dir.join(line)) + .map(|path| load_context.load(path)) + .collect(); Ok(DynamicScene::default()) } @@ -143,14 +143,10 @@ impl AssetLoader for SaveSceneLoader { } } - fn test_load_entity(loader: Res, mut commands: Commands) { let _: Handle = loader.load("editor/_.scene"); let handle: Handle = loader.load("levels/00/entities/van.entity"); - commands.spawn(( - SpatialBundle { ..default() }, - handle, - )); + commands.spawn((SpatialBundle { ..default() }, handle)); } fn spawn_loaded_entities(