use crate::host::error::*;
use crate::host::filter::*;
use crate::host::initialisation_context::*;
use crate::host::input_stream::*;
use crate::host::output_sink::*;
use crate::host::scene::*;
use crate::host::scene_context::*;
use crate::host::scene_core::*;
use crate::host::scene_message::*;
use crate::host::serialization::*;
use crate::host::serialization_context::*;
use crate::host::stream_source::*;
use crate::host::stream_target::*;
use crate::host::subprogram_id::*;
use crate::host::programs::{SceneControl};
#[cfg(feature="guest_programs")]
use crate::guest::*;
use futures::prelude::*;
use futures::channel::mpsc::{Sender};
use futures::stream::{BoxStream};
use futures::task::{Waker};
use once_cell::sync::{Lazy};
use std::any::*;
use std::collections::*;
use std::hash::*;
use std::sync::*;
static STREAM_TYPE_FUNCTIONS: Lazy<RwLock<HashMap<TypeId, StreamTypeFunctions>>> = Lazy::new(|| RwLock::new(HashMap::new()));
type ConnectOutputToInputFn = Arc<dyn Send + Sync + Fn(&Arc<dyn Send + Sync + Any>, &Arc<dyn Send + Sync + Any>, bool) -> Result<Option<Waker>, ConnectionError>>;
type ConnectOutputToDiscardFn = Arc<dyn Send + Sync + Fn(&Arc<dyn Send + Sync + Any>) -> Result<Option<Waker>, ConnectionError>>;
type DisconnectOutputFn = Arc<dyn Send + Sync + Fn(&Arc<dyn Send + Sync + Any>) -> Result<Option<Waker>, ConnectionError>>;
type CloseInputFn = Arc<dyn Send + Sync + Fn(&Arc<dyn Send + Sync + Any>) -> Result<Option<Waker>, ConnectionError>>;
type IsIdleFn = Arc<dyn Send + Sync + Fn(&Arc<dyn Send + Sync + Any>) -> Result<bool, ConnectionError>>;
type WaitingForIdleFn = Arc<dyn Send + Sync + Fn(&Arc<dyn Send + Sync + Any>, usize) -> Result<IdleInputStreamCore, ConnectionError>>;
type DefaultTargetFn = Arc<dyn Send + Sync + Fn() -> StreamTarget>;
type ActiveTargetFn = Arc<dyn Send + Sync + Fn(&Arc<dyn Send + Sync + Any>) -> Result<StreamTarget, ConnectionError>>;
type ReconnectSinkFn = Arc<dyn Send + Sync + Fn(&Arc<Mutex<SceneCore>>, &Arc<dyn Send + Sync + Any>, SubProgramId, StreamTarget) -> Result<Option<Waker>, ConnectionError>>;
type InitialiseFn = Arc<dyn Send + Sync + Fn(&Scene)>;
type SendGuestMessagesFn = Arc<dyn Send + Sync + Fn(StreamTarget, &SceneContext, Box<dyn SerializationContext>) -> Result<Box<dyn 'static + Send + Sink<Vec<u8>, Error=SceneSendError<Vec<u8>>>>, ConnectionError>>;
#[cfg(feature="guest_programs")]
type RunHostSubProgramFn = Arc<dyn Send + Sync + Fn(SubProgramId, usize, Sender<GuestAction>, BoxStream<'static, GuestResult>) -> SceneControl>;
struct StreamTypeFunctions {
connect_output_to_input: ConnectOutputToInputFn,
connect_output_to_discard: ConnectOutputToDiscardFn,
disconnect_output: DisconnectOutputFn,
close_input: CloseInputFn,
is_idle: IsIdleFn,
waiting_for_idle: WaitingForIdleFn,
default_target: DefaultTargetFn,
active_target: ActiveTargetFn,
reconnect_sink: ReconnectSinkFn,
#[cfg(all(feature="postcard", feature="guest_programs"))]
run_host_subprogram_postcard: RunHostSubProgramFn,
#[cfg(any(feature="postcard", target_family="wasm"))]
send_guest_messages: SendGuestMessagesFn,
initialise: InitialiseFn,
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
enum StreamIdType {
MessageType,
Target(StreamTarget),
}
#[derive(Clone, Eq, Debug)]
pub struct StreamId {
stream_id_type: StreamIdType,
message_type_name: &'static str,
message_type: TypeId,
input_stream_core_type: TypeId,
}
impl PartialEq for StreamId {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.stream_id_type == other.stream_id_type && self.message_type == other.message_type
}
}
impl Hash for StreamId {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.stream_id_type.hash(state);
self.message_type.hash(state);
}
}
impl StreamTypeFunctions {
pub fn for_message_type<TMessageType>() -> Self
where
TMessageType: 'static + SceneMessage,
{
static FILTERS: Lazy<RwLock<HashMap<TypeId, Vec<FilterHandle>>>> = Lazy::new(|| RwLock::new(HashMap::new()));
StreamTypeFunctions {
connect_output_to_input: Arc::new(|output_sink_any, input_stream_any, close_when_dropped| {
let output_sink = output_sink_any.clone().downcast::<Mutex<OutputSinkCore<TMessageType>>>().map_err(|_| ConnectionError::UnexpectedConnectionType)?;
let input_stream = input_stream_any.clone().downcast::<Mutex<InputStreamCore<TMessageType>>>().map_err(|_| ConnectionError::UnexpectedConnectionType)?;
let waker = if !close_when_dropped {
OutputSinkCore::set_new_target(&output_sink, OutputSinkTarget::Input(Arc::downgrade(&input_stream)))
} else {
OutputSinkCore::set_new_target(&output_sink, OutputSinkTarget::CloseWhenDropped(Arc::downgrade(&input_stream)))
};
Ok(waker)
}),
connect_output_to_discard: Arc::new(|output_sink_any| {
let output_sink = output_sink_any.clone().downcast::<Mutex<OutputSinkCore<TMessageType>>>().map_err(|_| ConnectionError::UnexpectedConnectionType)?;
let waker = OutputSinkCore::set_new_target(&output_sink, OutputSinkTarget::Discard);
Ok(waker)
}),
disconnect_output: Arc::new(|output_sink_any| {
let output_sink = output_sink_any.clone().downcast::<Mutex<OutputSinkCore<TMessageType>>>().map_err(|_| ConnectionError::UnexpectedConnectionType)?;
let waker = OutputSinkCore::set_new_target(&output_sink, OutputSinkTarget::Disconnected);
Ok(waker)
}),
close_input: Arc::new(|input_stream_any| {
let input_stream = input_stream_any.clone().downcast::<Mutex<InputStreamCore<TMessageType>>>().map_err(|_| ConnectionError::UnexpectedConnectionType)?;
let waker = input_stream.lock().unwrap().close();
Ok(waker)
}),
is_idle: Arc::new(|input_stream_any| {
let input_stream = input_stream_any.clone().downcast::<Mutex<InputStreamCore<TMessageType>>>().map_err(|_| ConnectionError::UnexpectedConnectionType)?;
let is_idle = input_stream.lock().unwrap().is_idle();
Ok(is_idle)
}),
waiting_for_idle: Arc::new(|input_stream_any, max_idle_queue_len| {
let input_stream = input_stream_any.clone().downcast::<Mutex<InputStreamCore<TMessageType>>>().map_err(|_| ConnectionError::UnexpectedConnectionType)?;
let dropper = InputStreamCore::<TMessageType>::waiting_for_idle(&input_stream, max_idle_queue_len);
Ok(dropper)
}),
default_target: Arc::new(|| {
TMessageType::default_target()
}),
active_target: Arc::new(|output_sink_core_any| {
let output_sink = output_sink_core_any.clone().downcast::<Mutex<OutputSinkCore<TMessageType>>>().map_err(|_| ConnectionError::UnexpectedConnectionType)?;
let output_sink_target = output_sink.lock().unwrap().target().clone();
match &output_sink_target {
OutputSinkTarget::Disconnected => Ok(StreamTarget::Any),
OutputSinkTarget::Discard => Ok(StreamTarget::None),
OutputSinkTarget::Input(input_core) |
OutputSinkTarget::FixedInput(input_core) |
OutputSinkTarget::CloseWhenDropped(input_core) => {
if let Some(input_core) = input_core.upgrade() {
Ok(StreamTarget::Program(input_core.lock().unwrap().target_program_id()))
} else {
Ok(StreamTarget::None)
}
}
}
}),
reconnect_sink: Arc::new(|scene_core, output_sink_core_any, source_program, stream_target| {
let new_target = SceneCore::sink_for_target::<TMessageType>(scene_core, &source_program, stream_target)?;
let output_sink = output_sink_core_any.clone().downcast::<Mutex<OutputSinkCore<TMessageType>>>().map_err(|_| ConnectionError::UnexpectedConnectionType)?;
let waker = OutputSinkCore::set_new_target(&output_sink, new_target);
Ok(waker)
}),
#[cfg(feature="postcard")]
run_host_subprogram_postcard: Arc::new(|program_id, max_waiting, actions, results|
SceneControl::start_program(program_id, move |input: InputStream<TMessageType>, context| async move {
run_host_subprogram(input, context, actions, results).await;
}, max_waiting)),
#[cfg(any(feature="postcard", target_family="wasm"))]
send_guest_messages: Arc::new(|target, context, serialization_context| {
let sink = context.send::<TMessageType>(target)?;
let sink = sink
.sink_map_err(|_| SceneSendError::<Vec<u8>>::ErrorAfterDeserialization) .with(move |msg: Vec<u8>| {
let deserialized = TMessageType::from_guest_message(&msg, &serialization_context)
.map_err(move |err| err.map(move |_| msg));
async move {
deserialized
}
});
Ok(Box::new(sink))
}),
initialise: Arc::new(move |scene| {
use std::mem;
let serialization_filters = {
let filters = (*FILTERS).read().unwrap();
if let Some(existing_filters) = filters.get(&TypeId::of::<TMessageType>()) {
existing_filters.clone()
} else {
mem::drop(filters);
#[cfg(feature="json")]
install_serializable_type(|msg: TMessageType| msg.to_json(), |json| TMessageType::from_json(json)).unwrap();
#[cfg(any(feature="postcard", target_family="wasm"))]
install_serializable_type(
|msg: TMessageType| msg.to_guest_message(&DisconnectedSerializationContext).map(|ok| GuestMessage(ok)),
|postcard| TMessageType::from_guest_message(&postcard.0, &DisconnectedSerializationContext))
.unwrap();
let mut filters = (*FILTERS).write().unwrap();
if let Some(existing_filters) = filters.get(&TypeId::of::<TMessageType>()) {
existing_filters.clone()
} else {
let new_filters = if TMessageType::serializable() {
create_default_serializer_filters::<TMessageType>()
} else {
vec![]
};
filters.insert(TypeId::of::<TMessageType>(), new_filters.clone());
new_filters
}
}
};
for filter in serialization_filters.iter() {
scene.connect_programs(StreamSource::Filtered(filter.clone()), (), filter.source_stream_id_any().unwrap()).ok();
}
TMessageType::initialise(scene)
}),
}
}
pub fn add<TMessageType>()
where
TMessageType: 'static + SceneMessage,
{
let type_id = TypeId::of::<TMessageType>();
let mut stream_type_functions = STREAM_TYPE_FUNCTIONS.write().unwrap();
stream_type_functions.entry(type_id)
.or_insert_with(|| StreamTypeFunctions::for_message_type::<TMessageType>());
}
pub fn connect_output_to_input(type_id: &TypeId) -> Option<ConnectOutputToInputFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.connect_output_to_input))
}
pub fn connect_output_to_discard(type_id: &TypeId) -> Option<ConnectOutputToDiscardFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.connect_output_to_discard))
}
pub fn disconnect_output(type_id: &TypeId) -> Option<DisconnectOutputFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.disconnect_output))
}
pub fn close_input(type_id: &TypeId) -> Option<CloseInputFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.close_input))
}
pub fn is_idle(type_id: &TypeId) -> Option<IsIdleFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.is_idle))
}
pub fn waiting_for_idle(type_id: &TypeId) -> Option<WaitingForIdleFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.waiting_for_idle))
}
pub fn default_target(type_id: &TypeId) -> Option<DefaultTargetFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.default_target))
}
pub fn active_target(type_id: &TypeId) -> Option<ActiveTargetFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.active_target))
}
pub fn reconnect_output_sink(type_id: &TypeId) -> Option<ReconnectSinkFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.reconnect_sink))
}
#[cfg(all(feature="postcard", feature="guest_programs"))]
pub fn run_host_subprogram_postcard(type_id: &TypeId) -> Option<RunHostSubProgramFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.run_host_subprogram_postcard))
}
#[cfg(any(feature="postcard", target_family="wasm"))]
pub fn send_guest_messages(type_id: &TypeId) -> Option<SendGuestMessagesFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.send_guest_messages))
}
pub fn initialise(type_id: &TypeId) -> Option<InitialiseFn> {
let stream_type_functions = STREAM_TYPE_FUNCTIONS.read().unwrap();
stream_type_functions.get(type_id)
.map(|all_functions| Arc::clone(&all_functions.initialise))
}
}
impl StreamId {
pub fn with_message_type<TMessageType>() -> Self
where
TMessageType: 'static + SceneMessage,
{
StreamTypeFunctions::add::<TMessageType>();
StreamId {
stream_id_type: StreamIdType::MessageType,
message_type_name: type_name::<TMessageType>(),
message_type: TypeId::of::<TMessageType>(),
input_stream_core_type: TypeId::of::<Mutex<InputStreamCore<TMessageType>>>(),
}
}
pub fn for_target(&self, target: impl Into<StreamTarget>) -> Self {
StreamId {
stream_id_type: StreamIdType::Target(target.into()),
message_type_name: self.message_type_name,
message_type: self.message_type,
input_stream_core_type: self.input_stream_core_type,
}
}
pub fn as_message_type(&self) -> Self {
StreamId {
stream_id_type: StreamIdType::MessageType,
message_type_name: self.message_type_name,
message_type: self.message_type,
input_stream_core_type: self.input_stream_core_type,
}
}
pub fn target_program(&self) -> Option<SubProgramId> {
match self.stream_id_type {
StreamIdType::MessageType => None,
StreamIdType::Target(StreamTarget::Program(target_id)) => Some(target_id),
StreamIdType::Target(StreamTarget::Filtered(_, target_id)) => Some(target_id),
StreamIdType::Target(_) => None,
}
}
pub fn message_type(&self) -> TypeId {
self.message_type
}
pub fn message_type_name(&self) -> String {
self.message_type_name.into()
}
pub fn default_target(&self) -> StreamTarget {
let message_type = self.message_type();
if let Some(default_target) = StreamTypeFunctions::default_target(&message_type) {
default_target()
} else {
StreamTarget::None
}
}
pub (crate) fn input_stream_core_type(&self) -> TypeId {
self.input_stream_core_type
}
pub (crate) fn connect_output_to_input(&self, output_sink: &Arc<dyn Send + Sync + Any>, input_stream: &Arc<dyn Send + Sync + Any>, close_when_dropped: bool) -> Result<Option<Waker>, ConnectionError> {
let message_type = self.message_type();
if let Some(connect_input) = StreamTypeFunctions::connect_output_to_input(&message_type) {
(connect_input)(output_sink, input_stream, close_when_dropped)
} else {
Err(ConnectionError::UnexpectedConnectionType)
}
}
pub (crate) fn connect_output_to_discard(&self, output_sink: &Arc<dyn Send + Sync + Any>) -> Result<Option<Waker>, ConnectionError> {
let message_type = self.message_type();
if let Some(connect_input) = StreamTypeFunctions::connect_output_to_discard(&message_type) {
(connect_input)(output_sink)
} else {
Err(ConnectionError::UnexpectedConnectionType)
}
}
pub (crate) fn disconnect_output(&self, output_sink: &Arc<dyn Send + Sync + Any>) -> Result<Option<Waker>, ConnectionError> {
let message_type = self.message_type();
if let Some(connect_input) = StreamTypeFunctions::disconnect_output(&message_type) {
(connect_input)(output_sink)
} else {
Err(ConnectionError::UnexpectedConnectionType)
}
}
pub (crate) fn close_input(&self, input_stream: &Arc<dyn Send + Sync + Any>) -> Result<Option<Waker>, ConnectionError> {
let message_type = self.message_type();
if let Some(close_input) = StreamTypeFunctions::close_input(&message_type) {
(close_input)(input_stream)
} else {
Err(ConnectionError::UnexpectedConnectionType)
}
}
pub (crate) fn is_idle(&self, input_stream: &Arc<dyn Send + Sync + Any>) -> Result<bool, ConnectionError> {
let message_type = self.message_type();
if let Some(is_idle) = StreamTypeFunctions::is_idle(&message_type) {
(is_idle)(input_stream)
} else {
Err(ConnectionError::UnexpectedConnectionType)
}
}
pub (crate) fn waiting_for_idle(&self, input_stream: &Arc<dyn Send + Sync + Any>, max_idle_queue_len: usize) -> Result<IdleInputStreamCore, ConnectionError> {
let message_type = self.message_type();
if let Some(waiting_for_idle) = StreamTypeFunctions::waiting_for_idle(&message_type) {
(waiting_for_idle)(input_stream, max_idle_queue_len)
} else {
Err(ConnectionError::UnexpectedConnectionType)
}
}
pub (crate) fn initialise_in_scene(&self, scene: &Scene) -> Result<(), ConnectionError> {
let message_type = self.message_type();
if let Some(initialise) = StreamTypeFunctions::initialise(&message_type) {
(initialise)(scene);
Ok(())
} else {
Err(ConnectionError::UnexpectedConnectionType)
}
}
pub (crate) fn active_target_for_output_sink(&self, output_sink_core: &Arc<dyn Send + Sync + Any>) -> Result<StreamTarget, ConnectionError> {
let message_type = self.message_type();
if let Some(active_target) = StreamTypeFunctions::active_target(&message_type) {
(active_target)(output_sink_core)
} else {
Err(ConnectionError::UnexpectedConnectionType)
}
}
pub (crate) fn reconnect_output_sink(&self, scene_core: &Arc<Mutex<SceneCore>>, output_sink_core: &Arc<dyn Send + Sync + Any>, source_program: SubProgramId, new_target: StreamTarget) -> Result<Option<Waker>, ConnectionError> {
let message_type = self.message_type();
if let Some(reconnect_output_sink) = StreamTypeFunctions::reconnect_output_sink(&message_type) {
(reconnect_output_sink)(scene_core, output_sink_core, source_program, new_target)
} else {
Err(ConnectionError::UnexpectedConnectionType)
}
}
#[cfg(all(feature="postcard", feature="guest_programs"))]
pub fn run_host_subprogram_postcard(&self, program_id: SubProgramId, max_input_waiting: usize, actions: Sender<GuestAction>, results: impl 'static + Send + Stream<Item=GuestResult>) -> Result<SceneControl, ConnectionError> {
let message_type = self.message_type();
if let Some(run_host_subprogram_postcard) = StreamTypeFunctions::run_host_subprogram_postcard(&message_type) {
Ok((run_host_subprogram_postcard)(program_id, max_input_waiting, actions, results.boxed()))
} else {
Err(ConnectionError::UnexpectedConnectionType)
}
}
#[cfg(any(feature="postcard", target_family="wasm"))]
pub fn send_guest_messages(&self, target: StreamTarget, context: &SceneContext, serialization_context: impl 'static + SerializationContext) -> Result<Box<dyn 'static + Send + Sink<Vec<u8>, Error=SceneSendError<Vec<u8>>>>, ConnectionError> {
let serialization_context = Box::new(serialization_context);
let message_type = self.message_type();
if let Some(send_guest_messages) = StreamTypeFunctions::send_guest_messages(&message_type) {
(send_guest_messages)(target, context, serialization_context)
} else {
Err(ConnectionError::UnexpectedConnectionType)
}
}
}
mod serialization {
use super::*;
use serde::*;
#[derive(Serialize, Deserialize)]
enum SerializedStreamId {
Serializable { type_name: String, target: Option<SubProgramId> },
RustType { type_name: String, target: Option<SubProgramId> },
}
impl Serialize for StreamId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let serialized = if let Some(serializable_name) = self.serialization_type_name() {
SerializedStreamId::Serializable { type_name: serializable_name, target: self.target_program() }
} else {
SerializedStreamId::RustType { type_name: self.message_type_name(), target: self.target_program() }
};
serialized.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for StreamId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let stream_id = SerializedStreamId::deserialize(deserializer)?;
match stream_id {
SerializedStreamId::Serializable { type_name, target } => {
if let Some(stream_id) = StreamId::with_serialization_type(type_name) {
if let Some(target) = target {
Ok(stream_id.for_target(target))
} else {
Ok(stream_id)
}
} else {
todo!()
}
}
SerializedStreamId::RustType { type_name, target } => {
if let Some(stream_id) = StreamId::with_rust_type(type_name) {
if let Some(target) = target {
Ok(stream_id.for_target(target))
} else {
Ok(stream_id)
}
} else {
todo!()
}
}
}
}
}
}