serde_gff/
header.rs

1//! Содержит описания структур заголовка GFF файла
2
3use std::cmp::max;
4use std::io::{Read, Write, Result};
5use byteorder::{LE, ReadBytesExt, WriteBytesExt};
6
7pub use crate::sig::*;
8pub use crate::ver::*;
9
10/// Описание области файла, описывающей местоположение списков записей в файле
11#[derive(Debug, Default)]
12pub struct Section {
13  /// Смещение в байтах от начала файла в сериализованном виде
14  pub offset: u32,
15  /// Количество записей по смещению `offset`. Размер записи зависит от конкретного поля
16  pub count:  u32,
17}
18
19impl Section {
20  /// Читает описание области из потока
21  #[inline]
22  pub fn read<R: Read>(reader: &mut R) -> Result<Self> {
23    Ok(Section {
24      offset: reader.read_u32::<LE>()?,
25      count:  reader.read_u32::<LE>()?,
26    })
27  }
28  /// Записывает описание области файла в поток
29  #[inline]
30  pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
31    writer.write_u32::<LE>(self.offset)?;
32    writer.write_u32::<LE>(self.count)
33  }
34}
35
36///////////////////////////////////////////////////////////////////////////////////////////////////
37
38/// Заголовок GFF файла. Заголовок содержит вид файла, версию формата и информацию о
39/// 6 областях, файла, содержащих данные:
40/// - Список структур в файле
41/// - Общий список полей всех структур файла
42/// - Список уникальных названий полей
43/// - Список с данными полей
44/// - Вспомогательный список для индексов для сложных структур данных
45/// - Вспомогательный список для хранения списочных значений полей
46#[derive(Debug)]
47pub struct Header {
48  /// Конкретный вид GFF файла
49  pub signature: Signature,
50  /// Версия файла
51  pub version: Version,
52
53  /// Содержит смещение в байтах от начала файла области с расположением
54  /// структур и их количество
55  pub structs: Section,
56
57  /// Содержит смещение в байтах от начала файла области с расположением
58  /// полей структур и их количество
59  pub fields: Section,
60
61  /// Содержит смещение в байтах от начала файла области с расположением
62  /// меток полей в структурах и их количество
63  pub labels: Section,
64
65  /// Содержит смещение в байтах от начала файла области с расположением
66  /// сериализованных значений полей и суммарное число байт данных
67  pub field_data: Section,
68
69  /// Содержит смещение в байтах от начала файла области с расположением
70  /// индексов полей и их количество
71  pub field_indices: Section,
72
73  /// Содержит смещение в байтах от начала файла области с расположением
74  /// индексов списков и их количество
75  pub list_indices: Section,
76}
77
78impl Header {
79  /// Создает заголовок для пустого файла с указанным типом
80  #[inline]
81  pub fn new(signature: Signature) -> Self {
82    Self::with_version(signature, Version::V3_2)
83  }
84  /// Создает заголовок для пустого файла с указанным типом и версией
85  #[inline]
86  pub fn with_version(signature: Signature, version: Version) -> Self {
87    Header {
88      signature,
89      version,
90      structs:       Section::default(),
91      fields:        Section::default(),
92      labels:        Section::default(),
93      field_data:    Section::default(),
94      field_indices: Section::default(),
95      list_indices:  Section::default(),
96    }
97  }
98  /// Читает значение GFF заголовка из потока
99  pub fn read<R: Read>(reader: &mut R) -> Result<Self> {
100    Ok(Header {
101      signature:     Signature::read(reader)?,
102      version:       Version::read(reader)?,
103
104      structs:       Section::read(reader)?,
105      fields:        Section::read(reader)?,
106      labels:        Section::read(reader)?,
107      field_data:    Section::read(reader)?,
108      field_indices: Section::read(reader)?,
109      list_indices:  Section::read(reader)?,
110    })
111  }
112  /// Записывает значение GFF заголовка в поток
113  pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
114    self.signature.write(writer)?;
115    self.version.write(writer)?;
116
117    self.structs.write(writer)?;
118    self.fields.write(writer)?;
119    self.labels.write(writer)?;
120    self.field_data.write(writer)?;
121    self.field_indices.write(writer)?;
122    self.list_indices.write(writer)
123  }
124  /// Возвращает нижнюю границу на количество токенов, которые может произвести
125  /// данный файл
126  #[inline]
127  pub fn token_count(&self) -> usize {
128    // Для каждой структуры - токен начала и окончания
129    // Для каждого списка - токен начала и окончания
130    let size = (self.structs.count + self.list_indices.count)*2;
131
132    // Т.к. каждое поле может быть списком или структурой, то они уже подсчитываются
133    // в списках и структурах. Поэтому минимальное количество вычисляем, как максимум
134    // из того, что нам смогут дать поля или структуры со списками
135    max(size, self.fields.count) as usize
136  }
137}