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
use std::io::Write;

use stream_io::ByteOrder;

use crate::{StreamWriter, XCellValue};

impl StreamWriter for XCellValue {
    fn write_to<W: Write>(&self, buffer: &mut W, order: ByteOrder) -> std::io::Result<()> {
        match self {
            XCellValue::Boolean(v) => match v {
                true => 0u8.write_to(buffer, order)?,
                false => 1u8.write_to(buffer, order)?,
            },
            XCellValue::Integer8(v) => v.write_to(buffer, order)?,
            XCellValue::Integer16(v) => v.write_to(buffer, order)?,
            XCellValue::Integer32(v) => v.write_to(buffer, order)?,
            XCellValue::Integer64(v) => v.write_to(buffer, order)?,
            XCellValue::Unsigned8(v) => v.write_to(buffer, order)?,
            XCellValue::Unsigned16(v) => v.write_to(buffer, order)?,
            XCellValue::Unsigned32(v) => v.write_to(buffer, order)?,
            XCellValue::Unsigned64(v) => v.write_to(buffer, order)?,
            XCellValue::Float32(v) => v.write_to(buffer, order)?,
            XCellValue::Float64(v) => v.write_to(buffer, order)?,
            XCellValue::Vector2(v) => {
                for item in v {
                    item.write_to(buffer, order)?;
                }
            }
            XCellValue::Vector3(v) => {
                for item in v {
                    item.write_to(buffer, order)?;
                }
            }
            XCellValue::Vector4(v) => {
                for item in v {
                    item.write_to(buffer, order)?;
                }
            }
            XCellValue::Color4(v) => {
                for item in v {
                    item.write_to(buffer, order)?;
                }
            }
            XCellValue::Quaternion4(v) => {
                for item in v {
                    item.write_to(buffer, order)?;
                }
            }
            // https://en.wikipedia.org/wiki/Variable-length_quantity
            XCellValue::String(v) => {
                write_7_bit(v.len(), buffer, order)?;
                for item in v.bytes() {
                    item.write_to(buffer, order)?
                }
            }
            XCellValue::Color(v) => {
                v.r.write_to(buffer, order)?;
                v.g.write_to(buffer, order)?;
                v.b.write_to(buffer, order)?;
                v.a.write_to(buffer, order)?;
            }
            XCellValue::Vector(v) => {
                (v.len() as u32).write_to(buffer, order)?;
                for item in v.iter() {
                    item.write_to(buffer, order)?
                }
            }
            XCellValue::Enumerate(v) => {
                panic!("无法写入二进制 `{}`", v)
            }
        }
        Ok(())
    }
}

pub fn write_7_bit<W: Write>(length: usize, buffer: &mut W, order: ByteOrder) -> std::io::Result<()> {
    let mut value = length as u32;
    while value >= 0x80 {
        ((value | 0x80) as u8).write_to(buffer, order)?;
        value >>= 7;
    }
    (value as u8).write_to(buffer, order)
}