Struct Database

Source
pub struct Database<Data, Back, DeSer> { /* private fields */ }
Expand description

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§

Source§

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

Source

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 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);
Source

pub fn write_safe<T>(&self, task: T) -> Result<()>

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);
Source

pub fn read<T, R>(&self, task: T) -> Result<R>
where T: FnOnce(&Data) -> R,

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.

Source

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::{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);
Source

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 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);
Source

pub fn load(&self) -> Result<()>

Load the data from the backend.

Source

pub fn save(&self) -> Result<()>

Flush the data structure to the backend.

Source

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.

Source

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.

Source

pub fn from_parts(data: Data, backend: Back, deser: DeSer) -> Self

Create a database from its constituents.

Source

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

Break a database into its individual parts.

Source

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::{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);
Source§

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

Source

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

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

Source

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

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.

Source

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

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.

Source

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

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.

Source

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

Create new FileDatabase from a file.

Source§

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

Source

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

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.

Source§

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

Source

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

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

Source

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

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.

Source

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

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.

Source

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

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.

Source§

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

Source

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

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.

Source§

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

Source

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

Create new in-memory database.

Source§

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

Source

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

Create new MmapDatabase.

Source

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

Create new MmapDatabase with specified initial size.

Source§

impl<Data, Back, DeSer> Database<Data, Back, DeSer>

Source

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

Exchanges the DeSerialization strategy with the new one.

Source§

impl<Data, Back, DeSer> Database<Data, Back, DeSer>

Source

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.

Source§

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

Source

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,

Converts from one data type to another.

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

Trait Implementations§

Source§

impl<Data: Debug, Back: Debug, DeSer: Debug> Debug for Database<Data, Back, DeSer>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<Data, Back, DeSer> !Freeze for Database<Data, Back, DeSer>

§

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

§

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

§

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

§

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

§

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

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

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

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

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

Source§

fn vzip(self) -> V