libsurfer/
state_file_io.rs

1use std::path::PathBuf;
2
3use color_eyre::eyre::Context;
4
5use crate::{
6    async_util::{perform_async_work, AsyncJob},
7    file_dialog::{load_state_dialog, save_state_dialog},
8    message::Message,
9    SystemState,
10};
11
12impl SystemState {
13    pub fn load_state_file(&mut self, path: Option<PathBuf>) {
14        let sender = self.channels.msg_sender.clone();
15
16        perform_async_work(async move {
17            let source = if let Some(path) = path.clone() {
18                #[cfg(not(target_arch = "wasm32"))]
19                {
20                    Some(path.into())
21                }
22                #[cfg(target_arch = "wasm32")]
23                {
24                    None
25                }
26            } else {
27                load_state_dialog().await
28            };
29            let Some(source) = source else {
30                return;
31            };
32            let bytes = source.read().await;
33            let new_state = match ron::de::from_bytes(&bytes)
34                .context(format!("Failed loading {}", source.file_name()))
35            {
36                Ok(s) => s,
37                Err(e) => {
38                    log::error!("Failed to load state: {e:#?}");
39                    return;
40                }
41            };
42            sender.send(Message::LoadState(new_state, path)).unwrap();
43        });
44    }
45
46    pub fn save_state_file(&mut self, path: Option<PathBuf>) {
47        let sender = self.channels.msg_sender.clone();
48        let Some(encoded) = self.encode_state() else {
49            return;
50        };
51
52        perform_async_work(async move {
53            let destination = if let Some(path) = path {
54                #[cfg(not(target_arch = "wasm32"))]
55                {
56                    Some(path.into())
57                }
58                #[cfg(target_arch = "wasm32")]
59                {
60                    None
61                }
62            } else {
63                save_state_dialog().await
64            };
65            let Some(destination) = destination else {
66                return;
67            };
68
69            #[cfg(not(target_arch = "wasm32"))]
70            sender
71                .send(Message::SetStateFile(destination.path().into()))
72                .unwrap();
73            destination
74                .write(encoded.as_bytes())
75                .await
76                .map_err(|e| log::error!("Failed to write state to {destination:#?} {e:#?}"))
77                .ok();
78            sender
79                .send(Message::AsyncDone(AsyncJob::SaveState))
80                .unwrap();
81        });
82    }
83
84    fn encode_state(&self) -> Option<String> {
85        let opt = ron::Options::default();
86
87        opt.to_string_pretty(&self.user, ron::ser::PrettyConfig::default())
88            .context("Failed to encode state")
89            .map_err(|e| log::error!("Failed to encode state. {e:#?}"))
90            .ok()
91    }
92}