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}