terrazzo-terminal 0.2.7

A simple web-based terminal emulator built on Terrazzo.
#![cfg(feature = "server")]

use std::sync::Arc;

use super::Tile;
use super::Tiles;
use super::state::TREE;
use super::state::TilesStateError;
use crate::tiles::id::TileId;

pub fn mutate_node(
    id_to_mutate: TileId,
    mutation: impl FnOnce(&Tile) -> Tile,
) -> Result<Arc<Tiles>, TilesStateError> {
    let mut lock = TREE.lock().map_err(|_| TilesStateError::PoisonError)?;
    let tree = lock.take().unwrap_or_default();
    let mut maybe_mutation = Some(mutation);
    let tree = mutate_node_aux(tree, id_to_mutate, &mut maybe_mutation)?;
    if maybe_mutation.is_some() {
        return Err(TilesStateError::TileIdNotFound(id_to_mutate));
    }
    *lock = tree.clone().into();
    return Ok(tree);
}

fn mutate_node_aux(
    tree: Arc<Tiles>,
    id_to_mutate: TileId,
    maybe_mutation: &mut Option<impl FnOnce(&Tile) -> Tile>,
) -> Result<Arc<Tiles>, TilesStateError> {
    if maybe_mutation.is_none() {
        return Ok(tree);
    }
    Ok(match &*tree {
        Tiles::Tile(node) if node.id == id_to_mutate => {
            let Some(mutation) = maybe_mutation.take() else {
                return Err(TilesStateError::DuplicateTileId(id_to_mutate));
            };
            Arc::new(Tiles::Tile(mutation(node)))
        }
        Tiles::Tile { .. } => tree,
        Tiles::Array {
            id,
            direction,
            nodes,
        } => {
            let mut nodes2 = Vec::with_capacity(nodes.len());
            for node in nodes {
                nodes2.push(mutate_node_aux(node.clone(), id_to_mutate, maybe_mutation)?);
            }
            Arc::new(Tiles::Array {
                id: *id,
                direction: *direction,
                nodes: nodes2,
            })
        }
    })
}