Skip to content

Commit efe8946

Browse files
Maybe bad idea
1 parent 9860fd6 commit efe8946

7 files changed

Lines changed: 78 additions & 22 deletions

File tree

editor/src/messages/frontend/frontend_message.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::IconName;
22
use super::utility_types::{MouseCursorIcon, PersistedState};
33
use crate::messages::app_window::app_window_message_handler::AppWindowPlatform;
4-
use crate::messages::frontend::utility_types::{DocumentInfo, EyedropperPreviewImage};
4+
use crate::messages::frontend::utility_types::{DocumentInfo, EyedropperPreviewImage, FrontendMessageFuture};
55
use crate::messages::input_mapper::utility_types::misc::ActionShortcut;
66
use crate::messages::layout::utility_types::widget_prelude::*;
77
use crate::messages::portfolio::document::node_graph::utility_types::{
@@ -101,6 +101,12 @@ pub enum FrontendMessage {
101101
folder: Option<PathBuf>,
102102
content: serde_bytes::ByteBuf,
103103
},
104+
Await {
105+
#[serde(skip, default)]
106+
#[derivative(Debug = "ignore", PartialEq = "ignore")]
107+
#[cfg_attr(feature = "wasm", tsify(type = "unknown"))]
108+
future: FrontendMessageFuture,
109+
},
104110
TriggerExportImage {
105111
svg: String,
106112
name: String,

editor/src/messages/frontend/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod utility_types;
44

55
#[doc(inline)]
66
pub use frontend_message::{FrontendMessage, FrontendMessageDiscriminant};
7+
pub use utility_types::FrontendMessageFuture;
78

89
// TODO: Make this an enum with the actual icon names, somehow derived from or tied to the frontend icon set.
910
// TODO: Then remove `#[widget_builder(string)]` from all icon fields.

editor/src/messages/frontend/utility_types.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
use std::future::{Future, IntoFuture};
12
use std::path::PathBuf;
3+
use std::pin::Pin;
4+
use std::sync::{Arc, Mutex};
25

36
use graph_craft::application_io::ResourceHash;
47

@@ -82,3 +85,31 @@ pub struct EyedropperPreviewImage {
8285
pub width: u32,
8386
pub height: u32,
8487
}
88+
89+
#[derive(Clone, Default)]
90+
pub struct FrontendMessageFuture {
91+
inner: Arc<Mutex<Option<InnerFrontendMessageFuture>>>,
92+
}
93+
94+
impl FrontendMessageFuture {
95+
pub fn new(future: impl Future<Output = FrontendMessage> + Send + 'static) -> Self {
96+
Self {
97+
inner: Arc::new(Mutex::new(Some(Box::pin(future)))),
98+
}
99+
}
100+
}
101+
102+
type InnerFrontendMessageFuture = Pin<Box<dyn Future<Output = FrontendMessage> + Send + 'static>>;
103+
104+
impl IntoFuture for FrontendMessageFuture {
105+
type Output = FrontendMessage;
106+
type IntoFuture = InnerFrontendMessageFuture;
107+
108+
fn into_future(self) -> Self::IntoFuture {
109+
self.inner
110+
.lock()
111+
.unwrap_or_else(|poisoned| poisoned.into_inner())
112+
.take()
113+
.expect("FrontendMessageFuture can only be awaited once")
114+
}
115+
}

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -925,19 +925,25 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
925925
}
926926
let folder = self.path.as_ref().and_then(|path| path.parent()).map(|parent| parent.to_path_buf());
927927

928-
let exported = resources.export(&Vec::from_iter(self.used_resources()));
929-
self.embedded_resources = EmbeddedResources::from_iter(exported);
930-
let content = self.serialize_document();
931-
932-
// Clear embedded resources after serialization to free memory.
933-
let _ = std::mem::take(&mut self.embedded_resources);
934-
935-
responses.add(FrontendMessage::TriggerSaveDocument {
936-
document_id,
937-
name: format!("{}.{}", self.name.clone(), FILE_EXTENSION),
938-
path,
939-
folder,
940-
content: content.into_bytes().into(),
928+
let resource_hashes = Vec::from_iter(self.used_resources()).into_boxed_slice();
929+
let resources = resources.resources();
930+
let mut document = self.clone();
931+
let name = format!("{}.{}", self.name.clone(), FILE_EXTENSION);
932+
933+
responses.add(FrontendMessage::Await {
934+
future: FrontendMessageFuture::new(async move {
935+
let exported = ResourceMessageHandler::export_async(resources, resource_hashes).await;
936+
document.embedded_resources = EmbeddedResources::from_iter(exported);
937+
let content = document.serialize_document();
938+
939+
FrontendMessage::TriggerSaveDocument {
940+
document_id,
941+
name,
942+
path,
943+
folder,
944+
content: content.into_bytes().into(),
945+
}
946+
}),
941947
});
942948
}
943949
DocumentMessage::SavedDocument { path } => {

editor/src/messages/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub use crate::messages::dialog::export_dialog::{ExportDialogMessage, ExportDial
1515
pub use crate::messages::dialog::new_document_dialog::{NewDocumentDialogMessage, NewDocumentDialogMessageDiscriminant, NewDocumentDialogMessageHandler};
1616
pub use crate::messages::dialog::preferences_dialog::{PreferencesDialogMessage, PreferencesDialogMessageContext, PreferencesDialogMessageDiscriminant, PreferencesDialogMessageHandler};
1717
pub use crate::messages::dialog::{DialogMessage, DialogMessageContext, DialogMessageDiscriminant, DialogMessageHandler};
18-
pub use crate::messages::frontend::{FrontendMessage, FrontendMessageDiscriminant};
18+
pub use crate::messages::frontend::{FrontendMessage, FrontendMessageDiscriminant, FrontendMessageFuture};
1919
pub use crate::messages::input_mapper::key_mapping::{KeyMappingMessage, KeyMappingMessageContext, KeyMappingMessageDiscriminant, KeyMappingMessageHandler};
2020
pub use crate::messages::input_mapper::{InputMapperMessage, InputMapperMessageContext, InputMapperMessageDiscriminant, InputMapperMessageHandler};
2121
pub use crate::messages::input_preprocessor::{InputPreprocessorMessage, InputPreprocessorMessageContext, InputPreprocessorMessageDiscriminant, InputPreprocessorMessageHandler};

editor/src/messages/resource/resource_message_handler.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,17 @@ impl ResourceMessageHandler {
2626
}
2727
}
2828

29-
pub fn export(&self, resources: &[ResourceHash]) -> Box<[(ResourceHash, Resource)]> {
30-
let Some(storage) = &self.storage else {
31-
log::error!("Attempted to export resources but storage is not initialized");
32-
return Box::new([]);
33-
};
34-
let mut storage = storage.write().unwrap();
35-
resources.iter().filter_map(|hash| storage.read(hash).map(|resource| (*hash, resource))).collect()
29+
pub async fn export_async(resources: Box<dyn Resources>, resource_hashes: Box<[ResourceHash]>) -> Box<[(ResourceHash, Resource)]> {
30+
let loads = resource_hashes
31+
.into_vec()
32+
.into_iter()
33+
.map(|hash| {
34+
let resource = resources.load(hash);
35+
async move { resource.await.map(|resource| (hash, resource)) }
36+
})
37+
.collect::<Vec<_>>();
38+
39+
futures::future::join_all(loads).await.into_iter().flatten().collect()
3640
}
3741

3842
pub fn resources(&self) -> Box<dyn Resources> {

frontend/wrapper/src/editor_wrapper.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,14 @@ impl EditorWrapper {
143143

144144
// Sends a FrontendMessage to JavaScript
145145
pub(crate) fn send_frontend_message_to_js(&self, message: FrontendMessage) {
146+
if let FrontendMessage::Await { future } = message {
147+
let wrapper = self.clone();
148+
wasm_bindgen_futures::spawn_local(async move {
149+
wrapper.send_frontend_message_to_js(future.await);
150+
});
151+
return;
152+
}
153+
146154
if let FrontendMessage::UpdateImageData { ref image_data } = message {
147155
let new_hash = calculate_hash(&CacheHashWrapper(image_data));
148156
let prev_hash = IMAGE_DATA_HASH.load(Ordering::Relaxed);

0 commit comments

Comments
 (0)