daybreak/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#![deny(
6    missing_docs,
7    non_camel_case_types,
8    non_snake_case,
9    path_statements,
10    trivial_casts,
11    trivial_numeric_casts,
12    unsafe_code,
13    unstable_features,
14    unused_allocation,
15    unused_import_braces,
16    unused_imports,
17    unused_must_use,
18    unused_mut,
19    while_true,
20    clippy::panic,
21    clippy::print_stdout,
22    clippy::todo,
23    //clippy::unwrap_used, // not yet in stable
24    clippy::wrong_pub_self_convention
25)]
26#![warn(clippy::pedantic)]
27// part of `clippy::pedantic`, causing many warnings
28#![allow(clippy::missing_errors_doc, clippy::module_name_repetitions)]
29
30//! # Daybreak
31//!
32//! Daybreak was a Ruby [Daybreak][daybreak] inspired single file Database.
33//! It has now since evolved into something else. Please check v1 for a more
34//! similar version.
35//!
36//! This is a continuation of the Rustbreak project, which is now
37//! archived.
38//!
39//! You will find an overview here in the docs, but to give you a more complete
40//! tale of how this is used please check the [examples][examples].
41//!
42//! At its core, Daybreak is an attempt at making a configurable
43//! general-purpose store Database. It features the possibility of:
44//!
45//! - Choosing what kind of Data is stored in it
46//! - Which kind of Serialization is used for persistence
47//! - Which kind of persistence is used
48//!
49//! This means you can take any struct you can serialize and deserialize and
50//! stick it into this Database. It is then encoded with Ron, Yaml, JSON,
51//! Bincode, anything really that uses Serde operations!
52//!
53//! There are three helper type aliases [`MemoryDatabase`], [`FileDatabase`],
54//! and [`PathDatabase`], each backed by their respective backend.
55//!
56//! The [`MemoryBackend`] saves its data into a `Vec<u8>`, which is not that
57//! useful on its own, but is needed for compatibility with the rest of the
58//! Library.
59//!
60//! The [`FileDatabase`] is a classical file based database. You give it a path
61//! or a file, and it will use it as its storage. You still get to pick what
62//! encoding it uses.
63//!
64//! The [`PathDatabase`] is very similar, but always requires a path for
65//! creation. It features atomic saves, so that the old database contents won't
66//! be lost when panicing during the save. It should therefore be preferred to a
67//! [`FileDatabase`].
68//!
69//! Using the [`Database::with_deser`] and [`Database::with_backend`] one can
70//! switch between the representations one needs. Even at runtime! However this
71//! is only useful in a few scenarios.
72//!
73//! If you have any questions feel free to ask at the main [repo][repo].
74//!
75//! ## Quickstart
76//!
77//! Add this to your `Cargo.toml`:
78//!
79//! ```toml
80//! [dependencies.rustbreak]
81//! version = "2"
82//! features = ["ron_enc"] # You can also use "yaml_enc" or "bin_enc"
83//!                        # Check the documentation to add your own!
84//! ```
85//!
86//! ```rust
87//! # extern crate daybreak;
88//! # use std::collections::HashMap;
89//! use daybreak::{deser::Ron, MemoryDatabase};
90//!
91//! # fn main() {
92//! # let func = || -> Result<(), Box<dyn std::error::Error>> {
93//! let db = MemoryDatabase::<HashMap<u32, String>, Ron>::memory(HashMap::new())?;
94//!
95//! println!("Writing to Database");
96//! db.write(|db| {
97//!     db.insert(0, String::from("world"));
98//!     db.insert(1, String::from("bar"));
99//! });
100//!
101//! db.read(|db| {
102//!     // db.insert("foo".into(), String::from("bar"));
103//!     // The above line will not compile since we are only reading
104//!     println!("Hello: {:?}", db.get(&0));
105//! })?;
106//! # return Ok(()); };
107//! # func().unwrap();
108//! # }
109//! ```
110//!
111//! Or alternatively:
112//! ```rust
113//! # extern crate daybreak;
114//! # use std::collections::HashMap;
115//! use daybreak::{deser::Ron, MemoryDatabase};
116//!
117//! # fn main() {
118//! # let func = || -> Result<(), Box<dyn std::error::Error>> {
119//! let db = MemoryDatabase::<HashMap<u32, String>, Ron>::memory(HashMap::new())?;
120//!
121//! println!("Writing to Database");
122//! {
123//!     let mut data = db.borrow_data_mut()?;
124//!     data.insert(0, String::from("world"));
125//!     data.insert(1, String::from("bar"));
126//! }
127//!
128//! let data = db.borrow_data()?;
129//! println!("Hello: {:?}", data.get(&0));
130//! # return Ok(()); };
131//! # func().unwrap();
132//! # }
133//! ```
134//!
135//! ## Error Handling
136//!
137//! Handling errors in Daybreak is straightforward. Every `Result` has as its
138//! fail case as [`error::Error`]. This means that you can now either
139//! continue bubbling up said error case, or handle it yourself.
140//!
141//! ```rust
142//! use daybreak::{deser::Ron, error::Error, MemoryDatabase};
143//! let db = match MemoryDatabase::<usize, Ron>::memory(0) {
144//!     Ok(db) => db,
145//!     Err(e) => {
146//!         // Do something with `e` here
147//!         std::process::exit(1);
148//!     }
149//! };
150//! ```
151//!
152//! ## Panics
153//!
154//! This Database implementation uses [`RwLock`] and [`Mutex`] under the hood.
155//! If either the closures given to [`Database::write`] or any of the Backend
156//! implementation methods panic the respective objects are then poisoned. This
157//! means that you *cannot panic* under any circumstances in your closures or
158//! custom backends.
159//!
160//! Currently there is no way to recover from a poisoned `Database` other than
161//! re-creating it.
162//!
163//! ## Examples
164//!
165//! There are several more or less in-depth example programs you can check out!
166//! Check them out here: [Examples][examples]
167//!
168//! - `config.rs` shows you how a possible configuration file could be managed
169//!   with rustbreak
170//! - `full.rs` shows you how the database can be used as a hashmap store
171//! - `switching.rs` show you how you can easily swap out different parts of the
172//!   Database *Note*: To run this example you need to enable the feature `yaml`
173//!   like so: `cargo run --example switching --features yaml`
174//! - `server/` is a fully fledged example app written with the Rocket framework
175//!   to make a form of micro-blogging website. You will need rust nightly to
176//!   start it.
177//!
178//! ## Features
179//!
180//! Daybreak comes with following optional features:
181//!
182//! - `ron_enc` which enables the [Ron][ron] de/serialization
183//! - `yaml_enc` which enables the Yaml de/serialization
184//! - `bin_enc` which enables the Bincode de/serialization
185//! - 'mmap' whhich enables memory map backend.
186//!
187//! [Enable them in your `Cargo.toml` file to use them.][features] You can
188//! safely have them all turned on per-default.
189//!
190//!
191//! [repo]: https://github.com/TheNeikos/rustbreak
192//! [daybreak]: https://propublica.github.io/daybreak
193//! [examples]: https://github.com/corepaper/daybreak/tree/master/examples
194//! [ron]: https://github.com/ron-rs/ron
195//! [features]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#choosing-features
196
197pub mod backend;
198/// Different serialization and deserialization methods one can use
199pub mod deser;
200/// The rustbreak errors that can be returned
201pub mod error;
202
203/// The `DeSerializer` trait used by serialization structs
204pub use crate::deser::DeSerializer;
205use std::fmt::Debug;
206use std::ops::Deref;
207use std::path::PathBuf;
208use std::sync::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
209
210use serde::de::DeserializeOwned;
211use serde::Serialize;
212
213#[cfg(feature = "mmap")]
214use crate::backend::MmapStorage;
215use crate::backend::{Backend, FileBackend, MemoryBackend, PathBackend};
216
217pub use crate::error::*;
218
219/// The Central Database to Daybreak.
220///
221/// It has 3 Type Generics:
222///
223/// - `Data`: Is the Data, you must specify this
224/// - `Back`: The storage backend.
225/// - `DeSer`: The Serializer/Deserializer or short `DeSer`. Check the [`deser`]
226///   module for other strategies.
227///
228/// # Panics
229///
230/// If the backend or the de/serialization panics, the database is poisoned.
231/// This means that any subsequent writes/reads will fail with an
232/// [`error::Error::Poison`]. You can only recover from this by
233/// re-creating the Database Object.
234#[derive(Debug)]
235pub struct Database<Data, Back, DeSer> {
236    data: RwLock<Data>,
237    backend: Mutex<Back>,
238    deser: DeSer,
239}
240
241impl<Data, Back, DeSer> Database<Data, Back, DeSer>
242where
243    Data: Serialize + DeserializeOwned + Clone + Send,
244    Back: Backend,
245    DeSer: DeSerializer<Data> + Send + Sync + Clone,
246{
247    /// Write lock the database and get write access to the `Data` container.
248    ///
249    /// This gives you an exclusive lock on the memory object. Trying to open
250    /// the database in writing will block if it is currently being written
251    /// to.
252    ///
253    /// # Panics
254    ///
255    /// If you panic in the closure, the database is poisoned. This means that
256    /// any subsequent writes/reads will fail with an
257    /// [`error::Error::Poison`]. You can only recover from
258    /// this by re-creating the Database Object.
259    ///
260    /// If you do not have full control over the code being written, and cannot
261    /// incur the cost of having a single operation panicking then use
262    /// [`Database::write_safe`].
263    ///
264    /// # Examples
265    ///
266    /// ```rust
267    /// # #[macro_use] extern crate serde_derive;
268    /// # extern crate daybreak;
269    /// # extern crate serde;
270    /// # extern crate tempfile;
271    /// use daybreak::{deser::Ron, FileDatabase};
272    ///
273    /// #[derive(Debug, Serialize, Deserialize, Clone)]
274    /// struct Data {
275    ///     level: u32,
276    /// }
277    ///
278    /// # fn main() {
279    /// # let func = || -> Result<(), Box<dyn std::error::Error>> {
280    /// # let file = tempfile::tempfile()?;
281    /// let db = FileDatabase::<Data, Ron>::from_file(file, Data { level: 0 })?;
282    ///
283    /// db.write(|db| {
284    ///     db.level = 42;
285    /// })?;
286    ///
287    /// // You can also return from a `.read()`. But don't forget that you cannot return references
288    /// // into the structure
289    /// let value = db.read(|db| db.level)?;
290    /// assert_eq!(42, value);
291    /// # return Ok(());
292    /// # };
293    /// # func().unwrap();
294    /// # }
295    /// ```
296    pub fn write<T, R>(&self, task: T) -> error::Result<R>
297    where
298        T: FnOnce(&mut Data) -> R,
299    {
300        let mut lock = self.data.write().map_err(|_| Error::Poison)?;
301        Ok(task(&mut lock))
302    }
303
304    /// Write lock the database and get write access to the `Data` container in
305    /// a safe way.
306    ///
307    /// This gives you an exclusive lock on the memory object. Trying to open
308    /// the database in writing will block if it is currently being written
309    /// to.
310    ///
311    /// This differs to `Database::write` in that a clone of the internal data
312    /// is made, which is then passed to the closure. Only if the closure
313    /// doesn't panic is the internal model updated.
314    ///
315    /// Depending on the size of the database this can be very costly. This is a
316    /// tradeoff to make for panic safety.
317    ///
318    /// You should read the documentation about this:
319    /// [`UnwindSafe`](https://doc.rust-lang.org/std/panic/trait.UnwindSafe.html)
320    ///
321    /// # Panics
322    ///
323    /// When the closure panics, it is caught and a
324    /// [`error::Error::WritePanic`] will be returned.
325    ///
326    /// # Examples
327    ///
328    /// ```rust
329    /// # #[macro_use] extern crate serde_derive;
330    /// # extern crate daybreak;
331    /// # extern crate serde;
332    /// # extern crate tempfile;
333    /// use daybreak::{
334    ///     deser::Ron,
335    ///     error::Error,
336    ///     FileDatabase,
337    /// };
338    ///
339    /// #[derive(Debug, Serialize, Deserialize, Clone)]
340    /// struct Data {
341    ///     level: u32,
342    /// }
343    ///
344    /// # fn main() {
345    /// # let func = || -> Result<(), Box<dyn std::error::Error>> {
346    /// # let file = tempfile::tempfile()?;
347    /// let db = FileDatabase::<Data, Ron>::from_file(file, Data { level: 0 })?;
348    ///
349    /// let result = db
350    ///     .write_safe(|db| {
351    ///         db.level = 42;
352    ///         panic!("We panic inside the write code.");
353    ///     })
354    ///     .expect_err("This should have been caught");
355    ///
356    /// match result {
357    ///     Error::WritePanic => {
358    ///         // We can now handle this, in this example we will just ignore it
359    ///     }
360    ///     e => {
361    ///         println!("{:#?}", e);
362    ///         // You should always have generic error catching here.
363    ///         // This future-proofs your code, and makes your code more robust.
364    ///         // In this example this is unreachable though, and to assert that we have this
365    ///         // macro here
366    ///         unreachable!();
367    ///     }
368    /// }
369    ///
370    /// // We read it back out again, it has not changed
371    /// let value = db.read(|db| db.level)?;
372    /// assert_eq!(0, value);
373    /// # return Ok(());
374    /// # };
375    /// # func().unwrap();
376    /// # }
377    /// ```
378    pub fn write_safe<T>(&self, task: T) -> error::Result<()>
379    where
380        T: FnOnce(&mut Data) + std::panic::UnwindSafe,
381    {
382        let mut lock = self.data.write().map_err(|_| Error::Poison)?;
383        let mut data = lock.clone();
384        std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
385            task(&mut data);
386        }))
387        .map_err(|_| Error::WritePanic)?;
388        *lock = data;
389        Ok(())
390    }
391
392    /// Read lock the database and get read access to the `Data` container.
393    ///
394    /// This gives you a read-only lock on the database. You can have as many
395    /// readers in parallel as you wish.
396    ///
397    /// # Errors
398    ///
399    /// May return:
400    ///
401    /// - [`error::Error::Backend`]
402    ///
403    /// # Panics
404    ///
405    /// If you panic in the closure, the database is poisoned. This means that
406    /// any subsequent writes/reads will fail with an
407    /// [`error::Error::Poison`]. You can only recover from
408    /// this by re-creating the Database Object.
409    pub fn read<T, R>(&self, task: T) -> error::Result<R>
410    where
411        T: FnOnce(&Data) -> R,
412    {
413        let mut lock = self.data.read().map_err(|_| Error::Poison)?;
414        Ok(task(&mut lock))
415    }
416
417    /// Read lock the database and get access to the underlying struct.
418    ///
419    /// This gives you access to the underlying struct, allowing for simple read
420    /// only operations on it.
421    ///
422    /// # Examples
423    ///
424    /// ```rust
425    /// # #[macro_use] extern crate serde_derive;
426    /// # extern crate daybreak;
427    /// # extern crate serde;
428    /// # extern crate tempfile;
429    /// use daybreak::{deser::Ron, FileDatabase};
430    ///
431    /// #[derive(Debug, Serialize, Deserialize, Clone)]
432    /// struct Data {
433    ///     level: u32,
434    /// }
435    ///
436    /// # fn main() {
437    /// # let func = || -> Result<(), Box<dyn std::error::Error>> {
438    /// # let file = tempfile::tempfile()?;
439    /// let db = FileDatabase::<Data, Ron>::from_file(file, Data { level: 0 })?;
440    ///
441    /// db.write(|db| {
442    ///     db.level = 42;
443    /// })?;
444    ///
445    /// let data = db.borrow_data()?;
446    ///
447    /// assert_eq!(42, data.level);
448    /// # return Ok(());
449    /// # };
450    /// # func().unwrap();
451    /// # }
452    /// ```
453    pub fn borrow_data<'a>(&'a self) -> error::Result<RwLockReadGuard<'a, Data>> {
454        self.data.read().map_err(|_| Error::Poison)
455    }
456
457    /// Write lock the database and get access to the underlying struct.
458    ///
459    /// This gives you access to the underlying struct, allowing you to modify
460    /// it.
461    ///
462    /// # Panics
463    ///
464    /// If you panic while holding this reference, the database is poisoned.
465    /// This means that any subsequent writes/reads will fail with an
466    /// [`error::Error::Poison`]. You can only recover from
467    /// this by re-creating the Database Object.
468    ///
469    /// If you do not have full control over the code being written, and cannot
470    /// incur the cost of having a single operation panicking then use
471    /// [`Database::write_safe`].
472    ///
473    /// # Examples
474    ///
475    /// ```rust
476    /// # #[macro_use] extern crate serde_derive;
477    /// # extern crate daybreak;
478    /// # extern crate serde;
479    /// # extern crate tempfile;
480    /// use daybreak::{deser::Ron, FileDatabase};
481    ///
482    /// #[derive(Debug, Serialize, Deserialize, Clone)]
483    /// struct Data {
484    ///     level: u32,
485    /// }
486    ///
487    /// # fn main() {
488    /// # let func = || -> Result<(), Box<dyn std::error::Error>> {
489    /// # let file = tempfile::tempfile()?;
490    /// let db = FileDatabase::<Data, Ron>::from_file(file, Data { level: 0 })?;
491    ///
492    /// {
493    ///     let mut data = db.borrow_data_mut()?;
494    ///     data.level = 42;
495    /// }
496    ///
497    /// let data = db.borrow_data()?;
498    ///
499    /// assert_eq!(42, data.level);
500    /// # return Ok(());
501    /// # };
502    /// # func().unwrap();
503    /// # }
504    /// ```
505    pub fn borrow_data_mut<'a>(&'a self) -> error::Result<RwLockWriteGuard<'a, Data>> {
506        self.data.write().map_err(|_| Error::Poison)
507    }
508
509    /// Load data from backend and return this data.
510    fn load_from_backend(backend: &mut Back, deser: &DeSer) -> error::Result<Data> {
511        let new_data = deser.deserialize(&backend.get_data()?[..])?;
512
513        Ok(new_data)
514    }
515
516    /// Like [`Self::load`] but returns the write lock to data it used.
517    fn load_get_data_lock(&self) -> error::Result<RwLockWriteGuard<'_, Data>> {
518        let mut backend_lock = self.backend.lock().map_err(|_| Error::Poison)?;
519
520        let fresh_data = Self::load_from_backend(&mut backend_lock, &self.deser)?;
521        drop(backend_lock);
522
523        let mut data_write_lock = self.data.write().map_err(|_| Error::Poison)?;
524        *data_write_lock = fresh_data;
525        Ok(data_write_lock)
526    }
527
528    /// Load the data from the backend.
529    pub fn load(&self) -> error::Result<()> {
530        self.load_get_data_lock().map(|_| ())
531    }
532
533    /// Like [`Self::save`] but with explicit read (or write) lock to data.
534    fn save_data_locked<L: Deref<Target = Data>>(&self, lock: L) -> error::Result<()> {
535        let ser = self.deser.serialize(lock.deref())?;
536        drop(lock);
537
538        let mut backend = self.backend.lock().map_err(|_| Error::Poison)?;
539        backend.put_data(&ser)?;
540        Ok(())
541    }
542
543    /// Flush the data structure to the backend.
544    pub fn save(&self) -> error::Result<()> {
545        let data = self.data.read().map_err(|_| Error::Poison)?;
546        self.save_data_locked(data)
547    }
548
549    /// Get a clone of the data as it is in memory right now.
550    ///
551    /// To make sure you have the latest data, call this method with `load`
552    /// true.
553    pub fn get_data(&self, load: bool) -> error::Result<Data> {
554        let data = if load {
555            self.load_get_data_lock()?
556        } else {
557            self.data.write().map_err(|_| Error::Poison)?
558        };
559        Ok(data.clone())
560    }
561
562    /// Puts the data as is into memory.
563    ///
564    /// To save the data afterwards, call with `save` true.
565    pub fn put_data(&self, new_data: Data, save: bool) -> error::Result<()> {
566        let mut data = self.data.write().map_err(|_| Error::Poison)?;
567        *data = new_data;
568        if save {
569            self.save_data_locked(data)
570        } else {
571            Ok(())
572        }
573    }
574
575    /// Create a database from its constituents.
576    pub fn from_parts(data: Data, backend: Back, deser: DeSer) -> Self {
577        Self {
578            data: RwLock::new(data),
579            backend: Mutex::new(backend),
580            deser,
581        }
582    }
583
584    /// Break a database into its individual parts.
585    pub fn into_inner(self) -> error::Result<(Data, Back, DeSer)> {
586        Ok((
587            self.data.into_inner().map_err(|_| Error::Poison)?,
588            self.backend
589                .into_inner()
590                .map_err(|_| Error::Poison)?,
591            self.deser,
592        ))
593    }
594
595    /// Tries to clone the Data in the Database.
596    ///
597    /// This method returns a `MemoryDatabase` which has an empty vector as a
598    /// backend initially. This means that the user is responsible for assigning
599    /// a new backend if an alternative is wanted.
600    ///
601    /// # Examples
602    ///
603    /// ```rust
604    /// # #[macro_use] extern crate serde_derive;
605    /// # extern crate daybreak;
606    /// # extern crate serde;
607    /// # extern crate tempfile;
608    /// use daybreak::{deser::Ron, FileDatabase};
609    ///
610    /// #[derive(Debug, Serialize, Deserialize, Clone)]
611    /// struct Data {
612    ///     level: u32,
613    /// }
614    ///
615    /// # fn main() {
616    /// # let func = || -> Result<(), Box<dyn std::error::Error>> {
617    /// # let file = tempfile::tempfile()?;
618    /// let db = FileDatabase::<Data, Ron>::from_file(file, Data { level: 0 })?;
619    ///
620    /// db.write(|db| {
621    ///     db.level = 42;
622    /// })?;
623    ///
624    /// db.save()?;
625    ///
626    /// let other_db = db.try_clone()?;
627    ///
628    /// // You can also return from a `.read()`. But don't forget that you cannot return references
629    /// // into the structure
630    /// let value = other_db.read(|db| db.level)?;
631    /// assert_eq!(42, value);
632    /// # return Ok(());
633    /// # };
634    /// # func().unwrap();
635    /// # }
636    /// ```
637    pub fn try_clone(&self) -> error::Result<MemoryDatabase<Data, DeSer>> {
638        let lock = self.data.read().map_err(|_| Error::Poison)?;
639
640        Ok(Database {
641            data: RwLock::new(lock.clone()),
642            backend: Mutex::new(MemoryBackend::new()),
643            deser: self.deser.clone(),
644        })
645    }
646}
647
648/// A database backed by a file.
649pub type FileDatabase<D, DS> = Database<D, FileBackend, DS>;
650
651impl<Data, DeSer> Database<Data, FileBackend, DeSer>
652where
653    Data: Serialize + DeserializeOwned + Clone + Send,
654    DeSer: DeSerializer<Data> + Send + Sync + Clone,
655{
656    /// Create new [`FileDatabase`] from the file at [`Path`](std::path::Path),
657    /// and load the contents.
658    pub fn load_from_path<S>(path: S) -> error::Result<Self>
659    where
660        S: AsRef<std::path::Path>,
661    {
662        let mut backend = FileBackend::from_path_or_fail(path)?;
663        let deser = DeSer::default();
664        let data = Self::load_from_backend(&mut backend, &deser)?;
665
666        let db = Self {
667            data: RwLock::new(data),
668            backend: Mutex::new(backend),
669            deser,
670        };
671        Ok(db)
672    }
673
674    /// Load [`FileDatabase`] at `path` or initialise with `data`.
675    ///
676    /// Create new [`FileDatabase`] from the file at [`Path`](std::path::Path),
677    /// and load the contents. If the file does not exist, initialise with
678    /// `data`.
679    pub fn load_from_path_or<S>(path: S, data: Data) -> error::Result<Self>
680    where
681        S: AsRef<std::path::Path>,
682    {
683        let (mut backend, exists) = FileBackend::from_path_or_create(path)?;
684        let deser = DeSer::default();
685        if !exists {
686            let ser = deser.serialize(&data)?;
687            backend.put_data(&ser)?;
688        }
689
690        let db = Self {
691            data: RwLock::new(data),
692            backend: Mutex::new(backend),
693            deser,
694        };
695
696        if exists {
697            db.load()?;
698        }
699
700        Ok(db)
701    }
702
703    /// Load [`FileDatabase`] at `path` or initialise with `closure`.
704    ///
705    /// Create new [`FileDatabase`] from the file at [`Path`](std::path::Path),
706    /// and load the contents. If the file does not exist, `closure` is
707    /// called and the database is initialised with it's return value.
708    pub fn load_from_path_or_else<S, C>(path: S, closure: C) -> error::Result<Self>
709    where
710        S: AsRef<std::path::Path>,
711        C: FnOnce() -> Data,
712    {
713        let (mut backend, exists) = FileBackend::from_path_or_create(path)?;
714        let deser = DeSer::default();
715        let data = if exists {
716            Self::load_from_backend(&mut backend, &deser)?
717        } else {
718            let data = closure();
719
720            let ser = deser.serialize(&data)?;
721            backend.put_data(&ser)?;
722
723            data
724        };
725
726        let db = Self {
727            data: RwLock::new(data),
728            backend: Mutex::new(backend),
729            deser,
730        };
731        Ok(db)
732    }
733
734    /// Create [`FileDatabase`] at `path`. Initialise with `data` if the file
735    /// doesn't exist.
736    ///
737    /// Create new [`FileDatabase`] from the file at [`Path`](std::path::Path).
738    /// Contents are not loaded. If the file does not exist, it is
739    /// initialised with `data`. Frontend is always initialised with `data`.
740    pub fn create_at_path<S>(path: S, data: Data) -> error::Result<Self>
741    where
742        S: AsRef<std::path::Path>,
743    {
744        let (mut backend, exists) = FileBackend::from_path_or_create(path)?;
745        let deser = DeSer::default();
746        if !exists {
747            let ser = deser.serialize(&data)?;
748            backend.put_data(&ser)?;
749        }
750
751        let db = Self {
752            data: RwLock::new(data),
753            backend: Mutex::new(backend),
754            deser,
755        };
756        Ok(db)
757    }
758
759    /// Create new [`FileDatabase`] from a file.
760    pub fn from_file(file: std::fs::File, data: Data) -> error::Result<Self> {
761        let backend = FileBackend::from_file(file);
762
763        Ok(Self {
764            data: RwLock::new(data),
765            backend: Mutex::new(backend),
766            deser: DeSer::default(),
767        })
768    }
769}
770
771impl<Data, DeSer> Database<Data, FileBackend, DeSer>
772where
773    Data: Serialize + DeserializeOwned + Clone + Send + Default,
774    DeSer: DeSerializer<Data> + Send + Sync + Clone,
775{
776    /// Load [`FileDatabase`] at `path` or initialise with `Data::default()`.
777    ///
778    /// Create new [`FileDatabase`] from the file at [`Path`](std::path::Path),
779    /// and load the contents. If the file does not exist, initialise with
780    /// `Data::default`.
781    pub fn load_from_path_or_default<S>(path: S) -> error::Result<Self>
782    where
783        S: AsRef<std::path::Path>,
784    {
785        Self::load_from_path_or_else(path, Data::default)
786    }
787}
788
789/// A database backed by a file, using atomic saves.
790pub type PathDatabase<D, DS> = Database<D, PathBackend, DS>;
791
792impl<Data, DeSer> Database<Data, PathBackend, DeSer>
793where
794    Data: Serialize + DeserializeOwned + Clone + Send,
795    DeSer: DeSerializer<Data> + Send + Sync + Clone,
796{
797    /// Create new [`PathDatabase`] from the file at [`Path`](std::path::Path),
798    /// and load the contents.
799    pub fn load_from_path(path: PathBuf) -> error::Result<Self> {
800        let mut backend = PathBackend::from_path_or_fail(path)?;
801        let deser = DeSer::default();
802        let data = Self::load_from_backend(&mut backend, &deser)?;
803
804        let db = Self {
805            data: RwLock::new(data),
806            backend: Mutex::new(backend),
807            deser,
808        };
809        Ok(db)
810    }
811
812    /// Load [`PathDatabase`] at `path` or initialise with `data`.
813    ///
814    /// Create new [`PathDatabase`] from the file at [`Path`](std::path::Path),
815    /// and load the contents. If the file does not exist, initialise with
816    /// `data`.
817    pub fn load_from_path_or(path: PathBuf, data: Data) -> error::Result<Self> {
818        let (mut backend, exists) = PathBackend::from_path_or_create(path)?;
819        let deser = DeSer::default();
820        if !exists {
821            let ser = deser.serialize(&data)?;
822            backend.put_data(&ser)?;
823        }
824
825        let db = Self {
826            data: RwLock::new(data),
827            backend: Mutex::new(backend),
828            deser,
829        };
830
831        if exists {
832            db.load()?;
833        }
834
835        Ok(db)
836    }
837
838    /// Load [`PathDatabase`] at `path` or initialise with `closure`.
839    ///
840    /// Create new [`PathDatabase`] from the file at [`Path`](std::path::Path),
841    /// and load the contents. If the file does not exist, `closure` is
842    /// called and the database is initialised with it's return value.
843    pub fn load_from_path_or_else<C>(path: PathBuf, closure: C) -> error::Result<Self>
844    where
845        C: FnOnce() -> Data,
846    {
847        let (mut backend, exists) = PathBackend::from_path_or_create(path)?;
848        let deser = DeSer::default();
849        let data = if exists {
850            Self::load_from_backend(&mut backend, &deser)?
851        } else {
852            let data = closure();
853
854            let ser = deser.serialize(&data)?;
855            backend.put_data(&ser)?;
856
857            data
858        };
859
860        let db = Self {
861            data: RwLock::new(data),
862            backend: Mutex::new(backend),
863            deser,
864        };
865        Ok(db)
866    }
867
868    /// Create [`PathDatabase`] at `path`. Initialise with `data` if the file
869    /// doesn't exist.
870    ///
871    /// Create new [`PathDatabase`] from the file at [`Path`](std::path::Path).
872    /// Contents are not loaded. If the file does not exist, it is
873    /// initialised with `data`. Frontend is always initialised with `data`.
874    pub fn create_at_path(path: PathBuf, data: Data) -> error::Result<Self> {
875        let (mut backend, exists) = PathBackend::from_path_or_create(path)?;
876        let deser = DeSer::default();
877        if !exists {
878            let ser = deser.serialize(&data)?;
879            backend.put_data(&ser)?;
880        }
881
882        let db = Self {
883            data: RwLock::new(data),
884            backend: Mutex::new(backend),
885            deser,
886        };
887        Ok(db)
888    }
889}
890
891impl<Data, DeSer> Database<Data, PathBackend, DeSer>
892where
893    Data: Serialize + DeserializeOwned + Clone + Send + Default,
894    DeSer: DeSerializer<Data> + Send + Sync + Clone,
895{
896    /// Load [`PathDatabase`] at `path` or initialise with `Data::default()`.
897    ///
898    /// Create new [`PathDatabase`] from the file at [`Path`](std::path::Path),
899    /// and load the contents. If the file does not exist, initialise with
900    /// `Data::default`.
901    pub fn load_from_path_or_default(path: PathBuf) -> error::Result<Self> {
902        Self::load_from_path_or_else(path, Data::default)
903    }
904}
905
906/// A database backed by a byte vector (`Vec<u8>`).
907pub type MemoryDatabase<D, DS> = Database<D, MemoryBackend, DS>;
908
909impl<Data, DeSer> Database<Data, MemoryBackend, DeSer>
910where
911    Data: Serialize + DeserializeOwned + Clone + Send,
912    DeSer: DeSerializer<Data> + Send + Sync + Clone,
913{
914    /// Create new in-memory database.
915    pub fn memory(data: Data) -> error::Result<Self> {
916        let backend = MemoryBackend::new();
917
918        Ok(Self {
919            data: RwLock::new(data),
920            backend: Mutex::new(backend),
921            deser: DeSer::default(),
922        })
923    }
924}
925
926/// A database backed by anonymous memory map.
927#[cfg(feature = "mmap")]
928pub type MmapDatabase<D, DS> = Database<D, MmapStorage, DS>;
929
930#[cfg(feature = "mmap")]
931impl<Data, DeSer> Database<Data, MmapStorage, DeSer>
932where
933    Data: Serialize + DeserializeOwned + Clone + Send,
934    DeSer: DeSerializer<Data> + Send + Sync + Clone,
935{
936    /// Create new [`MmapDatabase`].
937    pub fn mmap(data: Data) -> error::Result<Self> {
938        let backend = MmapStorage::new()?;
939
940        Ok(Self {
941            data: RwLock::new(data),
942            backend: Mutex::new(backend),
943            deser: DeSer::default(),
944        })
945    }
946
947    /// Create new [`MmapDatabase`] with specified initial size.
948    pub fn mmap_with_size(data: Data, size: usize) -> error::Result<Self> {
949        let backend = MmapStorage::with_size(size)?;
950
951        Ok(Self {
952            data: RwLock::new(data),
953            backend: Mutex::new(backend),
954            deser: DeSer::default(),
955        })
956    }
957}
958
959impl<Data, Back, DeSer> Database<Data, Back, DeSer> {
960    /// Exchanges the `DeSerialization` strategy with the new one.
961    pub fn with_deser<T>(self, deser: T) -> Database<Data, Back, T> {
962        Database {
963            backend: self.backend,
964            data: self.data,
965            deser,
966        }
967    }
968}
969
970impl<Data, Back, DeSer> Database<Data, Back, DeSer> {
971    /// Exchanges the `Backend` with the new one.
972    ///
973    /// The new backend does not necessarily have the latest data saved to it,
974    /// so a `.save` should be called to make sure that it is saved.
975    pub fn with_backend<T>(self, backend: T) -> Database<Data, T, DeSer> {
976        Database {
977            backend: Mutex::new(backend),
978            data: self.data,
979            deser: self.deser,
980        }
981    }
982}
983
984impl<Data, Back, DeSer> Database<Data, Back, DeSer>
985where
986    Data: Serialize + DeserializeOwned + Clone + Send,
987    Back: Backend,
988    DeSer: DeSerializer<Data> + Send + Sync + Clone,
989{
990    /// Converts from one data type to another.
991    ///
992    /// This method is useful to migrate from one datatype to another.
993    pub fn convert_data<C, OutputData>(
994        self,
995        convert: C,
996    ) -> error::Result<Database<OutputData, Back, DeSer>>
997    where
998        OutputData: Serialize + DeserializeOwned + Clone + Send,
999        C: FnOnce(Data) -> OutputData,
1000        DeSer: DeSerializer<OutputData> + Send + Sync,
1001    {
1002        let (data, backend, deser) = self.into_inner()?;
1003        Ok(Database {
1004            data: RwLock::new(convert(data)),
1005            backend: Mutex::new(backend),
1006            deser,
1007        })
1008    }
1009}
1010
1011#[cfg(test)]
1012mod tests {
1013    use super::*;
1014    use std::collections::HashMap;
1015    use tempfile::NamedTempFile;
1016
1017    type TestData = HashMap<usize, String>;
1018    type TestDb<B> = Database<TestData, B, crate::deser::Ron>;
1019    type TestMemDb = TestDb<MemoryBackend>;
1020
1021    fn test_data() -> TestData {
1022        let mut data = HashMap::new();
1023        data.insert(1, "Hello World".to_string());
1024        data.insert(100, "Rustbreak".to_string());
1025        data
1026    }
1027
1028    /// Used to test that `Default::default` isn't called.
1029    #[derive(Clone, Debug, Serialize, serde::Deserialize)]
1030    struct PanicDefault;
1031    impl Default for PanicDefault {
1032        fn default() -> Self {
1033            panic!("`default` was called but should not")
1034        }
1035    }
1036
1037    #[test]
1038    fn create_db_and_read() {
1039        let db = TestMemDb::memory(test_data()).expect("Could not create database");
1040        assert_eq!(
1041            "Hello World",
1042            db.read(|d| d.get(&1).cloned())
1043                .expect("Rustbreak read error")
1044                .expect("Should be `Some` but was `None`")
1045        );
1046        assert_eq!(
1047            "Rustbreak",
1048            db.read(|d| d.get(&100).cloned())
1049                .expect("Rustbreak read error")
1050                .expect("Should be `Some` but was `None`")
1051        );
1052    }
1053
1054    #[test]
1055    fn write_twice() {
1056        let db = TestMemDb::memory(test_data()).expect("Could not create database");
1057        db.write(|d| d.insert(3, "Write to db".to_string()))
1058            .expect("Rustbreak write error");
1059        db.write(|d| d.insert(3, "Second write".to_string()))
1060            .expect("Rustbreak write error");
1061        assert_eq!(
1062            "Hello World",
1063            db.read(|d| d.get(&1).cloned())
1064                .expect("Rustbreak read error")
1065                .expect("Should be `Some` but was `None`")
1066        );
1067        assert_eq!(
1068            "Rustbreak",
1069            db.read(|d| d.get(&100).cloned())
1070                .expect("Rustbreak read error")
1071                .expect("Should be `Some` but was `None`")
1072        );
1073        assert_eq!(
1074            "Second write",
1075            db.read(|d| d.get(&3).cloned())
1076                .expect("Rustbreak read error")
1077                .expect("Should be `Some` but was `None`")
1078        );
1079    }
1080
1081    #[test]
1082    fn save_load() {
1083        let db = TestMemDb::memory(test_data()).expect("Could not create database");
1084        db.save().expect("Rustbreak save error");
1085        db.write(|d| d.clear()).expect("Rustbreak write error");
1086        db.load().expect("Rustbreak load error");
1087        assert_eq!(
1088            "Hello World",
1089            db.read(|d| d.get(&1).cloned())
1090                .expect("Rustbreak read error")
1091                .expect("Should be `Some` but was `None`")
1092        );
1093        assert_eq!(
1094            "Rustbreak",
1095            db.read(|d| d.get(&100).cloned())
1096                .expect("Rustbreak read error")
1097                .expect("Should be `Some` but was `None`")
1098        );
1099    }
1100
1101    #[test]
1102    fn writesafe_twice() {
1103        let db = TestMemDb::memory(test_data()).expect("Could not create database");
1104        db.write_safe(|d| {
1105            d.insert(3, "Write to db".to_string());
1106        })
1107        .expect("Rustbreak write error");
1108        db.write_safe(|d| {
1109            d.insert(3, "Second write".to_string());
1110        })
1111        .expect("Rustbreak write error");
1112        assert_eq!(
1113            "Hello World",
1114            db.read(|d| d.get(&1).cloned())
1115                .expect("Rustbreak read error")
1116                .expect("Should be `Some` but was `None`")
1117        );
1118        assert_eq!(
1119            "Rustbreak",
1120            db.read(|d| d.get(&100).cloned())
1121                .expect("Rustbreak read error")
1122                .expect("Should be `Some` but was `None`")
1123        );
1124        assert_eq!(
1125            "Second write",
1126            db.read(|d| d.get(&3).cloned())
1127                .expect("Rustbreak read error")
1128                .expect("Should be `Some` but was `None`")
1129        );
1130    }
1131
1132    #[test]
1133    fn writesafe_panic() {
1134        let db = TestMemDb::memory(test_data()).expect("Could not create database");
1135        let err = db
1136            .write_safe(|d| {
1137                d.clear();
1138                panic!("Panic should be catched")
1139            })
1140            .expect_err("Did not error on panic in safe write!");
1141        assert!(matches!(err, Error::WritePanic));
1142
1143        assert_eq!(
1144            "Hello World",
1145            db.read(|d| d.get(&1).cloned())
1146                .expect("Rustbreak read error")
1147                .expect("Should be `Some` but was `None`")
1148        );
1149        assert_eq!(
1150            "Rustbreak",
1151            db.read(|d| d.get(&100).cloned())
1152                .expect("Rustbreak read error")
1153                .expect("Should be `Some` but was `None`")
1154        );
1155    }
1156
1157    #[test]
1158    fn borrow_data_twice() {
1159        let db = TestMemDb::memory(test_data()).expect("Could not create database");
1160        let readlock1 = db.borrow_data().expect("Rustbreak readlock error");
1161        let readlock2 = db.borrow_data().expect("Rustbreak readlock error");
1162        assert_eq!(
1163            "Hello World",
1164            readlock1.get(&1).expect("Should be `Some` but was `None`")
1165        );
1166        assert_eq!(
1167            "Hello World",
1168            readlock2.get(&1).expect("Should be `Some` but was `None`")
1169        );
1170        assert_eq!(
1171            "Rustbreak",
1172            readlock1
1173                .get(&100)
1174                .expect("Should be `Some` but was `None`")
1175        );
1176        assert_eq!(
1177            "Rustbreak",
1178            readlock2
1179                .get(&100)
1180                .expect("Should be `Some` but was `None`")
1181        );
1182        assert_eq!(*readlock1, *readlock2);
1183    }
1184
1185    #[test]
1186    fn borrow_data_mut() {
1187        let db = TestMemDb::memory(test_data()).expect("Could not create database");
1188        let mut writelock = db.borrow_data_mut().expect("Rustbreak writelock error");
1189        writelock.insert(3, "Write to db".to_string());
1190        drop(writelock);
1191        assert_eq!(
1192            "Hello World",
1193            db.read(|d| d.get(&1).cloned())
1194                .expect("Rustbreak read error")
1195                .expect("Should be `Some` but was `None`")
1196        );
1197        assert_eq!(
1198            "Rustbreak",
1199            db.read(|d| d.get(&100).cloned())
1200                .expect("Rustbreak read error")
1201                .expect("Should be `Some` but was `None`")
1202        );
1203        assert_eq!(
1204            "Write to db",
1205            db.read(|d| d.get(&3).cloned())
1206                .expect("Rustbreak read error")
1207                .expect("Should be `Some` but was `None`")
1208        );
1209    }
1210
1211    #[test]
1212    fn get_data_mem() {
1213        let db = TestMemDb::memory(test_data()).expect("Could not create database");
1214        let data = db.get_data(false).expect("could not get data");
1215        assert_eq!(test_data(), data);
1216    }
1217
1218    #[test]
1219    fn get_data_load() {
1220        let db = TestMemDb::memory(test_data()).expect("Could not create database");
1221        db.save().expect("Rustbreak save error");
1222        db.write(|d| d.clear()).expect("Rustbreak write error");
1223        let data = db.get_data(true).expect("could not get data");
1224        assert_eq!(test_data(), data);
1225    }
1226
1227    #[test]
1228    fn put_data_mem() {
1229        let db = TestMemDb::memory(TestData::default()).expect("Could not create database");
1230        db.put_data(test_data(), false).expect("could not put data");
1231        assert_eq!(
1232            "Hello World",
1233            db.read(|d| d.get(&1).cloned())
1234                .expect("Rustbreak read error")
1235                .expect("Should be `Some` but was `None`")
1236        );
1237        assert_eq!(
1238            "Rustbreak",
1239            db.read(|d| d.get(&100).cloned())
1240                .expect("Rustbreak read error")
1241                .expect("Should be `Some` but was `None`")
1242        );
1243        let data = db.get_data(false).expect("could not get data");
1244        assert_eq!(test_data(), data);
1245    }
1246
1247    #[test]
1248    fn put_data_save() {
1249        let db = TestMemDb::memory(TestData::default()).expect("Could not create database");
1250        db.put_data(test_data(), true).expect("could not put data");
1251        db.load().expect("Rustbreak load error");
1252        assert_eq!(
1253            "Hello World",
1254            db.read(|d| d.get(&1).cloned())
1255                .expect("Rustbreak read error")
1256                .expect("Should be `Some` but was `None`")
1257        );
1258        assert_eq!(
1259            "Rustbreak",
1260            db.read(|d| d.get(&100).cloned())
1261                .expect("Rustbreak read error")
1262                .expect("Should be `Some` but was `None`")
1263        );
1264        let data = db.get_data(false).expect("could not get data");
1265        assert_eq!(test_data(), data);
1266    }
1267
1268    #[test]
1269    fn save_and_into_inner() {
1270        let db = TestMemDb::memory(test_data()).expect("Could not create database");
1271        db.save().expect("Rustbreak save error");
1272        let (data, mut backend, _) = db
1273            .into_inner()
1274            .expect("error calling `Database.into_inner`");
1275        assert_eq!(test_data(), data);
1276        let parsed: TestData =
1277            ron::de::from_reader(&backend.get_data().expect("could not get data from backend")[..])
1278                .expect("backend contains invalid RON");
1279        assert_eq!(test_data(), parsed);
1280    }
1281
1282    #[test]
1283    fn clone() {
1284        let db1 = TestMemDb::memory(test_data()).expect("Could not create database");
1285        let readlock1 = db1.borrow_data().expect("Rustbreak readlock error");
1286        let db2 = db1.try_clone().expect("Rustbreak clone error");
1287        let readlock2 = db2.borrow_data().expect("Rustbreak readlock error");
1288        assert_eq!(test_data(), *readlock1);
1289        assert_eq!(*readlock1, *readlock2);
1290    }
1291
1292    #[test]
1293    fn allow_databases_with_boxed_backend() {
1294        let db =
1295            MemoryDatabase::<Vec<u64>, crate::deser::Ron>::memory(vec![]).expect("To be created");
1296        let db: Database<_, Box<dyn Backend>, _> = db.with_backend(Box::new(MemoryBackend::new()));
1297        db.put_data(vec![1, 2, 3], true)
1298            .expect("Can save data in memory");
1299        assert_eq!(
1300            &[1, 2, 3],
1301            &db.get_data(true).expect("Can get data from memory")[..]
1302        );
1303    }
1304
1305    /// Since `save` only needs read-access to the data we should be able to
1306    /// save while holding a readlock.
1307    #[test]
1308    fn save_holding_readlock() {
1309        let db = TestMemDb::memory(test_data()).expect("Could not create database");
1310        let readlock = db.borrow_data().expect("Rustbreak readlock error");
1311        db.save().expect("Rustbreak save error");
1312        assert_eq!(test_data(), *readlock);
1313    }
1314
1315    /// Test that if the file already exists, the closure won't be called.
1316    #[test]
1317    #[cfg_attr(miri, ignore)]
1318    fn pathdb_from_path_or_else_existing_nocall() {
1319        let file = NamedTempFile::new().expect("could not create temporary file");
1320        let path = file.path().to_owned();
1321        let _ = TestDb::<PathBackend>::load_from_path_or_else(path, || {
1322            panic!("closure called while file existed")
1323        });
1324    }
1325
1326    /// Test that if the file already exists, the closure won't be called.
1327    #[test]
1328    #[cfg_attr(miri, ignore)]
1329    fn filedb_from_path_or_else_existing_nocall() {
1330        let file = NamedTempFile::new().expect("could not create temporary file");
1331        let path = file.path();
1332        let _ = TestDb::<FileBackend>::load_from_path_or_else(path, || {
1333            panic!("closure called while file existed")
1334        });
1335    }
1336
1337    /// Test that if the file already exists, `default` won't be called.
1338    #[test]
1339    #[cfg_attr(miri, ignore)]
1340    fn pathdb_from_path_or_default_existing_nocall() {
1341        let file = NamedTempFile::new().expect("could not create temporary file");
1342        let path = file.path().to_owned();
1343        let _ = Database::<PanicDefault, PathBackend, crate::deser::Ron>::load_from_path_or_default(
1344            path,
1345        );
1346    }
1347
1348    /// Test that if the file already exists, the closure won't be called.
1349    #[test]
1350    #[cfg_attr(miri, ignore)]
1351    fn filedb_from_path_or_default_existing_nocall() {
1352        let file = NamedTempFile::new().expect("could not create temporary file");
1353        let path = file.path();
1354        let _ = Database::<PanicDefault, FileBackend, crate::deser::Ron>::load_from_path_or_default(
1355            path,
1356        );
1357    }
1358
1359    #[test]
1360    #[cfg_attr(miri, ignore)]
1361    fn pathdb_from_path_or_new() {
1362        let dir = tempfile::tempdir().expect("could not create temporary directory");
1363        let mut file_path = dir.path().to_owned();
1364        file_path.push("rustbreak_path_db.db");
1365        let db = TestDb::<PathBackend>::load_from_path_or(file_path, test_data())
1366            .expect("could not load from path");
1367        db.load().expect("could not load");
1368        let readlock = db.borrow_data().expect("Rustbreak readlock error");
1369        assert_eq!(test_data(), *readlock);
1370        dir.close().expect("Error while deleting temp directory!");
1371    }
1372
1373    #[test]
1374    #[cfg_attr(miri, ignore)]
1375    fn pathdb_from_path_or_else_new() {
1376        let dir = tempfile::tempdir().expect("could not create temporary directory");
1377        let mut file_path = dir.path().to_owned();
1378        file_path.push("rustbreak_path_db.db");
1379        let db = TestDb::<PathBackend>::load_from_path_or_else(file_path, test_data)
1380            .expect("could not load from path");
1381        db.load().expect("could not load");
1382        let readlock = db.borrow_data().expect("Rustbreak readlock error");
1383        assert_eq!(test_data(), *readlock);
1384        dir.close().expect("Error while deleting temp directory!");
1385    }
1386
1387    #[test]
1388    #[cfg_attr(miri, ignore)]
1389    fn filedb_from_path_or_new() {
1390        let dir = tempfile::tempdir().expect("could not create temporary directory");
1391        let mut file_path = dir.path().to_owned();
1392        file_path.push("rustbreak_path_db.db");
1393        let db = TestDb::<FileBackend>::load_from_path_or(file_path, test_data())
1394            .expect("could not load from path");
1395        db.load().expect("could not load");
1396        let readlock = db.borrow_data().expect("Rustbreak readlock error");
1397        assert_eq!(test_data(), *readlock);
1398        dir.close().expect("Error while deleting temp directory!");
1399    }
1400
1401    #[test]
1402    #[cfg_attr(miri, ignore)]
1403    fn filedb_from_path_or_else_new() {
1404        let dir = tempfile::tempdir().expect("could not create temporary directory");
1405        let mut file_path = dir.path().to_owned();
1406        file_path.push("rustbreak_path_db.db");
1407        let db = TestDb::<FileBackend>::load_from_path_or_else(file_path, test_data)
1408            .expect("could not load from path");
1409        db.load().expect("could not load");
1410        let readlock = db.borrow_data().expect("Rustbreak readlock error");
1411        assert_eq!(test_data(), *readlock);
1412        dir.close().expect("Error while deleting temp directory!");
1413    }
1414
1415    #[test]
1416    #[cfg_attr(miri, ignore)]
1417    fn pathdb_from_path_new_fail() {
1418        let dir = tempfile::tempdir().expect("could not create temporary directory");
1419        let mut file_path = dir.path().to_owned();
1420        file_path.push("rustbreak_path_db.db");
1421        let err = TestDb::<PathBackend>::load_from_path(file_path)
1422            .expect_err("should fail with file not found");
1423        if let Error::Backend(BackendError::Io(io_err)) = &err {
1424            assert_eq!(std::io::ErrorKind::NotFound, io_err.kind());
1425        } else {
1426            panic!("Wrong error: {}", err)
1427        };
1428
1429        dir.close().expect("Error while deleting temp directory!");
1430    }
1431
1432    #[test]
1433    #[cfg_attr(miri, ignore)]
1434    fn filedb_from_path_new_fail() {
1435        let dir = tempfile::tempdir().expect("could not create temporary directory");
1436        let mut file_path = dir.path().to_owned();
1437        file_path.push("rustbreak_path_db.db");
1438        let err = TestDb::<FileBackend>::load_from_path(file_path)
1439            .expect_err("should fail with file not found");
1440        if let Error::Backend(BackendError::Io(io_err)) = &err {
1441            assert_eq!(std::io::ErrorKind::NotFound, io_err.kind());
1442        } else {
1443            panic!("Wrong error: {}", err)
1444        };
1445
1446        dir.close().expect("Error while deleting temp directory!");
1447    }
1448
1449    #[test]
1450    #[cfg_attr(miri, ignore)]
1451    fn pathdb_from_path_existing() {
1452        let file = NamedTempFile::new().expect("could not create temporary file");
1453        let path = file.path().to_owned();
1454        // initialise the file
1455        let db = TestDb::<PathBackend>::create_at_path(path.clone(), test_data())
1456            .expect("could not create db");
1457        db.save().expect("could not save db");
1458        drop(db);
1459        // test that loading now works
1460        let db = TestDb::<PathBackend>::load_from_path(path).expect("could not load");
1461        let readlock = db.borrow_data().expect("Rustbreak readlock error");
1462        assert_eq!(test_data(), *readlock);
1463    }
1464
1465    #[test]
1466    #[cfg_attr(miri, ignore)]
1467    fn filedb_from_path_existing() {
1468        let file = NamedTempFile::new().expect("could not create temporary file");
1469        let path = file.path();
1470        // initialise the file
1471        let db =
1472            TestDb::<FileBackend>::create_at_path(path, test_data()).expect("could not create db");
1473        db.save().expect("could not save db");
1474        drop(db);
1475        // test that loading now works
1476        let db = TestDb::<FileBackend>::load_from_path(path).expect("could not load");
1477        let readlock = db.borrow_data().expect("Rustbreak readlock error");
1478        assert_eq!(test_data(), *readlock);
1479    }
1480}