Skip to content

Commit 1137c08

Browse files
committed
derive joined
Signed-off-by: Teo Koon Peng <[email protected]>
1 parent a6bf08d commit 1137c08

File tree

3 files changed

+139
-109
lines changed

3 files changed

+139
-109
lines changed

macros/src/buffers.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use proc_macro::TokenStream;
2+
use quote::{format_ident, quote};
3+
use syn::{DeriveInput, Ident, Type};
4+
5+
use crate::Result;
6+
7+
pub(crate) fn impl_buffer_map_layout(ast: DeriveInput) -> Result<TokenStream> {
8+
let struct_ident = ast.ident;
9+
let (field_ident, field_type) = match ast.data {
10+
syn::Data::Struct(data) => get_fields_map(data.fields)?,
11+
_ => return Err("expected struct".to_string()),
12+
};
13+
let map_key: Vec<String> = field_ident.iter().map(|v| v.to_string()).collect();
14+
let struct_buffer_ident = format_ident!("__{}Buffers", struct_ident);
15+
16+
let gen = quote! {
17+
impl BufferMapLayout for #struct_ident {
18+
fn is_compatible(buffers: &BufferMap) -> Result<(), IncompatibleLayout> {
19+
let mut compatibility = IncompatibleLayout::default();
20+
#(
21+
compatibility.require_buffer::<#field_type>(#map_key, buffers);
22+
)*
23+
compatibility.into_result()
24+
}
25+
26+
fn buffered_count(
27+
buffers: &BufferMap,
28+
session: Entity,
29+
world: &World,
30+
) -> Result<usize, OperationError> {
31+
#(
32+
let #field_ident = world
33+
.get_entity(buffers.get(#map_key).unwrap().id())
34+
.or_broken()?
35+
.buffered_count::<#field_type>(session)?;
36+
)*
37+
38+
Ok([#( #field_ident ),*]
39+
.iter()
40+
.min()
41+
.copied()
42+
.unwrap_or(0))
43+
}
44+
45+
fn ensure_active_session(
46+
buffers: &BufferMap,
47+
session: Entity,
48+
world: &mut World,
49+
) -> OperationResult {
50+
#(
51+
world
52+
.get_entity_mut(buffers.get(#map_key).unwrap().id())
53+
.or_broken()?
54+
.ensure_session::<#field_type>(session)?;
55+
)*
56+
57+
Ok(())
58+
}
59+
}
60+
61+
impl JoinedValue for #struct_ident {
62+
type Buffers = #struct_buffer_ident;
63+
64+
fn pull(
65+
buffers: &BufferMap,
66+
session: Entity,
67+
world: &mut World,
68+
) -> Result<Self, OperationError> {
69+
#(
70+
let #field_ident = world
71+
.get_entity_mut(buffers.get(#map_key).unwrap().id())
72+
.or_broken()?
73+
.pull_from_buffer::<#field_type>(session)?;
74+
)*
75+
76+
Ok(Self {
77+
#(
78+
#field_ident
79+
),*
80+
})
81+
}
82+
}
83+
84+
struct #struct_buffer_ident {
85+
#(
86+
#field_ident: Buffer<#field_type>
87+
),*
88+
}
89+
90+
impl From<#struct_buffer_ident> for BufferMap {
91+
fn from(value: #struct_buffer_ident) -> Self {
92+
let mut buffers = BufferMap::default();
93+
#(
94+
buffers.insert(Cow::Borrowed(#map_key), value.#field_ident);
95+
)*
96+
buffers
97+
}
98+
}
99+
};
100+
101+
Ok(gen.into())
102+
}
103+
104+
fn get_fields_map(fields: syn::Fields) -> Result<(Vec<Ident>, Vec<Type>)> {
105+
match fields {
106+
syn::Fields::Named(data) => {
107+
let mut idents = Vec::with_capacity(data.named.len());
108+
let mut types = Vec::with_capacity(data.named.len());
109+
for field in data.named {
110+
let ident = field.ident.ok_or("expected named fields".to_string())?;
111+
idents.push(ident);
112+
types.push(field.ty);
113+
}
114+
Ok((idents, types))
115+
}
116+
_ => return Err("expected named fields".to_string()),
117+
}
118+
}

macros/src/lib.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
*
1616
*/
1717

18+
mod buffers;
19+
use buffers::impl_buffer_map_layout;
20+
1821
use proc_macro::TokenStream;
1922
use quote::quote;
20-
use syn::DeriveInput;
23+
use syn::{parse_macro_input, DeriveInput};
2124

2225
#[proc_macro_derive(Stream)]
2326
pub fn simple_stream_macro(item: TokenStream) -> TokenStream {
@@ -58,3 +61,18 @@ pub fn delivery_label_macro(item: TokenStream) -> TokenStream {
5861
}
5962
.into()
6063
}
64+
65+
// The result error is the compiler error message to be displayed.
66+
type Result<T> = std::result::Result<T, String>;
67+
68+
#[proc_macro_derive(Joined)]
69+
pub fn derive_joined(input: TokenStream) -> TokenStream {
70+
let input = parse_macro_input!(input as DeriveInput);
71+
match impl_buffer_map_layout(input) {
72+
Ok(tokens) => tokens,
73+
Err(msg) => quote! {
74+
compile_error!(#msg);
75+
}
76+
.into(),
77+
}
78+
}

src/buffer/buffer_map.rs

Lines changed: 2 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -365,121 +365,15 @@ mod tests {
365365
};
366366

367367
use bevy_ecs::prelude::World;
368+
use bevy_impulse_derive::Joined;
368369

369-
#[derive(Clone)]
370+
#[derive(Clone, Joined)]
370371
struct TestJoinedValue {
371372
integer: i64,
372373
float: f64,
373374
string: String,
374375
}
375376

376-
impl BufferMapLayout for TestJoinedValue {
377-
fn is_compatible(buffers: &BufferMap) -> Result<(), IncompatibleLayout> {
378-
let mut compatibility = IncompatibleLayout::default();
379-
compatibility.require_buffer::<i64>("integer", buffers);
380-
compatibility.require_buffer::<f64>("float", buffers);
381-
compatibility.require_buffer::<String>("string", buffers);
382-
compatibility.into_result()
383-
}
384-
385-
fn buffered_count(
386-
buffers: &BufferMap,
387-
session: Entity,
388-
world: &World,
389-
) -> Result<usize, OperationError> {
390-
let integer_count = world
391-
.get_entity(buffers.get("integer").unwrap().id())
392-
.or_broken()?
393-
.buffered_count::<i64>(session)?;
394-
395-
let float_count = world
396-
.get_entity(buffers.get("float").unwrap().id())
397-
.or_broken()?
398-
.buffered_count::<f64>(session)?;
399-
400-
let string_count = world
401-
.get_entity(buffers.get("string").unwrap().id())
402-
.or_broken()?
403-
.buffered_count::<String>(session)?;
404-
405-
Ok([integer_count, float_count, string_count]
406-
.iter()
407-
.min()
408-
.copied()
409-
.unwrap_or(0))
410-
}
411-
412-
fn ensure_active_session(
413-
buffers: &BufferMap,
414-
session: Entity,
415-
world: &mut World,
416-
) -> OperationResult {
417-
world
418-
.get_entity_mut(buffers.get("integer").unwrap().id())
419-
.or_broken()?
420-
.ensure_session::<i64>(session)?;
421-
422-
world
423-
.get_entity_mut(buffers.get("float").unwrap().id())
424-
.or_broken()?
425-
.ensure_session::<f64>(session)?;
426-
427-
world
428-
.get_entity_mut(buffers.get("string").unwrap().id())
429-
.or_broken()?
430-
.ensure_session::<String>(session)?;
431-
432-
Ok(())
433-
}
434-
}
435-
436-
impl JoinedValue for TestJoinedValue {
437-
type Buffers = TestJoinedValueBuffers;
438-
439-
fn pull(
440-
buffers: &BufferMap,
441-
session: Entity,
442-
world: &mut World,
443-
) -> Result<Self, OperationError> {
444-
let integer = world
445-
.get_entity_mut(buffers.get("integer").unwrap().id())
446-
.or_broken()?
447-
.pull_from_buffer::<i64>(session)?;
448-
449-
let float = world
450-
.get_entity_mut(buffers.get("float").unwrap().id())
451-
.or_broken()?
452-
.pull_from_buffer::<f64>(session)?;
453-
454-
let string = world
455-
.get_entity_mut(buffers.get("string").unwrap().id())
456-
.or_broken()?
457-
.pull_from_buffer::<String>(session)?;
458-
459-
Ok(Self {
460-
integer,
461-
float,
462-
string,
463-
})
464-
}
465-
}
466-
467-
struct TestJoinedValueBuffers {
468-
integer: Buffer<i64>,
469-
float: Buffer<f64>,
470-
string: Buffer<String>,
471-
}
472-
473-
impl From<TestJoinedValueBuffers> for BufferMap {
474-
fn from(value: TestJoinedValueBuffers) -> Self {
475-
let mut buffers = BufferMap::default();
476-
buffers.insert(Cow::Borrowed("integer"), value.integer);
477-
buffers.insert(Cow::Borrowed("float"), value.float);
478-
buffers.insert(Cow::Borrowed("string"), value.string);
479-
buffers
480-
}
481-
}
482-
483377
#[test]
484378
fn test_joined_value() {
485379
let mut context = TestingContext::minimal_plugins();

0 commit comments

Comments
 (0)