Struct daybreak::Database

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

The Central Database to Daybreak.

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

Implementations

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

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

Examples
use daybreak::{
    deser::Ron,
    error::Error,
    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 {
    Error::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);

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

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

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

Load the data from the backend.

Flush the data structure to the backend.

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.

Puts the data as is into memory.

To save the data afterwards, call with save true.

Create a database from its constituents.

Break a database into its individual parts.

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

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

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.

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.

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.

Create new FileDatabase from a file.

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.

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

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.

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.

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.

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.

Create new in-memory database.

Create new MmapDatabase.

Create new MmapDatabase with specified initial size.

Exchanges the DeSerialization strategy with the new one.

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.

Converts from one data type to another.

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

Trait Implementations

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.