// Stiletto // Copyright (C) 2020 Stiletto Authors // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . use crate::{DocumentSnapshot, STILETTO_FORMAT_MAJOR, STILETTO_FORMAT_MINOR}; use std::error::Error; use std::fmt; use std::fs::File; use std::io; use std::path::PathBuf; #[derive(Debug)] pub enum MigrationError { SerdeJsonError(serde_json::Error), SerdeBareError(serde_bare::Error), IoError(io::Error), UnexpectedVersion(u16, u16, u16, u16), } #[derive(Debug)] pub enum StilettoDocument { DocumentSnapshot0_1(DocumentSnapshot), DocumentSnapshot0_2(DocumentSnapshot), } impl StilettoDocument { pub fn version(&self) -> (u16, u16) { match &self { StilettoDocument::DocumentSnapshot0_1(_) => (0, 1), StilettoDocument::DocumentSnapshot0_2(_) => (0, 2), } } pub fn migrate_to_next(self) -> StilettoDocument { match self { StilettoDocument::DocumentSnapshot0_1(snapshot) => StilettoDocument::DocumentSnapshot0_2(snapshot) , StilettoDocument::DocumentSnapshot0_2(_) => self, } } pub fn migrate_to_latest(mut self) -> DocumentSnapshot { while self.version() != (STILETTO_FORMAT_MAJOR, STILETTO_FORMAT_MINOR) { self = self.migrate_to_next() } assert!(matches!(self, StilettoDocument::DocumentSnapshot0_2(_))); match self { StilettoDocument::DocumentSnapshot0_2(snapshot) => snapshot, _ => panic!("Wrong Document Snapshot Version") } } } impl fmt::Display for MigrationError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self { MigrationError::SerdeJsonError(e) => e.fmt(f), MigrationError::SerdeBareError(e) => e.fmt(f), MigrationError::IoError(e) => e.fmt(f), MigrationError::UnexpectedVersion(major, minor, e_major, e_minor) => { write!( f, "Unexpected version ({}, {}): was expecting ({}, {})", major, minor, e_major, e_minor ) }, } } } impl Error for MigrationError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { MigrationError::SerdeJsonError(e) => e.source(), MigrationError::SerdeBareError(e) => e.source(), MigrationError::IoError(e) => e.source(), MigrationError::UnexpectedVersion(..) => None, } } } impl From for MigrationError { fn from(error: io::Error) -> Self { MigrationError::IoError(error) } } impl From for MigrationError { fn from(error: serde_json::Error) -> Self { MigrationError::SerdeJsonError(error) } } impl From for MigrationError { fn from(error: serde_bare::Error) -> Self { MigrationError::SerdeBareError(error) } } fn open_0_1(path: &PathBuf) -> Result { let f = File::open(path)?; let document_snapshot: DocumentSnapshot = serde_json::from_reader(f)?; if document_snapshot.format_version_major != 0 || document_snapshot.format_version_minor != 1 { Err(MigrationError::UnexpectedVersion( document_snapshot.format_version_major, document_snapshot.format_version_minor, 0, 1 )) } else { Ok(StilettoDocument::DocumentSnapshot0_1(document_snapshot)) } } fn open_0_2(path: &PathBuf) -> Result { let f = File::open(path)?; let document_snapshot: DocumentSnapshot = serde_bare::from_reader(f)?; Ok(StilettoDocument::DocumentSnapshot0_2(document_snapshot)) } pub fn open_stiletto_document(path: &PathBuf) -> Result { if let Ok(res) = open_0_1(path) { return Ok(res); } open_0_2(path) }