Skip to content

Add const and unsafe block suport to bsn! macro#24336

Open
loreball wants to merge 2 commits into
bevyengine:mainfrom
loreball:bsn_const_block
Open

Add const and unsafe block suport to bsn! macro#24336
loreball wants to merge 2 commits into
bevyengine:mainfrom
loreball:bsn_const_block

Conversation

@loreball
Copy link
Copy Markdown
Contributor

@loreball loreball commented May 17, 2026

Objective

Closes #24121

Solution

Add const, unsafe and async block support to bsn expressions.

Testing

I've added a compile test for const and unsafe blocks. I couldn't figure out how to test or even use the async blocks. The macro needs to construct a struct that holds a future, but async blocks produce voldemort (unnameable) types. Using Box<dyn Future> fixes this problem but then you run into the problem that the struct needs to be clone-able and have a default value. async block futures have neither of those properties.


Showcase

The bsn! macro now supports const and unsafe blocks.

 fn friendly(people: &[&'static str]) -> impl Scene {
     bsn! {
         Friend {
             name: const {"John"}
             // SAFETY: Jesus take the wheel
             father: unsafe {people.get_unchecked(0)}
         }
     }
 }

@alice-i-cecile alice-i-cecile added this to the 0.19 milestone May 17, 2026
@kfc35 kfc35 added A-Scenes Composing and serializing ECS objects S-Needs-Review Needs reviewer attention (from anyone!) to move forward D-Macros Code that generates Rust code labels May 18, 2026
let braced = braced_tokens(input)?;

BsnValue::Expr(quote! {#unsafe_token {#braced}})
} else if input.peek(Token![async]) && input.peek2(Brace) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the difficulties you noted with supporting async blocks, it may be better to leave this out until it's supported

loreball added 2 commits May 18, 2026 16:40
You can't really make it work properly without limits.
The problem is that async futures produce unnamable types.
You'd have to box them but the `.into()` call we use doesn't
work for that.

```rust
fn what_we_do() -> Box<dyn Future<Output = ()>> {
    {async {}}.into()
}

// This wouldn't be generic over the container though
fn what_we_need_to_do() -> Box<dyn Future<Output = ()>> {
    Box::new({async {}})
}
```
@loreball
Copy link
Copy Markdown
Contributor Author

I've ripped out support for async blocks. More detailed reasoning is in the commit description but tl;dr there's just no way to type a struct field that would make it work. If somebody really needs it they can do {Box::new(async {...})}.

@kfc35 kfc35 added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Scenes Composing and serializing ECS objects D-Macros Code that generates Rust code S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Can't use unsafe in bsn expression

4 participants