SceneMessage

Trait SceneMessage 

Source
pub trait SceneMessage:
    'static
    + Sized
    + Send
    + Unpin
    + Serialize
    + for<'a> Deserialize<'a> {
    // Provided methods
    fn default_target() -> StreamTarget { ... }
    fn initialise(init_context: &impl SceneInitialisationContext) { ... }
    fn allow_thread_stealing_by_default() -> bool { ... }
    fn serializable() -> bool { ... }
    fn message_type_name() -> String { ... }
}
Expand description

Trait implemented by messages that can be sent via a scene

A basic message type can be declared like this:

#[derive(Serialize, Deserialize)]
struct ExampleMessage { some_value: i64 };

impl SceneMessage for ExampleMessage { }

Messages are initialised the first time they are encountered in a scene. The initialise() function can be used to customise this if needed: for example, to set up the default set of connections that a message should support.

Scene messages should implement the serde serialization primitives but can return only errors. These types should also return false from serializable() so that the serialization filters aren’t generated. Most messages can use #[derive(Serialize, Deserialize)] to generate the serialization routines.

An implementation like the following can be used for non-serializable messages:

use serde::*;
use serde::de::{Error as DeError};
use serde::ser::{Error as SeError};

struct ExampleMessage;
 
impl Serialize for ExampleMessage {
    fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer 
    {
        Err(S::Error::custom("ExampleMessage cannot be serialized"))
    }
}
 
impl<'a> Deserialize<'a> for ExampleMessage {
    fn deserialize<D>(_: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'a> 
    {
        Err(D::Error::custom("RunCommand cannot be serialized"))
    }
}
 
impl SceneMessage for ExampleMessage {
    fn serializable() -> bool { false }
}

Another approach is to serialize via an intermediate type, which can be used when special treatment is needed for serialization or deserialization. This can look like this:

use serde::*;

#[derive(Serialize, Deserialize)]
struct IntermediateMessage { serialized_number: usize }
 
// This is a contrived example that serializes a different number

impl Serialize for ExampleMessage {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer 
    {
        IntermediateMessage { serialized_number: self.real_number + 1 }.serialize(serializer)
    }
}
 
impl<'a> Deserialize<'a> for ExampleMessage {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'a> 
    {
        let intermediate = IntermediateMessage::deserialize(deserializer)?;
        Ok(ExampleMessage { real_number: intermediate.serialized_number - 1 })
    }
}

Provided Methods§

Source

fn default_target() -> StreamTarget

The default target for this message type

This is StreamTarget::Any by default, so streams will wait to be connected. This can be set to StreamTarget::None to throw away messages, or even to a program ID if messages should be sent to a particular program by default.

Setting a default message target makes it much easier to start programs that use this message type as there’s no need to specifically set up the connections separately. Ideally aim for every message type to have a default target and only use the connect_programs() function to specify exceptions, avoiding the ‘wall o’configuration’ problem commonly encountered when using dependency injection to link together a large program.

Source

fn initialise(init_context: &impl SceneInitialisationContext)

Sets up this message type in a scene. This can be an opportunity to set up default filters and connections for a particular message type. This is called the first time that a message is referenced in a scene.

Source

fn allow_thread_stealing_by_default() -> bool

True if input streams for this message type should allow thread stealing by default

Thread stealing will immediately run a future when a message is queued instead of waiting for the future to be polled in the main loop.

Source

fn serializable() -> bool

True if this message supports serialization

This is true by default, but can be overridden to return false. Messages that are not serializable do not generate filters for receiving serialized messages.

All messages must implement the serialization interfaces, but in order to allow messages that are intended to only be sent within an application (eg, messages that contain function calls or similar non-serializable values, this can be overridden to return false)

Source

fn message_type_name() -> String

A string that identifies this message type uniquely when serializing

An error will occur if two types use the same name in the same process. We use std::any::type_name() by default but this does not have a guaranteed format between Rust versions and may not be unique, so it’s strongly recommended to override this function to return a specific value.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

Source§

impl SceneMessage for ErrorOutput

Source§

impl SceneMessage for IdleRequest

Source§

impl SceneMessage for SceneControl

Source§

impl SceneMessage for SceneUpdate

Source§

impl SceneMessage for TextInput

Source§

impl SceneMessage for TextInputResult

Source§

impl SceneMessage for TextOutput

Source§

impl SceneMessage for TimerRequest

Source§

impl SceneMessage for DescribeCommandRequest

Source§

impl SceneMessage for DescribeCommandResponse

Source§

impl SceneMessage for ListCommandResponse

Source§

impl SceneMessage for IdleNotification

Source§

impl SceneMessage for TimeOut

Source§

impl<T: SceneGuestMessage> SceneMessage for T

SceneGuestMessage is a cut-down version of SceneMessage: implicitly implement SceneMessage for every guest message

Unlike

Source§

impl<TMessageType: SceneMessage> SceneMessage for Subscribe<TMessageType>

Source§

impl<TParameter, TResponse> SceneMessage for RunCommand<TParameter, TResponse>
where for<'de> TParameter: 'static + Unpin + Send + Serialize + Deserialize<'de>, for<'de> TResponse: 'static + Unpin + Send + Serialize + Deserialize<'de>,

Source§

impl<TResponseData: 'static + Send + SceneMessage> SceneMessage for QueryResponse<TResponseData>

Source§

impl<TResponseData: Send + Unpin + SceneMessage> SceneMessage for Query<TResponseData>

Source§

impl<TSerializedType> SceneMessage for SerializedMessage<TSerializedType>
where TSerializedType: 'static + Send + Unpin,