criware_utf_core/
schema.rs

1use crate::{Error, Reader, Result, ValueKind};
2
3/// The possible ways a column can store data
4///
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum ColumnStorageFormat {
7    /// No data is stored currently, but may have data in the future
8    Zero,
9    /// A single value is stored
10    Constant,
11    /// A value is stored for every row of the table
12    Rowed,
13}
14
15/// Representation of a column of a table (data not included)
16///
17#[derive(Debug, Clone)]
18pub struct SchemaColumn {
19    /// The name of the column
20    pub name: String,
21    /// The method in which this column stores data
22    pub storage_format: ColumnStorageFormat,
23    /// The kind of data this column stores
24    pub value_kind: ValueKind,
25}
26
27/// Representation of a table's schema
28///
29/// This is meant to be immutable.
30///
31#[derive(Debug, Clone)]
32pub struct Schema {
33    /// The name of the table
34    pub table_name: String,
35    /// The columns, listed in the order they appear
36    pub columns: Box<[SchemaColumn]>,
37}
38
39impl Reader {
40    fn get_column(&mut self) -> Result<SchemaColumn> {
41        let flag: u8 = self.read_value(false)?;
42        let column_name: String = self.read_value(false)?;
43        let value_kind = match flag & 0x0f {
44            0 => ValueKind::U8,
45            1 => ValueKind::I8,
46            2 => ValueKind::U16,
47            3 => ValueKind::I16,
48            4 => ValueKind::U32,
49            5 => ValueKind::I32,
50            6 => ValueKind::U64,
51            7 => ValueKind::I64,
52            8 => ValueKind::F32,
53            0xa => ValueKind::STR,
54            0xb => ValueKind::BLOB,
55            v => return Err(Error::InvalidColumnType(v)),
56        };
57        match flag & 0xf0 {
58            0x10 => Ok(SchemaColumn {
59                name: column_name,
60                storage_format: ColumnStorageFormat::Zero,
61                value_kind,
62            }),
63            0x30 => {
64                match value_kind {
65                    ValueKind::U8 | ValueKind::I8 => {
66                        self.read_value::<u8>(false)?;
67                    }
68                    ValueKind::U16 | ValueKind::I16 => {
69                        self.read_value::<u16>(false)?;
70                    }
71                    ValueKind::U32 | ValueKind::I32 | ValueKind::F32 | ValueKind::STR => {
72                        self.read_value::<u32>(false)?;
73                    }
74                    ValueKind::U64 | ValueKind::I64 | ValueKind::BLOB => {
75                        self.read_value::<u64>(false)?;
76                    }
77                };
78                Ok(SchemaColumn {
79                    name: column_name,
80                    storage_format: ColumnStorageFormat::Constant,
81                    value_kind,
82                })
83            }
84            0x50 => Ok(SchemaColumn {
85                name: column_name,
86                storage_format: ColumnStorageFormat::Rowed,
87                value_kind,
88            }),
89            v => Err(Error::InvalidColumnStorage(v)),
90        }
91    }
92}
93
94impl Schema {
95    /**
96    Returns [`true`] if the column exists, [`false`] otherwise
97
98    # Example
99    ```no_run
100    # use std::fs::File;
101    # use criware_utf_core::Schema;
102    # let mut file = File::open("random-table.bin")?;
103    # let schema = Schema::read(&mut file)?;
104    if schema.has_column("ImportantColumn") {
105        println!("important data found :)");
106    } else {
107        println!("could not find important data");
108    }
109    ```
110     */
111    pub fn has_column(&self, name: &str) -> bool {
112        for column in &self.columns {
113            if column.name == name {
114                return true;
115            }
116        }
117        false
118    }
119    /**
120    Reads a table and extracts its schema.
121
122    The entire table's contents are consumed.
123
124    # Example
125    ```no_run
126    # use std::fs::File;
127    # use criware_utf_core::Schema;
128    let mut file = File::open("random-table.bin")?;
129    let schema = Schema::read(&mut file)?;
130    println!("{}", schema.table_name);
131    ```
132     */
133    pub fn read(reader: &mut dyn std::io::Read) -> Result<Self> {
134        let mut reader = Reader::new(reader)?;
135        let mut columns = Vec::new();
136        while reader.more_column_data() {
137            columns.push(reader.get_column()?);
138        }
139        Ok(Schema {
140            table_name: reader.table_name().to_owned(),
141            columns: columns.into_boxed_slice(),
142        })
143    }
144}