1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
use crate::{check_string_length, Error};
use std::fmt::Write;

#[derive(Clone, Copy, Debug)]
pub enum FieldValue<'a> {
    Float(f64),
    Integer(i64),
    UInteger(u64),
    String(&'a str),
    Boolean(bool),
}

impl FieldValue<'_> {
    pub fn to_writer<W>(&self, mut writer: W) -> Result<(), Error>
    where
        W: Write,
    {
        match self {
            FieldValue::Float(v) => write!(writer, "{}", v)?,
            FieldValue::Integer(v) => write!(writer, "{}i", v)?,
            FieldValue::UInteger(v) => write!(writer, "{}u", v)?,
            FieldValue::String(v) => {
                check_string_length(v)?;
                writer.write_char('"')?;
                for c in v.chars() {
                    match c {
                        '\n' => return Err(Error::Newline),
                        '"' => writer.write_str(r#"\""#)?,
                        '\\' => writer.write_str(r#"\\"#)?,
                        _ => writer.write_char(c)?,
                    }
                }
                writer.write_char('"')?;
            }
            FieldValue::Boolean(v) => {
                if *v {
                    write!(writer, "true")?
                } else {
                    write!(writer, "false")?
                }
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::FieldValue;

    fn check(field_value: FieldValue, expected: &str) {
        let mut string = String::new();
        field_value.to_writer(&mut string).unwrap();
        assert_eq!(string, expected);
    }

    #[test]
    fn test_float() {
        check(FieldValue::Float(1.), "1");
        check(
            FieldValue::Float(-1.234456e+78),
            "-1234456000000000000000000000000000000000000000000000000000000000000000000000000",
        );
    }

    #[test]
    fn test_integer() {
        check(FieldValue::Integer(1), "1i");
        check(FieldValue::Integer(12485903), "12485903i");
        check(FieldValue::Integer(-12485903), "-12485903i");
    }

    #[test]
    fn test_uinteger() {
        check(FieldValue::UInteger(1), "1u");
        check(FieldValue::UInteger(12485903), "12485903u");
    }

    #[test]
    fn test_string() {
        check(
            FieldValue::String(r#"this is a string"#),
            r#""this is a string""#,
        );
        check(
            FieldValue::String(r#""string" within a string"#),
            r#""\"string\" within a string""#,
        );
        check(
            FieldValue::String(r#""\"string\" within a string""#),
            r#""\"\\\"string\\\" within a string\"""#,
        );
    }

    #[test]
    fn test_boolean() {
        check(FieldValue::Boolean(true), "true");
        check(FieldValue::Boolean(false), "false");
    }
}