Adding parsing stuff (parsing the hard way)
parent
87ca1b13f6
commit
5ae1379e3a
@ -0,0 +1,327 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub(crate) enum SaveEntityParseError {
|
||||
#[error("Failed to parse Uuid: {0}")]
|
||||
Uuid(#[from] uuid::Error),
|
||||
#[error("Failed to parse name")]
|
||||
Name,
|
||||
#[error("Failed to parse Transform")]
|
||||
Transform,
|
||||
#[error("Failed to parse Entity")]
|
||||
Nom(nom::Err<nom::error::Error<Box<str>>>),
|
||||
#[error("Failed to parse camera")]
|
||||
Camera,
|
||||
}
|
||||
|
||||
// Convert Nom error to parse error
|
||||
// https://stackoverflow.com/a/77974858/3096574
|
||||
impl From<nom::Err<nom::error::Error<&str>>> for SaveEntityParseError {
|
||||
fn from(err: nom::Err<nom::error::Error<&str>>) -> Self {
|
||||
SaveEntityParseError::Nom(err.map_input(|input| input.into()))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_word<'a>(w: &'a str) -> impl Fn(&'a str) -> IResult<&'a str, &'a str> {
|
||||
move |i: &'a str| tag(w)(i)
|
||||
}
|
||||
|
||||
fn parse_xyz(i: &str) -> IResult<&str, (f32, f32, f32)> {
|
||||
tuple((float, space1, float, space1, float))(i)
|
||||
.map(|(s, (x, _, y, _, z))| (s, (x, y, z)))
|
||||
}
|
||||
|
||||
fn parse_wxyz(i: &str) -> IResult<&str, (f32, f32, f32, f32)> {
|
||||
tuple((
|
||||
float,
|
||||
space1,
|
||||
float,
|
||||
space1,
|
||||
float,
|
||||
space1,
|
||||
float,
|
||||
))(i)
|
||||
.map(|(s, (w, _, x, _, y, _, z))| (s, (w, x, y, z)))
|
||||
}
|
||||
|
||||
fn parse_string(i: &str) -> IResult<&str, &str> {
|
||||
let (rem, (_, out, _)) = tuple((tag("\""), take_until1("\""), tag("\"")))(i)?;
|
||||
Ok((rem, out))
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
pub(crate) fn parse_save_transform(line: &str) -> Result<Transform, SaveEntityParseError> {
|
||||
let (rem, _) = tag("transform")(line)?;
|
||||
|
||||
let mut transform = Transform::default();
|
||||
|
||||
let mut curr = rem.trim_start();
|
||||
for _ in 0..3 {
|
||||
if let Ok((rem, (_, _, (x, y, z)))) = tuple((parse_word("translation"), space1, parse_xyz))(curr.trim_start()) {
|
||||
transform.translation = Vec3::new(x, y, z);
|
||||
curr = rem.trim_start();
|
||||
} else if let Ok((rem, (_, _, (x, y, z, w)))) = tuple((parse_word("rotation"), space1, parse_wxyz))(curr.trim_start()) {
|
||||
transform.rotation = Quat::from_xyzw(x, y, z, w);
|
||||
curr = rem.trim_start();
|
||||
} else if let Ok((rem, (_, _, (x, y, z)))) = tuple((parse_word("scale"), space1, parse_xyz))(curr.trim_start()) {
|
||||
transform.scale = Vec3::new(x, y, z);
|
||||
curr = rem.trim_start();
|
||||
} else {
|
||||
return Err(SaveEntityParseError::Transform);
|
||||
}
|
||||
}
|
||||
|
||||
// Assert there are no trailing characters on the line
|
||||
debug_assert_eq!(curr, "");
|
||||
|
||||
Ok(transform)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_transform() {
|
||||
let line = "transform translation 1.0 2.0 3.0 rotation 0.1 0.2 0.3 1.0 scale 1.1 1.2 1.3";
|
||||
let parsed = parse_save_transform(line).unwrap();
|
||||
let expected = Transform {
|
||||
translation: Vec3::new(1.0, 2.0, 3.0),
|
||||
rotation: Quat::from_xyzw(0.1, 0.2, 0.3, 1.0),
|
||||
scale: Vec3::new(1.1, 1.2, 1.3),
|
||||
};
|
||||
|
||||
assert_eq!(parsed, expected);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
pub(crate) fn parse_save_name(line: &str) -> Result<Name, 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)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_name() {
|
||||
{
|
||||
let line = "name Van";
|
||||
let parsed = parse_save_name(line).unwrap();
|
||||
let expected = Name::new("Van");
|
||||
|
||||
assert_eq!(parsed, expected);
|
||||
}
|
||||
{
|
||||
let line = "name Big Mike";
|
||||
let parsed = parse_save_name(line).unwrap();
|
||||
let expected = Name::new("Big Mike");
|
||||
|
||||
assert_eq!(parsed, expected);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Component, Clone, Debug, Reflect, PartialEq)]
|
||||
#[reflect(Component)]
|
||||
pub(crate) struct EntityUuid {
|
||||
id: String
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
pub(crate) fn parse_save_uuid(line: &str) -> Result<EntityUuid, SaveEntityParseError> {
|
||||
let (remainder, _) = tag("uuid")(line)?;
|
||||
let id = remainder.trim().into();
|
||||
Ok(EntityUuid { id })
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_uuid() {
|
||||
let line = "uuid 1c16ab9a-5f79-4340-8469-4086f69c64f2";
|
||||
let parsed = parse_save_uuid(line).unwrap();
|
||||
let expected = EntityUuid { id: "1c16ab9a-5f79-4340-8469-4086f69c64f2".into() };
|
||||
|
||||
assert_eq!(parsed, expected);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
pub(crate) fn parse_save_model(line: &str) -> Result<(String, String), 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()))
|
||||
}
|
||||
|
||||
#[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"));
|
||||
|
||||
assert_eq!(parsed, expected);
|
||||
}
|
||||
|
||||
#[derive(Component, Debug, Default, PartialEq, Reflect, Clone)]
|
||||
#[reflect_value(Component, Default)]
|
||||
pub(crate) enum SaveCameraRenderTarget {
|
||||
#[default]
|
||||
Default,
|
||||
Window(Uuid),
|
||||
}
|
||||
|
||||
pub(crate) fn parse_save_camera(line: &str) -> Result<SaveCameraRenderTarget, 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) {
|
||||
// Camera + target + window + UUID
|
||||
if let Ok((rem, (_, uuid))) = tuple((space1::<&str, ()>, take(36usize)))(rem) {
|
||||
debug_assert!(rem == "");
|
||||
|
||||
let parsed_uuid = Uuid::parse_str(uuid)?;
|
||||
Ok(SaveCameraRenderTarget::Window(parsed_uuid))
|
||||
// Camera + target + widow
|
||||
} else {
|
||||
debug_assert!(rem == "");
|
||||
|
||||
Ok(SaveCameraRenderTarget::Default)
|
||||
}
|
||||
// camera + target
|
||||
} else {
|
||||
debug_assert!(rem == "");
|
||||
|
||||
Err(SaveEntityParseError::Camera)
|
||||
}
|
||||
// Just camera
|
||||
} else {
|
||||
debug_assert!(rem == "");
|
||||
|
||||
Ok(SaveCameraRenderTarget::Default)
|
||||
}
|
||||
// Nothing parsed well
|
||||
} else {
|
||||
Err(SaveEntityParseError::Camera)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_camera() {
|
||||
{
|
||||
let line = "camera";
|
||||
let parsed = parse_save_camera(line).unwrap();
|
||||
let expected = SaveCameraRenderTarget::Default;
|
||||
assert_eq!(parsed, expected);
|
||||
}
|
||||
{
|
||||
let line = "camera target window";
|
||||
let parsed = parse_save_camera(line).unwrap();
|
||||
let expected = SaveCameraRenderTarget::Default;
|
||||
assert_eq!(parsed, expected);
|
||||
}
|
||||
{
|
||||
let line = "camera target";
|
||||
let parsed = parse_save_camera(line);
|
||||
assert!(parsed.is_err());
|
||||
}
|
||||
{
|
||||
let line = "camera target window 9a1367e0-71e5-4c79-b4ad-02aa44b68af0";
|
||||
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);
|
||||
}
|
||||
{
|
||||
let line = "notcamera";
|
||||
let parsed = parse_save_camera(line);
|
||||
assert!(parsed.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 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)]
|
||||
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<SaveParent, SaveEntityParseError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[test]
|
||||
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);
|
||||
}
|
||||
|
||||
///
|
||||
/// 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<Window, SaveEntityParseError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_window() {
|
||||
let line = "window \"Editor\" visible false";
|
||||
let parsed = parse_save_window(line).unwrap();
|
||||
let expected = Window { visible: false, title: "Editor".into(), ..default() };
|
||||
assert_eq!(parsed.visible, expected.visible);
|
||||
assert_eq!(parsed.title, expected.title);
|
||||
}
|
||||
|
||||
///
|
||||
/// The UI Text bundle specified as a sparse subset of a bundle
|
||||
///
|
||||
pub(crate) fn parse_save_ui_text(line: &str) -> Result<TextBundle, SaveEntityParseError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_save_ui_text() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a parser function for a basic stand-alone tag
|
||||
/// e.g., "editor_tag" or "ui_node"
|
||||
pub(crate) fn parse_save_tag<T: Component + Reflect>(tag: &str) -> impl FnOnce(&str) -> Result<T, SaveEntityParseError> {
|
||||
move |line: &str| -> Result<T, SaveEntityParseError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_save_tag() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[derive(Component, Clone, Debug, Reflect, PartialEq)]
|
||||
#[reflect(Component)]
|
||||
pub(crate) struct SaveTargetCamera(String);
|
||||
|
||||
/// Parses the a SaveTargetCamera which at runtime is converted to a TargetCamera
|
||||
pub(crate) fn parse_save_target_camera(line: &str) -> Result<SaveTargetCamera, SaveEntityParseError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_target_camera() {
|
||||
todo!()
|
||||
}
|
||||
Loading…
Reference in New Issue