From e58c16735a156360c5875655c11a00f1828b1ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Wawrzyniec=20Urba=C5=84czyk?= Date: Tue, 26 May 2020 14:41:03 +0200 Subject: [PATCH] Attaching visualization creates a channel for passing the updata data. (https://github.com/enso-org/ide/pull/460) Original commit: https://github.com/enso-org/ide/commit/23286ad8c9f86d2e3f36cc93ff67f5fc13b654b4 --- .../rust/ide/src/model/execution_context.rs | 106 ++++++++++++++++-- .../model/synchronized/execution_context.rs | 10 +- 2 files changed, 101 insertions(+), 15 deletions(-) diff --git a/gui/src/rust/ide/src/model/execution_context.rs b/gui/src/rust/ide/src/model/execution_context.rs index 3d9b04ba02e..b5c4b8c6150 100644 --- a/gui/src/rust/ide/src/model/execution_context.rs +++ b/gui/src/rust/ide/src/model/execution_context.rs @@ -11,6 +11,55 @@ use std::collections::HashMap; use uuid::Uuid; + +// =============== +// === Aliases === +// =============== + +/// An identifier of called definition in module. +pub type DefinitionId = crate::double_representation::definition::Id; + +/// An identifier of expression. +pub type ExpressionId = ast::Id; + + + +// =============================== +// === VisualizationUpdateData === +// =============================== + +/// An update data that notification receives from the interpreter. Owns the binary data generated +/// for visualization by the Language Server. +/// +/// Binary data can be accessed through `Deref` or `AsRef` implementations. +/// +/// The inner storage is private and users should not make any assumptions about it. +#[derive(Clone,Debug)] +pub struct VisualizationUpdateData(Vec); + +impl VisualizationUpdateData { + /// Wraps given vector with binary data into a visualization update data. + pub fn new(data:Vec) -> VisualizationUpdateData { + VisualizationUpdateData(data) + } +} + +impl AsRef<[u8]> for VisualizationUpdateData { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl Deref for VisualizationUpdateData { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.as_ref() + } +} + + + // ============== // === Errors === // ============== @@ -31,11 +80,6 @@ pub struct InvalidVisualizationId(); // === StackItem === // ================= -/// An identifier of called definition in module. -pub type DefinitionId = crate::double_representation::definition::Id; -/// An identifier of expression. -pub type ExpressionId = ast::Id; - /// A specific function call occurring within another function's definition body. /// /// This is a single item in ExecutionContext stack. @@ -47,6 +91,12 @@ pub struct LocalCall { pub definition : DefinitionId, } + + +// ===================== +// === Visualization === +// ===================== + /// Unique Id for visualization. pub type VisualizationId = Uuid; @@ -57,7 +107,7 @@ pub struct Visualization { pub id: VisualizationId, /// Node that is to be visualized. pub ast_id: ExpressionId, - /// An enso lambda that will transform the data into expected format, i.e. `a -> a.json`. + /// An enso lambda that will transform the data into expected format, e.g. `a -> a.json`. pub expression: String, } @@ -75,6 +125,20 @@ pub type Id = language_server::ContextId; +// ============================= +// === AttachedVisualization === +// ============================= + +/// The information about active visualization. Includes the channel endpoint allowing sending +/// the visualization update's data to the visualization's attacher (presumably the view). +#[derive(Clone,Debug)] +pub struct AttachedVisualization { + visualization : Visualization, + update_sender : futures::channel::mpsc::UnboundedSender, +} + + + // ============= // === Model === // ============= @@ -90,11 +154,11 @@ pub type Id = language_server::ContextId; #[derive(Debug)] pub struct ExecutionContext { /// A name of definition which is a root call of this context. - pub entry_point: DefinitionName, + pub entry_point:DefinitionName, /// Local call stack. - stack: RefCell>, + stack:RefCell>, /// Set of active visualizations. - visualizations: RefCell>, + visualizations: RefCell>, } impl ExecutionContext { @@ -118,13 +182,21 @@ impl ExecutionContext { } /// Attaches a new visualization for current execution context. - pub fn attach_visualization(&self, vis: Visualization) { - self.visualizations.borrow_mut().insert(vis.id,vis); + /// + /// Returns a stream of visualization update data received from the server. + pub fn attach_visualization + (&self, visualization:Visualization) -> impl Stream { + let id = visualization.id; + let (update_sender,receiver) = futures::channel::mpsc::unbounded(); + let visualization = AttachedVisualization {visualization,update_sender}; + self.visualizations.borrow_mut().insert(id,visualization); + receiver } /// Detaches visualization from current execution context. pub fn detach_visualization(&self, id:&VisualizationId) -> FallibleResult { - Ok(self.visualizations.borrow_mut().remove(id).ok_or_else(InvalidVisualizationId)?) + let err = InvalidVisualizationId; + Ok(self.visualizations.borrow_mut().remove(id).ok_or_else(err)?.visualization) } /// Get an iterator over stack items. @@ -135,4 +207,14 @@ impl ExecutionContext { let stack_size = self.stack.borrow().len(); (0..stack_size).filter_map(move |i| self.stack.borrow().get(i).cloned()) } + + /// Dispatches the visualization update data (typically received from as LS binary notification) + /// to the respective's visualization update channel. + pub fn dispatch_update(&self, visualization_id:VisualizationId, data:VisualizationUpdateData) { + if let Some(visualization) = self.visualizations.borrow_mut().get(&visualization_id) { + // TODO [mwu] Should we consider detaching the visualization if the view has dropped the + // channel's receiver? Or we need to provide a way to re-establish the channel. + let _ = visualization.update_sender.unbounded_send(data); + } + } } diff --git a/gui/src/rust/ide/src/model/synchronized/execution_context.rs b/gui/src/rust/ide/src/model/synchronized/execution_context.rs index 1c4b0a37728..715bf73e829 100644 --- a/gui/src/rust/ide/src/model/synchronized/execution_context.rs +++ b/gui/src/rust/ide/src/model/synchronized/execution_context.rs @@ -5,6 +5,7 @@ use crate::prelude::*; use crate::double_representation::definition::DefinitionName; use crate::model::execution_context::LocalCall; use crate::model::execution_context::Visualization; +use crate::model::execution_context::VisualizationUpdateData; use crate::model::execution_context::VisualizationId; use enso_protocol::language_server; @@ -81,11 +82,14 @@ impl ExecutionContext { } /// Attaches a new visualization for current execution context. - pub async fn attach_visualization(&self, vis: Visualization) -> FallibleResult<()> { + /// + /// Returns a stream of visualization update data received from the server. + pub async fn attach_visualization + (&self, vis: Visualization) -> FallibleResult> { let config = vis.config(self.id,self.module_path.module_name().to_string()); self.language_server.attach_visualisation(&vis.id, &vis.ast_id, &config).await?; - self.model.attach_visualization(vis); - Ok(()) + let stream = self.model.attach_visualization(vis); + Ok(stream) } /// Detaches visualization from current execution context.