flo_scene/host/initialisation_context.rs
1use crate::host::connect_result::*;
2use crate::host::error::*;
3use crate::host::input_stream::*;
4use crate::host::scene_context::*;
5use crate::host::scene_message::*;
6use crate::host::stream_source::*;
7use crate::host::stream_target::*;
8use crate::host::stream_id::*;
9use crate::host::subprogram_id::*;
10
11use futures::prelude::*;
12
13///
14/// The initialisation context is used when setting up scenes and messages within scenes: it provides
15/// routines for creating and connecting programs.
16///
17/// Once the scene is running, the scene control program can be used to similar effect (by sending
18/// `SceneControl` messages)
19///
20pub trait SceneInitialisationContext {
21 ///
22 /// Adds a subprogram to run in this scene
23 ///
24 fn add_subprogram<'a, TProgramFn, TInputMessage, TFuture>(&'a self, program_id: SubProgramId, program: TProgramFn, max_input_waiting: usize)
25 where
26 TFuture: 'static + Send + Future<Output=()>,
27 TInputMessage: 'static + SceneMessage,
28 TProgramFn: 'a + Send + FnOnce(InputStream<TInputMessage>, SceneContext) -> TFuture;
29
30 ///
31 /// Connects the output `stream` of the `source` program to the input of `target`
32 ///
33 /// Sub-programs can send messages without needing to know what handles them, for instance by creating an output stream using
34 /// `scene_context.send(())`. This call provides the means to specify how these streams are connected, for example by
35 /// calling `scene.connect_programs((), some_target_program_id, StreamId::with_message_type::<SomeMessageType>())` to connect
36 /// everything that sends `SomeMessageType` to the subprogram with the ID `some_target_program_id`.
37 ///
38 /// The parameters can be used to specify exactly which stream should be redirected: it's possible to redirect only the streams
39 /// originating from a specific subprogram, or even streams that requested a particular target. A filtering mechanism is also
40 /// provided, in case it's necessary to change the type of the message to suit the target.
41 ///
42 /// The target is usually a specific program, but can also be `StreamTarget::None` to indicate that any messages should be
43 /// dropped with no further action. `StreamTarget::Any` is the default, and will result in the stream blocking until another
44 /// call connects it.
45 ///
46 /// The stream ID specifies which of the streams originating from the souce should be connected. This can either be created
47 /// using `StreamId::with_message_type::<SomeMessage>()` to indicate all outgoing streams of that type from `source`, or
48 /// `StreamId::with_message_type::<SomeMessage>().for_target(target)` to indicate an outgoing stream with a specific destination.
49 ///
50 /// Examples:
51 ///
52 /// ```
53 /// # use flo_scene::*;
54 /// # use futures::prelude::*;
55 /// # use serde::*;
56 /// #
57 /// # #[derive(Serialize, Deserialize)]
58 /// # enum ExampleMessage { Test };
59 /// # impl SceneMessage for ExampleMessage { }
60 /// # #[derive(Serialize, Deserialize)]
61 /// # enum FilteredMessage { Test };
62 /// # impl SceneMessage for FilteredMessage { }
63 /// # let scene = Scene::empty();
64 /// # let subprogram = SubProgramId::new();
65 /// # let source_program = SubProgramId::new();
66 /// # let other_program = SubProgramId::new();
67 /// # let example_filter = FilterHandle::for_filter(|input_stream: InputStream<FilteredMessage>| input_stream.map(|_| ExampleMessage::Test));
68 /// #
69 /// // Connect all the 'ExampleMessage' streams to one program
70 /// scene.connect_programs((), &subprogram, StreamId::with_message_type::<ExampleMessage>());
71 ///
72 /// // Direct the messages for the source_program to other_program instead (takes priority over the 'any' example set up above)
73 /// scene.connect_programs(&source_program, &other_program, StreamId::with_message_type::<ExampleMessage>());
74 ///
75 /// // Make 'other_program' throw away its messages
76 /// scene.connect_programs(&other_program, StreamTarget::None, StreamId::with_message_type::<ExampleMessage>());
77 ///
78 /// // When 'source_program' tries to connect directly to 'subprogram', send its output to 'other_program' instead
79 /// scene.connect_programs(&source_program, &other_program, StreamId::with_message_type::<ExampleMessage>().for_target(&subprogram));
80 ///
81 /// // Use a filter to accept a different incoming message type for a target program
82 /// scene.connect_programs((), StreamTarget::Filtered(example_filter.clone(), other_program), StreamId::with_message_type::<FilteredMessage>());
83 /// scene.connect_programs(&example_filter, StreamTarget::Program(other_program), StreamId::with_message_type::<FilteredMessage>());
84 ///
85 /// // Filter any output if it's connected to an input of a specified type
86 /// scene.connect_programs(&example_filter, (), StreamId::with_message_type::<FilteredMessage>().for_target(&subprogram));
87 /// ```
88 ///
89 fn connect_programs(&self, source: impl Into<StreamSource>, target: impl Into<StreamTarget>, stream: impl Into<StreamId>) -> Result<ConnectionResult, ConnectionError>;
90}