[][src]Struct rustbreak::Database

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::RustbreakError::Poison. You can only recover from this by re-creating the Database Object.

Implementations

impl<Data, Back, DeSer> Database<Data, Back, DeSer> where
    Data: Serialize + DeserializeOwned + Clone + Send,
    Back: Backend,
    DeSer: DeSerializer<Data> + Send + Sync + Clone
[src]

pub fn write<T, R>(&self, task: T) -> Result<R> where
    T: FnOnce(&mut Data) -> R, 
[src]

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 error::RustbreakError::Poison. 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::{deser::Ron, FileDatabase};

#[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]

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::RustbreakError::WritePanic will be returned.

Examples

use rustbreak::{
    deser::Ron,
    error::RustbreakError,
    FileDatabase,
};

#[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 {
    RustbreakError::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]

Read lock the database and get read 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:

Panics

If you panic in the closure, the database is poisoned. This means that any subsequent writes/reads will fail with an error::RustbreakError::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]

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::{deser::Ron, FileDatabase};

#[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]

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 error::RustbreakError::Poison. 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::{deser::Ron, FileDatabase};

#[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]

Load the data from the backend.

pub fn save(&self) -> Result<()>[src]

Flush the data structure to the backend.

pub fn get_data(&self, load: bool) -> Result<Data>[src]

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]

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) -> Self[src]

Create a database from its constituents.

pub fn into_inner(self) -> Result<(Data, Back, DeSer)>[src]

Break a database into its individual parts.

pub fn try_clone(&self) -> Result<MemoryDatabase<Data, DeSer>>[src]

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::{deser::Ron, FileDatabase};

#[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 + Clone + Send,
    DeSer: DeSerializer<Data> + Send + Sync + Clone
[src]

pub fn load_from_path<S>(path: S) -> Result<Self> where
    S: AsRef<Path>, 
[src]

Create new FileDatabase from the file at Path, and load the contents.

pub fn load_from_path_or<S>(path: S, data: Data) -> Result<Self> where
    S: AsRef<Path>, 
[src]

Load FileDatabase at path or initialise with data.

Create new FileDatabase from the file at Path, and load the contents. If the file does not exist, initialise with data.

pub fn load_from_path_or_else<S, C>(path: S, closure: C) -> Result<Self> where
    S: AsRef<Path>,
    C: FnOnce() -> Data, 
[src]

Load FileDatabase at path or initialise with closure.

Create new FileDatabase from the file at Path, and load the contents. If the file does not exist, closure is called and the database is initialised with it's return value.

pub fn create_at_path<S>(path: S, data: Data) -> Result<Self> where
    S: AsRef<Path>, 
[src]

Create FileDatabase at path. Initialise with data if the file doesn't exist.

Create new FileDatabase from the file at Path. Contents are not loaded. If the file does not exist, it is initialised with data. Frontend is always initialised with data.

pub fn from_file(file: File, data: Data) -> Result<Self>[src]

Create new FileDatabase from a file.

impl<Data, DeSer> Database<Data, FileBackend, DeSer> where
    Data: Serialize + DeserializeOwned + Clone + Send + Default,
    DeSer: DeSerializer<Data> + Send + Sync + Clone
[src]

pub fn load_from_path_or_default<S>(path: S) -> Result<Self> where
    S: AsRef<Path>, 
[src]

Load FileDatabase at path or initialise with Data::default().

Create new FileDatabase from the file at Path, and load the contents. If the file does not exist, initialise with Data::default.

impl<Data, DeSer> Database<Data, PathBackend, DeSer> where
    Data: Serialize + DeserializeOwned + Clone + Send,
    DeSer: DeSerializer<Data> + Send + Sync + Clone
[src]

pub fn load_from_path(path: PathBuf) -> Result<Self>[src]

Create new PathDatabase from the file at Path, and load the contents.

pub fn load_from_path_or(path: PathBuf, data: Data) -> Result<Self>[src]

Load PathDatabase at path or initialise with data.

Create new PathDatabase from the file at Path, and load the contents. If the file does not exist, initialise with data.

pub fn load_from_path_or_else<C>(path: PathBuf, closure: C) -> Result<Self> where
    C: FnOnce() -> Data, 
[src]

Load PathDatabase at path or initialise with closure.

Create new PathDatabase from the file at Path, and load the contents. If the file does not exist, closure is called and the database is initialised with it's return value.

pub fn create_at_path(path: PathBuf, data: Data) -> Result<Self>[src]

Create PathDatabase at path. Initialise with data if the file doesn't exist.

Create new PathDatabase from the file at Path. Contents are not loaded. If the file does not exist, it is initialised with data. Frontend is always initialised with data.

impl<Data, DeSer> Database<Data, PathBackend, DeSer> where
    Data: Serialize + DeserializeOwned + Clone + Send + Default,
    DeSer: DeSerializer<Data> + Send + Sync + Clone
[src]

pub fn load_from_path_or_default(path: PathBuf) -> Result<Self>[src]

Load PathDatabase at path or initialise with Data::default().

Create new PathDatabase from the file at Path, and load the contents. If the file does not exist, initialise with Data::default.

impl<Data, DeSer> Database<Data, MemoryBackend, DeSer> where
    Data: Serialize + DeserializeOwned + Clone + Send,
    DeSer: DeSerializer<Data> + Send + Sync + Clone
[src]

pub fn memory(data: Data) -> Result<Self>[src]

Create new in-memory database.

impl<Data, DeSer> Database<Data, MmapStorage, DeSer> where
    Data: Serialize + DeserializeOwned + Clone + Send,
    DeSer: DeSerializer<Data> + Send + Sync + Clone
[src]

pub fn mmap(data: Data) -> Result<Self>[src]

Create new MmapDatabase.

pub fn mmap_with_size(data: Data, size: usize) -> Result<Self>[src]

Create new MmapDatabase with specified initial size.

impl<Data, Back, DeSer> Database<Data, Back, DeSer>[src]

pub fn with_deser<T>(self, deser: T) -> Database<Data, Back, T>[src]

Exchanges the DeSerialization strategy with the new one.

impl<Data, Back, DeSer> Database<Data, Back, DeSer>[src]

pub fn with_backend<T>(self, backend: T) -> Database<Data, T, DeSer>[src]

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 + Clone + Send,
    Back: Backend,
    DeSer: DeSerializer<Data> + Send + Sync + Clone
[src]

pub fn convert_data<C, OutputData>(
    self,
    convert: C
) -> Result<Database<OutputData, Back, DeSer>> where
    OutputData: Serialize + DeserializeOwned + Clone + Send,
    C: FnOnce(Data) -> OutputData,
    DeSer: DeSerializer<OutputData> + Send + Sync
[src]

Converts from one data type to another.

This method is useful to migrate from one datatype to another.

Trait Implementations

impl<Data: Debug, Back: Debug, DeSer: Debug> Debug for Database<Data, Back, DeSer>[src]

Auto Trait Implementations

impl<Data, Back, DeSer> RefUnwindSafe for Database<Data, Back, DeSer> where
    DeSer: RefUnwindSafe

impl<Data, Back, DeSer> Send for Database<Data, Back, DeSer> where
    Back: Send,
    Data: Send,
    DeSer: Send

impl<Data, Back, DeSer> Sync for Database<Data, Back, DeSer> where
    Back: Send,
    Data: Send + Sync,
    DeSer: Sync

impl<Data, Back, DeSer> Unpin for Database<Data, Back, DeSer> where
    Back: Unpin,
    Data: Unpin,
    DeSer: Unpin

impl<Data, Back, DeSer> UnwindSafe for Database<Data, Back, DeSer> where
    DeSer: UnwindSafe

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

impl<V, T> VZip<V> for T where
    V: MultiLane<T>,