Struct rustbreak::Database [−][src]
pub struct Database<Data, Back, DeSer> { /* fields omitted */ }
The Central Database to RustBreak
It has 3 Type Generics:
- Data: Is the Data, you must specify this
- Back: The storage backend.
- DeSer: The Serializer/Deserializer or short DeSer. Check the
deser
module for other strategies.
Panics
If the backend or the de/serialization panics, the database is poisoned. This means that any
subsequent writes/reads will fail with an error::RustbreakErrorKind::PoisonError
.
You can only recover from this by re-creating the Database Object.
Methods
impl<Data, Back, DeSer> Database<Data, Back, DeSer> where
Data: Serialize + DeserializeOwned + Debug + Clone + Send,
Back: Backend + Debug,
DeSer: DeSerializer<Data> + Debug + Send + Sync + Clone,
[src]
impl<Data, Back, DeSer> Database<Data, Back, DeSer> where
Data: Serialize + DeserializeOwned + Debug + Clone + Send,
Back: Backend + Debug,
DeSer: DeSerializer<Data> + Debug + Send + Sync + Clone,
pub fn write<T, R>(&self, task: T) -> Result<R> where
T: FnOnce(&mut Data) -> R,
[src]
pub fn write<T, R>(&self, task: T) -> Result<R> where
T: FnOnce(&mut Data) -> R,
Write lock the database and get write access to the Data
container
This gives you an exclusive lock on the memory object. Trying to open the database in writing will block if it is currently being written to.
Panics
If you panic in the closure, the database is poisoned. This means that any
subsequent writes/reads will fail with an std::sync::PoisonError
.
You can only recover from this by re-creating the Database Object.
If you do not have full control over the code being written, and cannot incur the cost of
having a single operation panicking then use Database::write_safe
.
Examples
use rustbreak::{FileDatabase, deser::Ron}; #[derive(Debug, Serialize, Deserialize, Clone)] struct Data { level: u32, } let db = FileDatabase::<Data, Ron>::from_file(file, Data { level: 0 })?; db.write(|db| { db.level = 42; })?; // You can also return from a `.read()`. But don't forget that you cannot return references // into the structure let value = db.read(|db| db.level)?; assert_eq!(42, value);
pub fn write_safe<T>(&self, task: T) -> Result<()> where
T: FnOnce(&mut Data) + UnwindSafe,
[src]
pub fn write_safe<T>(&self, task: T) -> Result<()> where
T: FnOnce(&mut Data) + UnwindSafe,
Write lock the database and get write access to the Data
container in a safe way
This gives you an exclusive lock on the memory object. Trying to open the database in writing will block if it is currently being written to.
This differs to Database::write
in that a clone of the internal data is made, which is
then passed to the closure. Only if the closure doesn't panic is the internal model
updated.
Depending on the size of the database this can be very costly. This is a tradeoff to make for panic safety.
You should read the documentation about this: UnwindSafe
Panics
When the closure panics, it is caught and a error::RustbreakErrorKind::WritePanic
will be
returned.
Examples
use rustbreak::{ FileDatabase, deser::Ron, error::{ RustbreakError, RustbreakErrorKind, } }; #[derive(Debug, Serialize, Deserialize, Clone)] struct Data { level: u32, } let db = FileDatabase::<Data, Ron>::from_file(file, Data { level: 0 })?; let result = db.write_safe(|db| { db.level = 42; panic!("We panic inside the write code."); }).expect_err("This should have been caught"); match result.kind() { RustbreakErrorKind::WritePanic => { // We can now handle this, in this example we will just ignore it } e => { println!("{:#?}", e); // You should always have generic error catching here. // This future-proofs your code, and makes your code more robust. // In this example this is unreachable though, and to assert that we have this // macro here unreachable!(); } } // We read it back out again, it has not changed let value = db.read(|db| db.level)?; assert_eq!(0, value);
pub fn read<T, R>(&self, task: T) -> Result<R> where
T: FnOnce(&Data) -> R,
[src]
pub fn read<T, R>(&self, task: T) -> Result<R> where
T: FnOnce(&Data) -> R,
Read lock the database and get write access to the Data
container
This gives you a read-only lock on the database. You can have as many readers in parallel as you wish.
Errors
May return:
error::RustbreakErrorKind::Backend
Panics
If you panic in the closure, the database is poisoned. This means that any
subsequent writes/reads will fail with an error::RustbreakErrorKind::Poison
.
You can only recover from this by re-creating the Database Object.
pub fn borrow_data<'a>(&'a self) -> Result<RwLockReadGuard<'a, Data>>
[src]
pub fn borrow_data<'a>(&'a self) -> Result<RwLockReadGuard<'a, Data>>
Read lock the database and get access to the underlying struct
This gives you access to the underlying struct, allowing for simple read only operations on it.
Examples
use rustbreak::{FileDatabase, deser::Ron}; #[derive(Debug, Serialize, Deserialize, Clone)] struct Data { level: u32, } let db = FileDatabase::<Data, Ron>::from_file(file, Data { level: 0 })?; db.write(|db| { db.level = 42; })?; let data = db.borrow_data()?; assert_eq!(42, data.level);
pub fn borrow_data_mut<'a>(&'a self) -> Result<RwLockWriteGuard<'a, Data>>
[src]
pub fn borrow_data_mut<'a>(&'a self) -> Result<RwLockWriteGuard<'a, Data>>
Write lock the database and get access to the underlying struct
This gives you access to the underlying struct, allowing you to modify it.
Panics
If you panic while holding this reference, the database is poisoned. This means that any
subsequent writes/reads will fail with an std::sync::PoisonError
.
You can only recover from this by re-creating the Database Object.
If you do not have full control over the code being written, and cannot incur the cost of
having a single operation panicking then use Database::write_safe
.
Examples
use rustbreak::{FileDatabase, deser::Ron}; #[derive(Debug, Serialize, Deserialize, Clone)] struct Data { level: u32, } let db = FileDatabase::<Data, Ron>::from_file(file, Data { level: 0 })?; { let mut data = db.borrow_data_mut()?; data.level = 42; } let data = db.borrow_data()?; assert_eq!(42, data.level);
pub fn load(&self) -> Result<()>
[src]
pub fn load(&self) -> Result<()>
Load the Data from the backend
pub fn save(&self) -> Result<()>
[src]
pub fn save(&self) -> Result<()>
Flush the data structure to the backend
pub fn get_data(&self, load: bool) -> Result<Data>
[src]
pub fn get_data(&self, load: bool) -> Result<Data>
Get a clone of the data as it is in memory right now
To make sure you have the latest data, call this method with load
true
pub fn put_data(&self, new_data: Data, save: bool) -> Result<()>
[src]
pub fn put_data(&self, new_data: Data, save: bool) -> Result<()>
Puts the data as is into memory
To save the data afterwards, call with save
true.
pub fn from_parts(
data: Data,
backend: Back,
deser: DeSer
) -> Database<Data, Back, DeSer>
[src]
pub fn from_parts(
data: Data,
backend: Back,
deser: DeSer
) -> Database<Data, Back, DeSer>
Create a database from its constituents
pub fn into_inner(self) -> Result<(Data, Back, DeSer)>
[src]
pub fn into_inner(self) -> Result<(Data, Back, DeSer)>
Break a database into its individual parts
pub fn try_clone(&self) -> Result<MemoryDatabase<Data, DeSer>>
[src]
pub fn try_clone(&self) -> Result<MemoryDatabase<Data, DeSer>>
Tries to clone the Data in the Database.
This method returns a MemoryDatabase
which has an empty vector as a
backend initially. This means that the user is responsible for assigning a new backend
if an alternative is wanted.
Examples
use rustbreak::{FileDatabase, deser::Ron}; #[derive(Debug, Serialize, Deserialize, Clone)] struct Data { level: u32, } let db = FileDatabase::<Data, Ron>::from_file(file, Data { level: 0 })?; db.write(|db| { db.level = 42; })?; db.save()?; let other_db = db.try_clone()?; // You can also return from a `.read()`. But don't forget that you cannot return references // into the structure let value = other_db.read(|db| db.level)?; assert_eq!(42, value);
impl<Data, DeSer> Database<Data, FileBackend, DeSer> where
Data: Serialize + DeserializeOwned + Debug + Clone + Send,
DeSer: DeSerializer<Data> + Debug + Send + Sync + Clone,
[src]
impl<Data, DeSer> Database<Data, FileBackend, DeSer> where
Data: Serialize + DeserializeOwned + Debug + Clone + Send,
DeSer: DeSerializer<Data> + Debug + Send + Sync + Clone,
pub fn from_path<S>(path: S, data: Data) -> Result<FileDatabase<Data, DeSer>> where
S: AsRef<Path>,
[src]
pub fn from_path<S>(path: S, data: Data) -> Result<FileDatabase<Data, DeSer>> where
S: AsRef<Path>,
Create new FileDatabase from Path
pub fn from_file(file: File, data: Data) -> Result<FileDatabase<Data, DeSer>>
[src]
pub fn from_file(file: File, data: Data) -> Result<FileDatabase<Data, DeSer>>
Create new FileDatabase from a file
impl<Data, DeSer> Database<Data, MemoryBackend, DeSer> where
Data: Serialize + DeserializeOwned + Debug + Clone + Send,
DeSer: DeSerializer<Data> + Debug + Send + Sync + Clone,
[src]
impl<Data, DeSer> Database<Data, MemoryBackend, DeSer> where
Data: Serialize + DeserializeOwned + Debug + Clone + Send,
DeSer: DeSerializer<Data> + Debug + Send + Sync + Clone,
pub fn memory(data: Data) -> Result<MemoryDatabase<Data, DeSer>>
[src]
pub fn memory(data: Data) -> Result<MemoryDatabase<Data, DeSer>>
Create new FileDatabase from Path
impl<Data, DeSer> Database<Data, MmapStorage, DeSer> where
Data: Serialize + DeserializeOwned + Debug + Clone + Send,
DeSer: DeSerializer<Data> + Debug + Send + Sync + Clone,
[src]
impl<Data, DeSer> Database<Data, MmapStorage, DeSer> where
Data: Serialize + DeserializeOwned + Debug + Clone + Send,
DeSer: DeSerializer<Data> + Debug + Send + Sync + Clone,
pub fn mmap(data: Data) -> Result<MmapDatabase<Data, DeSer>>
[src]
pub fn mmap(data: Data) -> Result<MmapDatabase<Data, DeSer>>
Create new MmapDatabase.
pub fn mmap_with_size(
data: Data,
size: usize
) -> Result<MmapDatabase<Data, DeSer>>
[src]
pub fn mmap_with_size(
data: Data,
size: usize
) -> Result<MmapDatabase<Data, DeSer>>
Create new MmapDatabase with specified initial size.
impl<Data, Back, DeSer> Database<Data, Back, DeSer>
[src]
impl<Data, Back, DeSer> Database<Data, Back, DeSer>
pub fn with_deser<T>(self, deser: T) -> Database<Data, Back, T>
[src]
pub fn with_deser<T>(self, deser: T) -> Database<Data, Back, T>
Exchanges the DeSerialization strategy with the new one
impl<Data, Back, DeSer> Database<Data, Back, DeSer>
[src]
impl<Data, Back, DeSer> Database<Data, Back, DeSer>
pub fn with_backend<T>(self, backend: T) -> Database<Data, T, DeSer>
[src]
pub fn with_backend<T>(self, backend: T) -> Database<Data, T, DeSer>
Exchanges the Backend with the new one
The new backend does not necessarily have the latest data saved to it, so a .save
should
be called to make sure that it is saved.
impl<Data, Back, DeSer> Database<Data, Back, DeSer> where
Data: Serialize + DeserializeOwned + Debug + Clone + Send,
Back: Backend + Debug,
DeSer: DeSerializer<Data> + Debug + Send + Sync + Clone,
[src]
impl<Data, Back, DeSer> Database<Data, Back, DeSer> where
Data: Serialize + DeserializeOwned + Debug + Clone + Send,
Back: Backend + Debug,
DeSer: DeSerializer<Data> + Debug + Send + Sync + Clone,
pub fn convert_data<C, OutputData>(
self,
convert: C
) -> Result<Database<OutputData, Back, DeSer>> where
OutputData: Serialize + DeserializeOwned + Debug + Clone + Send,
C: FnOnce(Data) -> OutputData,
DeSer: DeSerializer<OutputData> + Debug + Send + Sync,
[src]
pub fn convert_data<C, OutputData>(
self,
convert: C
) -> Result<Database<OutputData, Back, DeSer>> where
OutputData: Serialize + DeserializeOwned + Debug + Clone + Send,
C: FnOnce(Data) -> OutputData,
DeSer: DeSerializer<OutputData> + Debug + Send + Sync,
Converts from one data type to another
This method is useful to migrate from one datatype to another