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}