rakata_formats/vis/
writer.rs

1//! VIS ASCII writer.
2
3use std::io::{Cursor, Write};
4
5use crate::binary;
6
7use super::{Vis, VisError};
8
9/// Writes a VIS graph to a writer.
10#[cfg_attr(
11    feature = "tracing",
12    tracing::instrument(level = "debug", skip(writer, vis))
13)]
14pub fn write_vis<W: Write>(writer: &mut W, vis: &Vis) -> Result<(), VisError> {
15    for (observer, observed) in vis.visibility() {
16        validate_room_token(observer)?;
17        binary::write_cp1252(
18            writer,
19            &format!("{observer} {}\n", observed.len()),
20            format!("observer `{observer}`"),
21            |context, source| VisError::TextEncoding { context, source },
22        )?;
23        for room in observed {
24            validate_room_token(room)?;
25            binary::write_cp1252(
26                writer,
27                &format!("  {room}\n"),
28                format!("edge `{observer}` -> `{room}`"),
29                |context, source| VisError::TextEncoding { context, source },
30            )?;
31        }
32    }
33    Ok(())
34}
35
36/// Serializes a VIS graph to bytes.
37#[cfg_attr(feature = "tracing", tracing::instrument(level = "debug", skip(vis)))]
38pub fn write_vis_to_vec(vis: &Vis) -> Result<Vec<u8>, VisError> {
39    let mut cursor = Cursor::new(Vec::new());
40    write_vis(&mut cursor, vis)?;
41    Ok(cursor.into_inner())
42}
43
44fn validate_room_token(room: &str) -> Result<(), VisError> {
45    if room.is_empty() || room.chars().any(char::is_whitespace) {
46        return Err(VisError::InvalidRoom(room.to_string()));
47    }
48    Ok(())
49}