// Copyright 2018 Zach Miller
//
// Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT License (https://opensource.org/licenses/MIT), at your option.
//
// This file may not be copied, modified, or distributed except according to those terms.

//! Provides checkpointing of application data for the Rust Programming Language.
//!
//! This library provides functionality to create checkpoints of application data and to restore
//! application data from existing checkpoints.
//!
//! This library is built around three traits: [`Storage`], [`UncommittedCheckpoint`], and
//! [`CommittedCheckpoint`].
//!
//! Types which implement `Storage` are responsible for managing the medium in which checkpointed
//! data is stored. Associated with each `Storage` type are two additional types, which implement
//! `UncommittedCheckpoint` and `CommittedCheckpoint` respectively. These types allow data to be
//! inserted into checkpoint storage, read from checkpoint storage, and removed from checkpoint
//! storage.
//!
//! This library currently provides [`FileStorage`] and [`MemoryStorage`] to store checkpoint data
//! in the file system and in memory.
//!
//! The [`wrappers`] module provides types that can add functionality to `Storage` types.
//! This library currently provides the following wrappers:
//! * [`ChecksumWrapper`] - Adds checksum verification to checkpoint data.
//! * [`GuardWrapper`] - Ensures that multiple uncommitted checkpoints are not given the same
//! identifier and that committed checkpoints are not in use before they are removed.
//! * [`HmacWrapper`] - Adds HMAC verification to checkpoint data.
//!
//! Note: Care must be taken to ensure that wrappers are applied in the desired order, as wrapper
//! ordering matters.
//!
//! [`ChecksumWrapper`]: wrappers/struct.ChecksumWrapper.html
//! [`CommittedCheckpoint`]: storage/trait.CommittedCheckpoint.html
//! [`FileStorage`]: storage/struct.FileStorage.html
//! [`GuardWrapper`]: wrappers/struct.GuardWrapper.html
//! [`HmacWrapper`]: wrappers/struct.HmacWrapper.html
//! [`MemoryStorage`]: storage/struct.MemoryStorage.html
//! [`Storage`]: storage/trait.Storage.html
//! [`UncommittedCheckpoint`]: storage/trait.UncommittedCheckpoint.html
//! [`wrappers`]: wrappers/index.html
//!
//! Example Usage:
//!
//! ```
//! # fn main() {}
//! // Checkpoint data is serialized and deserialized with the Serde library.
//! extern crate serde;
//! #[macro_use] extern crate serde_derive;
//!
//! use serde::de::DeserializeOwned;
//! use serde::ser::Serialize;
//!
//! extern crate checkpoint;
//!
//! use checkpoint::Result;
//! use checkpoint::storage::{
//!     CommittedCheckpoint, Storage, MemoryStorage, UncommittedCheckpoint};
//! use checkpoint::wrappers::ChecksumWrapper;
//!
//! // Any type implementing the Serialize and DeserializeOwned traits can be checkpointed.
//! #[derive(Deserialize, Serialize)]
//! struct Person {
//!     name: String,
//!     age: u8
//! }
//!
//! # fn example() -> Result<()> {
//! // Create the data that will be stored in a checkpoint.
//! let person = Person {
//!     name: String::from("John Smith"),
//!     age: 50
//! };
//!
//! // Create a MemoryStorage object to hold checkpoint data.
//! let storage = MemoryStorage::new()?;
//!
//! // Add integrity checks to checkpoint data with a ChecksumWrapper.
//! let mut wrapped_storage = ChecksumWrapper::wrap(storage);
//!
//! // Create a new checkpoint.
//! let mut uncommitted_checkpoint = wrapped_storage.create_checkpoint("Checkpoint")?;
//!
//! // Add data to the checkpoint.
//! uncommitted_checkpoint.put("Person", &person)?;
//!
//! // Commit the checkpoint.
//! let mut committed_checkpoint = wrapped_storage.commit_checkpoint(uncommitted_checkpoint)?;
//!
//! // Retrieve the checkpoint data.
//! let stored_person: Person = committed_checkpoint.get("Person")?;
//!
//! // The data retrieved from the checkpoint is the same as what was put in.
//! assert_eq!(person.name, stored_person.name);
//! assert_eq!(person.age, stored_person.age);
//!
//! # Ok(())
//! # }
//! ```

extern crate bincode;

extern crate failure;

extern crate hmac;

extern crate serde;

#[macro_use]
extern crate serde_derive;

extern crate sha2;

#[cfg(all(test, feature = "filestorage-tests"))]
extern crate tempfile;

#[cfg(all(test, feature = "filestorage-tests"))]
mod test_utils;

pub mod error;
pub mod storage;
pub mod wrappers;

#[doc(inline)]
pub use self::error::{Error, Result};

#[doc(inline)]
pub use self::storage::{CommittedCheckpoint, Storage, UncommittedCheckpoint};
