use serde_derive::{Deserialize, Serialize}; use std::io::{Read, Seek}; use zip::ZipArchive; #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct SourceQuestion { #[serde(default)] pub num: u32, pub id: String, #[serde(alias = "Вопрос")] pub description: String, #[serde(alias = "Ответ")] pub answer: String, #[serde(alias = "Автор")] #[serde(default)] pub author: String, #[serde(alias = "Комментарий")] #[serde(default)] pub comment: String, #[serde(alias = "Комментарии")] #[serde(alias = "Инфо")] #[serde(default)] pub comment1: String, #[serde(alias = "Тур")] #[serde(default)] pub tour: String, #[serde(alias = "Ссылка")] #[serde(alias = "URL")] #[serde(default)] pub url: String, #[serde(alias = "Дата")] #[serde(default)] pub date: String, #[serde(alias = "Обработан")] #[serde(default)] pub processed_by: String, #[serde(alias = "Редактор")] #[serde(default)] pub redacted_by: String, #[serde(alias = "Копирайт")] #[serde(default)] pub copyright: String, #[serde(alias = "Тема")] #[serde(default)] pub theme: String, #[serde(alias = "Вид")] #[serde(alias = "Тип")] #[serde(default)] pub kind: String, #[serde(alias = "Источник")] #[serde(default)] pub source: String, #[serde(alias = "Рейтинг")] #[serde(default)] pub rating: String, } #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct SourceQuestionsBatch { #[serde(default)] pub filename: String, #[serde(alias = "Пакет")] #[serde(alias = "Чемпионат")] pub description: String, #[serde(alias = "Автор")] #[serde(default)] pub author: String, #[serde(alias = "Комментарий")] #[serde(alias = "Комментарии")] #[serde(alias = "Инфо")] #[serde(default)] pub comment: String, #[serde(alias = "Ссылка")] #[serde(alias = "URL")] #[serde(default)] pub url: String, #[serde(alias = "Дата")] #[serde(default)] pub date: String, #[serde(alias = "Обработан")] #[serde(default)] pub processed_by: String, #[serde(alias = "Редактор")] #[serde(default)] pub redacted_by: String, #[serde(alias = "Копирайт")] #[serde(default)] pub copyright: String, #[serde(alias = "Тема")] #[serde(default)] pub theme: String, #[serde(alias = "Вид")] #[serde(alias = "Тип")] #[serde(default)] pub kind: String, #[serde(alias = "Источник")] #[serde(default)] pub source: String, #[serde(alias = "Рейтинг")] #[serde(default)] pub rating: String, #[serde(alias = "Вопросы")] pub questions: Vec, } pub struct SourceQuestionsZipReader where R: Read + Seek, { zipfile: ZipArchive, index: Option, } impl SourceQuestionsZipReader where R: Read + Seek, { fn new(zipfile: ZipArchive) -> Self { SourceQuestionsZipReader { zipfile, index: None, } } } impl Iterator for SourceQuestionsZipReader where R: Read + Seek, { type Item = (String, Result); fn next(&mut self) -> Option { if self.index.is_none() && !self.zipfile.is_empty() { self.index = Some(0); } match self.index { Some(i) if i < self.zipfile.len() => { self.index = Some(i + 1); self.nth(i) } _ => None, } } fn nth(&mut self, n: usize) -> Option { if self.zipfile.len() <= n { return None; } self.index = Some(n + 1); let file = self.zipfile.by_index(n).unwrap(); let name = file.mangled_name(); let name_str = name.to_str().unwrap(); let data: Result = serde_json::from_reader(file); Some((String::from(name_str), data)) } fn size_hint(&self) -> (usize, Option) { let len = self.zipfile.len(); let index = self.index.unwrap_or(0); let rem = if len > index + 1 { len - (index + 1) } else { 0 }; (rem, Some(rem)) } fn count(self) -> usize where Self: Sized, { self.zipfile.len() } } impl ExactSizeIterator for SourceQuestionsZipReader where R: Read + Seek, { fn len(&self) -> usize { self.zipfile.len() } } pub trait ReadSourceQuestionsBatches where R: Read + Seek, { fn source_questions(self) -> SourceQuestionsZipReader; } impl ReadSourceQuestionsBatches for ZipArchive where R: Read + Seek, { fn source_questions(self) -> SourceQuestionsZipReader { SourceQuestionsZipReader::new(self) } }