Skip to content

Commit 617e22f

Browse files
committed
Refactor Bufferable so we no longer need join_into
Signed-off-by: Michael X. Grey <[email protected]>
1 parent a40b8d3 commit 617e22f

File tree

7 files changed

+297
-218
lines changed

7 files changed

+297
-218
lines changed

src/buffer/buffer_map.rs

+48-12
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use bevy_ecs::prelude::{Entity, World};
2626
use crate::{
2727
add_listener_to_source, Accessed, AddOperation, AnyBuffer, AnyBufferKey, AnyMessageBox,
2828
Buffer, BufferKeyBuilder, Buffered, Builder, Chain, Gate, GateState, Join, Joined,
29-
OperationError, OperationResult, OperationRoster, Output, UnusedTarget,
29+
OperationError, OperationResult, OperationRoster, Output, UnusedTarget, Bufferable,
3030
};
3131

3232
#[derive(Clone, Default)]
@@ -116,14 +116,22 @@ pub struct BufferIncompatibility {
116116
/// You do not normally have to implement this yourself. Instead you should
117117
/// `#[derive(JoinedValue)]` on a struct that you want a join operation to
118118
/// produce.
119-
pub trait BufferMapLayout: Sized + Clone {
119+
pub trait BufferMapLayout: Sized + Clone + 'static + Send + Sync {
120120
/// Produce a list of the buffers that exist in this layout.
121121
fn buffer_list(&self) -> SmallVec<[AnyBuffer; 8]>;
122122

123123
/// Try to convert a generic [`BufferMap`] into this specific layout.
124124
fn try_from_buffer_map(buffers: &BufferMap) -> Result<Self, IncompatibleLayout>;
125125
}
126126

127+
impl<T: BufferMapLayout> Bufferable for T {
128+
type BufferType = Self;
129+
130+
fn into_buffer(self, _: &mut Builder) -> Self::BufferType {
131+
self
132+
}
133+
}
134+
127135
impl<T: BufferMapLayout> Buffered for T {
128136
fn verify_scope(&self, scope: Entity) {
129137
for buffer in self.buffer_list() {
@@ -231,14 +239,6 @@ pub trait JoinedValue: 'static + Send + Sync + Sized {
231239
/// Trait to describe a layout of buffer keys
232240
pub trait BufferKeyMap: 'static + Send + Sync + Sized + Clone {
233241
type Buffers: 'static + BufferMapLayout + Accessed<Key=Self> + Send + Sync;
234-
235-
fn add_accessor(buffers: &BufferMap, accessor: Entity, world: &mut World) -> OperationResult;
236-
237-
fn create_key(buffers: &BufferMap, builder: &BufferKeyBuilder) -> Self;
238-
239-
fn deep_clone_key(&self) -> Self;
240-
241-
fn is_key_in_use(&self) -> bool;
242242
}
243243

244244
impl BufferMapLayout for BufferMap {
@@ -383,7 +383,7 @@ mod tests {
383383
}
384384

385385
#[test]
386-
fn test_joined_value() {
386+
fn test_try_join() {
387387
let mut context = TestingContext::minimal_plugins();
388388

389389
let workflow = context.spawn_io_workflow(|scope, builder| {
@@ -403,7 +403,7 @@ mod tests {
403403
));
404404

405405
builder
406-
.try_join_into(&buffers)
406+
.try_join(&buffers)
407407
.unwrap()
408408
.connect(scope.terminate);
409409
});
@@ -421,4 +421,40 @@ mod tests {
421421
assert_eq!(value.string, "hello");
422422
assert!(context.no_unhandled_errors());
423423
}
424+
425+
#[test]
426+
fn test_joined_value() {
427+
let mut context = TestingContext::minimal_plugins();
428+
429+
let workflow = context.spawn_io_workflow(|scope, builder| {
430+
let buffers = TestJoinedValueBuffers {
431+
integer: builder.create_buffer(BufferSettings::default()),
432+
float: builder.create_buffer(BufferSettings::default()),
433+
string: builder.create_buffer(BufferSettings::default()),
434+
};
435+
436+
scope.input.chain(builder).fork_unzip((
437+
|chain: Chain<_>| chain.connect(buffers.integer.input_slot()),
438+
|chain: Chain<_>| chain.connect(buffers.float.input_slot()),
439+
|chain: Chain<_>| chain.connect(buffers.string.input_slot()),
440+
));
441+
442+
builder
443+
.join(buffers)
444+
.connect(scope.terminate);
445+
});
446+
447+
let mut promise = context.command(|commands| {
448+
commands
449+
.request((5_i64, 3.14_f64, "hello".to_string()), workflow)
450+
.take_response()
451+
});
452+
453+
context.run_with_conditions(&mut promise, Duration::from_secs(2));
454+
let value: TestJoinedValue = promise.take().available().unwrap();
455+
assert_eq!(value.integer, 5);
456+
assert_eq!(value.float, 3.14);
457+
assert_eq!(value.string, "hello");
458+
assert!(context.no_unhandled_errors());
459+
}
424460
}

src/buffer/bufferable.rs

+51-121
Original file line numberDiff line numberDiff line change
@@ -20,137 +20,18 @@ use smallvec::SmallVec;
2020

2121
use crate::{
2222
Accessed, AddOperation, Buffer, BufferSettings, Buffered, Builder, Chain,
23-
CleanupWorkflowConditions, CloneFromBuffer, Join, Joined, Listen, Output, Scope, ScopeSettings,
24-
UnusedTarget,
23+
CloneFromBuffer, Join, Joined, Output, UnusedTarget,
2524
};
2625

2726
pub type BufferKeys<B> = <<B as Bufferable>::BufferType as Accessed>::Key;
2827
pub type JoinedItem<B> = <<B as Bufferable>::BufferType as Joined>::Item;
2928

3029
pub trait Bufferable {
31-
type BufferType: Joined + Accessed;
30+
type BufferType: Buffered;
3231

3332
/// Convert these bufferable workflow elements into buffers if they are not
3433
/// buffers already.
3534
fn into_buffer(self, builder: &mut Builder) -> Self::BufferType;
36-
37-
/// Join these bufferable workflow elements. Each time every buffer contains
38-
/// at least one element, this will pull the oldest element from each buffer
39-
/// and join them into a tuple that gets sent to the target.
40-
///
41-
/// If you need a more general way to get access to one or more buffers,
42-
/// use [`listen`](Self::listen) instead.
43-
fn join<'w, 's, 'a, 'b>(
44-
self,
45-
builder: &'b mut Builder<'w, 's, 'a>,
46-
) -> Chain<'w, 's, 'a, 'b, JoinedItem<Self>>
47-
where
48-
Self: Sized,
49-
Self::BufferType: 'static + Send + Sync,
50-
JoinedItem<Self>: 'static + Send + Sync,
51-
{
52-
let scope = builder.scope();
53-
let buffers = self.into_buffer(builder);
54-
buffers.verify_scope(scope);
55-
56-
let join = builder.commands.spawn(()).id();
57-
let target = builder.commands.spawn(UnusedTarget).id();
58-
builder.commands.add(AddOperation::new(
59-
Some(scope),
60-
join,
61-
Join::new(buffers, target),
62-
));
63-
64-
Output::new(scope, target).chain(builder)
65-
}
66-
67-
/// Create an operation that will output buffer access keys each time any
68-
/// one of the buffers is modified. This can be used to create a node in a
69-
/// workflow that wakes up every time one or more buffers change, and then
70-
/// operates on those buffers.
71-
///
72-
/// For an operation that simply joins the contents of two or more outputs
73-
/// or buffers, use [`join`](Self::join) instead.
74-
fn listen<'w, 's, 'a, 'b>(
75-
self,
76-
builder: &'b mut Builder<'w, 's, 'a>,
77-
) -> Chain<'w, 's, 'a, 'b, BufferKeys<Self>>
78-
where
79-
Self: Sized,
80-
Self::BufferType: 'static + Send + Sync,
81-
BufferKeys<Self>: 'static + Send + Sync,
82-
{
83-
let scope = builder.scope();
84-
let buffers = self.into_buffer(builder);
85-
buffers.verify_scope(scope);
86-
87-
let listen = builder.commands.spawn(()).id();
88-
let target = builder.commands.spawn(UnusedTarget).id();
89-
builder.commands.add(AddOperation::new(
90-
Some(scope),
91-
listen,
92-
Listen::new(buffers, target),
93-
));
94-
95-
Output::new(scope, target).chain(builder)
96-
}
97-
98-
/// Alternative way to call [`Builder::on_cleanup`].
99-
fn on_cleanup<Settings>(
100-
self,
101-
builder: &mut Builder,
102-
build: impl FnOnce(Scope<BufferKeys<Self>, (), ()>, &mut Builder) -> Settings,
103-
) where
104-
Self: Sized,
105-
Self::BufferType: 'static + Send + Sync,
106-
BufferKeys<Self>: 'static + Send + Sync,
107-
Settings: Into<ScopeSettings>,
108-
{
109-
builder.on_cleanup(self, build)
110-
}
111-
112-
/// Alternative way to call [`Builder::on_cancel`].
113-
fn on_cancel<Settings>(
114-
self,
115-
builder: &mut Builder,
116-
build: impl FnOnce(Scope<BufferKeys<Self>, (), ()>, &mut Builder) -> Settings,
117-
) where
118-
Self: Sized,
119-
Self::BufferType: 'static + Send + Sync,
120-
BufferKeys<Self>: 'static + Send + Sync,
121-
Settings: Into<ScopeSettings>,
122-
{
123-
builder.on_cancel(self, build)
124-
}
125-
126-
/// Alternative way to call [`Builder::on_terminate`].
127-
fn on_terminate<Settings>(
128-
self,
129-
builder: &mut Builder,
130-
build: impl FnOnce(Scope<BufferKeys<Self>, (), ()>, &mut Builder) -> Settings,
131-
) where
132-
Self: Sized,
133-
Self::BufferType: 'static + Send + Sync,
134-
BufferKeys<Self>: 'static + Send + Sync,
135-
Settings: Into<ScopeSettings>,
136-
{
137-
builder.on_terminate(self, build)
138-
}
139-
140-
/// Alternative way to call [`Builder::on_cleanup_if`].
141-
fn on_cleanup_if<Settings>(
142-
self,
143-
builder: &mut Builder,
144-
conditions: CleanupWorkflowConditions,
145-
build: impl FnOnce(Scope<BufferKeys<Self>, (), ()>, &mut Builder) -> Settings,
146-
) where
147-
Self: Sized,
148-
Self::BufferType: 'static + Send + Sync,
149-
BufferKeys<Self>: 'static + Send + Sync,
150-
Settings: Into<ScopeSettings>,
151-
{
152-
builder.on_cleanup_if(conditions, self, build)
153-
}
15435
}
15536

15637
impl<T: 'static + Send + Sync> Bufferable for Buffer<T> {
@@ -179,6 +60,54 @@ impl<T: 'static + Send + Sync> Bufferable for Output<T> {
17960
}
18061
}
18162

63+
pub trait Joinable: Bufferable {
64+
type Item;
65+
66+
fn join<'w, 's, 'a, 'b>(
67+
self,
68+
builder: &'b mut Builder<'w, 's, 'a>,
69+
) -> Chain<'w, 's, 'a, 'b, Self::Item>;
70+
}
71+
72+
impl<B> Joinable for B
73+
where
74+
B: Bufferable,
75+
B::BufferType: Joined,
76+
{
77+
type Item = JoinedItem<B>;
78+
79+
fn join<'w, 's, 'a, 'b>(
80+
self,
81+
builder: &'b mut Builder<'w, 's, 'a>,
82+
) -> Chain<'w, 's, 'a, 'b, Self::Item> {
83+
self.into_buffer(builder).join(builder)
84+
}
85+
}
86+
87+
pub trait Accessible: Bufferable {
88+
type Keys;
89+
90+
fn listen<'w, 's, 'a, 'b>(
91+
self,
92+
builder: &'b mut Builder<'w, 's, 'a>,
93+
) -> Chain<'w, 's, 'a, 'b, Self::Keys>;
94+
}
95+
96+
impl<B> Accessible for B
97+
where
98+
B: Bufferable,
99+
B::BufferType: Accessed,
100+
{
101+
type Keys = BufferKeys<Self>;
102+
103+
fn listen<'w, 's, 'a, 'b>(
104+
self,
105+
builder: &'b mut Builder<'w, 's, 'a>,
106+
) -> Chain<'w, 's, 'a, 'b, Self::Keys> {
107+
self.into_buffer(builder).listen(builder)
108+
}
109+
}
110+
182111
macro_rules! impl_bufferable_for_tuple {
183112
($($T:ident),*) => {
184113
#[allow(non_snake_case)]
@@ -248,6 +177,7 @@ impl<T> IterBufferable for T
248177
where
249178
T: IntoIterator,
250179
T::Item: Bufferable,
180+
<T::Item as Bufferable>::BufferType: Joined,
251181
{
252182
type BufferElement = <T::Item as Bufferable>::BufferType;
253183

0 commit comments

Comments
 (0)