1use crate::*;
34use serde::{Deserialize, Deserializer, Serialize};
35use std::collections::HashMap;
36
37#[derive(Serialize)]
38struct SerializableVM<'a, S> {
39 state: &'a S,
40 commands_map: &'a command::Map<S>,
41 internal: &'a vm::Internal<S>,
42 save_stack: Vec<variable::SerializableSaveStackElement<'a>>,
43}
44
45impl<'a, S> SerializableVM<'a, S> {
46 fn new(vm: &'a vm::VM<S>) -> Self {
47 let variable_key_to_built_in = vm.commands_map.getters_key_to_built_in();
48 Self {
49 state: &vm.state,
50 commands_map: &vm.commands_map,
51 internal: &vm.internal,
52 save_stack: vm
53 .internal
54 .save_stack
55 .iter()
56 .map(|element| element.serializable(&variable_key_to_built_in))
57 .collect(),
58 }
59 }
60}
61
62impl<State: serde::Serialize> Serialize for vm::VM<State> {
63 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
64 where
65 S: serde::Serializer,
66 {
67 let serializable_vm = SerializableVM::new(self);
68 serializable_vm.serialize(serializer)
69 }
70}
71
72#[derive(Deserialize)]
77pub struct DeserializedVM<'a, S> {
78 state: S,
79 commands_map: command::map::SerializableMap<'a>,
80 internal: vm::Internal<S>,
81 save_stack: Vec<variable::SerializableSaveStackElement<'a>>,
82}
83
84pub fn finish_deserialization<S>(
89 #[allow(clippy::boxed_local)] mut deserialized: Box<DeserializedVM<'_, S>>,
90 built_in_commands: HashMap<&str, command::BuiltIn<S>>,
91) -> vm::VM<S> {
92 let built_in_commands = built_in_commands
93 .into_iter()
94 .map(|(key, value)| {
95 let cs_name = deserialized.internal.cs_name_interner.get_or_intern(key);
96 (cs_name, value)
97 })
98 .collect();
99 deserialized.internal.save_stack = deserialized
100 .save_stack
101 .into_iter()
102 .map(|element| element.finish_deserialization(&built_in_commands))
103 .collect();
104 let commands_map = deserialized
105 .commands_map
106 .finish_deserialization(built_in_commands, &deserialized.internal.cs_name_interner);
107 vm::VM {
108 state: deserialized.state,
109 commands_map,
110 working_directory: match std::env::current_dir() {
111 Ok(path_buf) => Some(path_buf),
112 Err(err) => {
113 println!("failed to determine the working directory: {err}");
114 None
115 }
116 },
117 internal: deserialized.internal,
118 }
119}
120
121pub(super) fn deserialize<'de, D: Deserializer<'de>, S: serde::Deserialize<'de>>(
122 deserializer: D,
123 built_in_commands: HashMap<&str, command::BuiltIn<S>>,
124) -> Result<vm::VM<S>, D::Error> {
125 let deserialized_vm: Box<DeserializedVM<S>> = Deserialize::deserialize(deserializer)?;
126 Ok(finish_deserialization(deserialized_vm, built_in_commands))
127}