wolfram_wxf 0.7.0

Convert a value to the Wolfram Language WXF format.
Documentation
use crate::{WolframFunction, WolframValue};
use std::fmt::{Display, Formatter, Write};

/// A serializer for the Wolfram Language.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct ReadableWriter {
    /// Whether to pretty print the output.
    pub pretty: bool,
    /// The number of spaces to indent.
    pub indent_string: &'static str,
}

impl Default for ReadableWriter {
    fn default() -> Self {
        Self { pretty: true, indent_string: "    " }
    }
}

struct ReadableBuffer {
    buffer: String,
    indent_level: usize,
    config: ReadableWriter,
}

impl ReadableBuffer {
    pub fn new(config: ReadableWriter) -> ReadableBuffer {
        Self { buffer: String::new(), indent_level: 0, config }
    }
    pub fn write_value(&mut self, value: &WolframValue) -> std::fmt::Result {
        match value {
            WolframValue::Skip => Ok(()),
            WolframValue::Function(v) => self.write_function(v),
            WolframValue::Boolean(v) => match v {
                true => write!(self.buffer, "True"),
                false => write!(self.buffer, "False"),
            },
            WolframValue::String(s) => write!(self.buffer, "{:?}", s),
            WolframValue::Bytes(b) => {
                let v: Vec<String> = b.iter().map(|s| format!("{}", s)).collect();
                write!(self.buffer, "ByteArray[{{{}}}]", v.join(","))
            }
            WolframValue::Symbol(s) => write!(self.buffer, "{}", s),
            WolframValue::Integer8(i) => write!(self.buffer, "{}", i),
            WolframValue::Integer16(i) => write!(self.buffer, "{}", i),
            WolframValue::Integer32(i) => write!(self.buffer, "{}", i),
            WolframValue::Integer64(i) => write!(self.buffer, "{}", i),
            WolframValue::BigInteger(i) => write!(self.buffer, "{}", i),
            WolframValue::Decimal64(d) => write!(self.buffer, "{}`", d.0),
            WolframValue::BigDecimal(d) => write!(self.buffer, "{}", d),
            WolframValue::PackedArray(_) => unimplemented!(),
            WolframValue::NumericArray(_) => unimplemented!(),
            WolframValue::Association(dict) => {
                let v: Vec<String> = dict.iter().map(|(k, (r, v))| format!("{}{}{}", k, r, v)).collect();
                write!(self.buffer, "<|{}|>", v.join(","))
            }
        }
    }
    pub fn write_function(&mut self, function: &WolframFunction) -> std::fmt::Result {
        let head = function.get_head();
        let args = function.get_rest();
        self.indent();
        if head.to_string() == "List" {
            self.write_items(args, '{', '}')?;
        }
        else {
            self.buffer.write_str(&head.to_string())?;
            self.write_items(args, '[', ']')?;
        }
        self.dedent();
        Ok(())
    }
    pub fn write_items(&mut self, items: &[WolframValue], lhs: char, rhs: char) -> std::fmt::Result {
        self.buffer.write_char(lhs)?;
        for (index, item) in items.iter().enumerate() {
            if index != 0 {
                self.buffer.write_char(',')?;
            }
            self.write_value(item)?;
            self.write_new_line()?;
        }
        self.buffer.write_char(rhs)?;
        Ok(())
    }

    pub fn write_new_line(&mut self) -> std::fmt::Result {
        if self.config.pretty {
            self.buffer.write_char('\n')?;
            for _ in 0..self.indent_level {
                self.buffer.write_str(self.config.indent_string)?;
            }
        }
        Ok(())
    }
    pub fn indent(&mut self) {
        self.indent_level += 1;
    }
    pub fn dedent(&mut self) {
        self.indent_level -= 1;
    }
}

impl Display for WolframFunction {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let mut buffer = ReadableBuffer::new(ReadableWriter { pretty: f.alternate(), indent_string: "    " });
        buffer.write_function(self)?;
        write!(f, "{}", buffer.buffer)
    }
}

impl Display for WolframValue {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let mut buffer = ReadableBuffer::new(ReadableWriter { pretty: f.alternate(), indent_string: "    " });
        buffer.write_value(self)?;
        write!(f, "{}", buffer.buffer)
    }
}