serde_gff/
index.rs

1//! Содержит описание структур-индексов различных данных в GFF файле
2
3use std::ops::Add;
4
5use crate::header::Header;
6
7/// Типаж, реализуемый специальными структурами, хранящими индексы на записи в GFF-файле,
8/// позволяющий преобразовать их в реальное смещение для чтения информации из файла.
9pub trait Index {
10  /// Получает смещение от начала GFF-файла, в котором находятся индексируемые данные
11  fn offset(&self, header: &Header) -> u64;
12}
13
14/// Макрос для объявления типизированной обертки над числом (или числами),
15/// представляющем(ими) индекс одной из структур данных в файле.
16///
17/// # Параметры 1
18/// - `$name`: Имя генерируемой структуры.
19/// - `$field`: Имя поля в заголовке, хранящее базовое смещение для структур,
20///   к которым производится доступ по данному индексу
21///
22/// # Параметры 2
23/// - `$name`: Имя генерируемой структуры. Структура реализует типаж `From` для
24///   конструирования из `u32`
25/// - `$field`: Имя поля в заголовке, хранящее базовое смещение для структур,
26///   к которым производится доступ по данному индексу
27/// - `$multiplier`: множитель для индекса, переводящий его в смещение в байтах
28macro_rules! index {
29  ($(#[$attrs:meta])* $name:ident, $field:ident) => (
30    $(#[$attrs])*
31    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
32    pub struct $name(pub(crate) u32, pub(crate) u32);
33
34    impl Index for $name {
35      #[inline]
36      fn offset(&self, header: &Header) -> u64 {
37        let start  = header.$field.offset as u64;
38        let offset = self.0 as u64 + self.1 as u64 * 4;
39
40        start + offset
41      }
42    }
43    impl Add<u32> for $name {
44      type Output = Self;
45
46      fn add(self, rhs: u32) -> Self {
47        $name(self.0, self.1 + rhs)
48      }
49    }
50  );
51
52  ($(#[$attrs:meta])* $name:ident, $field:ident, $multiplier:expr) => (
53    $(#[$attrs])*
54    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
55    pub struct $name(pub(crate) u32);
56    impl Index for $name {
57      #[inline]
58      fn offset(&self, header: &Header) -> u64 {
59        let start  = header.$field.offset as u64;
60        let offset = self.0 as u64 * $multiplier;
61
62        start + offset
63      }
64    }
65    impl From<u32> for $name {
66      fn from(value: u32) -> Self { $name(value) }
67    }
68  );
69}
70
71index!(
72  /// Номер структуры в файле
73  StructIndex, structs, 3*4
74);
75index!(
76  /// Номер поля в массиве полей GFF файла. Каждая структура в файле состоит из набора полей,
77  /// на которые ссылается по этим индексам.
78  FieldIndex, fields, 3*4
79);
80index!(
81  /// Номер метки для поля в общем массиве меток, хранящихся в GFF файле
82  LabelIndex, labels, 16
83);
84index!(
85  /// Двойной индекс -- номера списка с полями структуры структуры и номер поля в этом списке.
86  /// Используется для указания на поля структуры, когда структура содержит несколько полей.
87  FieldIndicesIndex, field_indices
88);
89index!(
90  /// Двойной индекс -- номера списка элементов и номер элемента в этом списке.
91  /// Используется для представления списков.
92  ListIndicesIndex, list_indices
93);
94
95index!(
96  /// Смещение в файле, по которому расположены данные поля типа `Dword64`
97  U64Index, field_data, 1
98);
99index!(
100  /// Смещение в файле, по которому расположены данные поля типа `Int64`
101  I64Index, field_data, 1
102);
103index!(
104  /// Смещение в файле, по которому расположены данные поля типа `Double64`
105  F64Index, field_data, 1
106);
107index!(
108  /// Смещение в файле, по которому расположены данные поля типа `String`
109  StringIndex, field_data, 1
110);
111index!(
112  /// Смещение в файле, по которому расположены данные поля типа `ResRef`
113  ResRefIndex, field_data, 1
114);
115index!(
116  /// Смещение в файле, по которому расположены данные поля типа `LocString`
117  LocStringIndex, field_data, 1
118);
119index!(
120  /// Смещение в файле, по которому расположены данные поля типа `Void`
121  BinaryIndex, field_data, 1
122);