use crate::prelude::*;
use beet_core::prelude::*;
use proc_macro2::TokenStream;
#[derive(Default, Clone, Deref, DerefMut, Component, ToTokens)]
pub struct CombinatorExpr(pub Vec<CombinatorExprPartial>);
#[derive(Clone, ToTokens)]
pub enum CombinatorExprPartial {
Tokens(String),
Element(Entity),
}
pub fn collapse_combinator_exprs(world: &mut World) -> Result {
let mut query = world.query_filtered::<Entity, With<CombinatorExpr>>();
while let Some(entity) = query.iter(world).next() {
if let Some(expr) =
tokenize_combinator_exprs_mapped(
world,
entity,
tokenize_rsx,
)? {
world
.entity_mut(entity)
.remove::<CombinatorExpr>()
.insert(expr);
}
}
Ok(())
}
pub fn tokenize_combinator_exprs_mapped(
world: &World,
entity: Entity,
map_child: impl Fn(&World, Entity) -> Result<TokenStream>,
) -> Result<Option<NodeExpr>> {
if let Some(combinator) = world.entity(entity).get::<CombinatorExpr>() {
let mut expr = String::new();
for item in combinator.iter() {
match item {
CombinatorExprPartial::Tokens(tokens) => {
expr.push_str(tokens);
}
CombinatorExprPartial::Element(entity) => {
let tokens = map_child(world, *entity)?;
expr.push_str(&tokens.to_string());
}
}
}
let expr_tokens =
syn::parse_str(&format!("{{{expr}}}")).map_err(|e| {
bevyhow!(
"Failed to parse combinator expression.\nInput: {expr}\nError: {e}"
)
})?;
Ok(Some(NodeExpr::new_block(expr_tokens)))
} else {
Ok(None)
}
}
#[allow(unused)]
fn tokenize_combinator_exprs(
world: &World,
items: &mut Vec<TokenStream>,
entity: Entity,
) -> Result<()> {
if let Some(expr) =
tokenize_combinator_exprs_mapped(world, entity, tokenize_rsx)?
{
items.push(expr.insert_deferred());
}
Ok(())
}
#[allow(unused)]
fn tokenize_combinator_exprs_tokens(
world: &World,
items: &mut Vec<TokenStream>,
entity: Entity,
) -> Result<()> {
if let Some(expr) =
tokenize_combinator_exprs_mapped(world, entity, tokenize_rsx_tokens)?
{
items.push(expr.self_token_stream());
}
Ok(())
}