texlang 0.1.0

Texlang: A TeX language interpreter
Documentation
use crate::*;
use serde::{Deserialize, Deserializer, Serialize};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

#[derive(Serialize)]
struct SerializableVM<'a, S> {
    state: &'a S,
    commands_map: &'a command::Map<S>,
    internal: &'a vm::Internal<S>,
}

impl<'a, S> SerializableVM<'a, S> {
    fn new(vm: &'a vm::VM<S>) -> Self {
        Self {
            state: &vm.state,
            commands_map: &vm.commands_map,
            internal: &vm.internal,
        }
    }
}

impl<State: serde::Serialize> Serialize for vm::VM<State> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let serializable_vm = SerializableVM::new(self);
        serializable_vm.serialize(serializer)
    }
}

#[derive(Deserialize)]
struct DeserializedVM<'a, S> {
    state: S,
    commands_map: command::map::SerializableMap<'a>,
    internal: vm::Internal<S>,
}

fn finish_deserialization<S>(
    #[allow(clippy::boxed_local)] mut deserialized: Box<DeserializedVM<'_, S>>,
    initial_built_ins: HashMap<&str, command::BuiltIn<S>>,
) -> Box<vm::VM<S>> {
    let initial_built_ins = initial_built_ins
        .into_iter()
        .map(|(key, value)| {
            let cs_name = deserialized.internal.cs_name_interner.get_or_intern(key);
            (cs_name, value)
        })
        .collect();
    let commands_map = deserialized
        .commands_map
        .finish_deserialization(initial_built_ins, &deserialized.internal.cs_name_interner);
    Box::new(vm::VM {
        state: deserialized.state,
        commands_map,
        file_system: Box::new(super::RealFileSystem {}),
        terminal: Rc::new(RefCell::new(std::io::stderr())),
        log_file: Rc::new(RefCell::new(std::io::sink())),
        working_directory: match std::env::current_dir() {
            Ok(path_buf) => Some(path_buf),
            Err(err) => {
                println!("failed to determine the working directory: {err}");
                None
            }
        },
        internal: deserialized.internal,
    })
}

pub fn deserialize<'de, D: Deserializer<'de>, S: serde::Deserialize<'de>>(
    deserializer: D,
    initial_built_ins: HashMap<&str, command::BuiltIn<S>>,
) -> Box<vm::VM<S>> {
    let deserialized_vm: Box<DeserializedVM<S>> = Deserialize::deserialize(deserializer).unwrap();
    finish_deserialization(deserialized_vm, initial_built_ins)
}