bstorage is a lightweight library for storing data in binary form.
bstorage creates a file storage and allows writing/reading any data into it. The only requirement for the data is the implementation of serde::Deserialize, serde::Serialize.
use Storage;
use ;
use temp_dir;
use Uuid;
// Set storage path
let storage_path = temp_dir.join;
// Create storage or open existed one
let mut storage = create.expect;
let my_record = MyRecord ;
// Save record into storage
storage
.set
.expect;
// Read record from storage
let recovered: MyRecord = storage
.get
.expect
.expect;
assert_eq!
When to use and when not to
bstorage is a good choice for:
- saving application settings
- saving temporary data
- other uses
bstorage is not the best choice if:
- if you are looking for something like a lightweight database; bstorage is not a database
- if you need fast search within the array of saved data without copying data (again, bstorage is not a database)
- direct access to the data by the user is implied (e.g., toml, json, and other text formats)
- large amounts of data (1 GB or more) need to be saved
How it works
bstorage uses the bincode crate for serializing and deserializing data. Each record is saved as a separate file within a directory specified when creating/opening the storage. Therefore, the number of records will be equivalent to the number of files in the storage.
The strategy of storing each record in a separate file is driven by the need to ensure maximum performance when writing data to the storage. If all data (all records) were stored in a single file, the seemingly simple task of "updating one record" would not be straightforward. On the file system level, data is stored in blocks, and "cleanly" replacing part of a file's content would require intervening in the file system's operations, which in most cases is an unnecessary complication. The simplest, most reliable, and effective method would be to overwrite the entire file. However, this approach leads to storage size issues. With large storage sizes, overwriting the entire storage becomes very costly.
This is why bstorage creates a separate file for each record, allowing for the fastest possible updating of each record without the need to overwrite the entire storage.
How to transfer the storage
Transferring the storage can be done by copying the entire contents of the storage directory. However, in some situations, this can be quite inconvenient, especially if the data needs to be transferred over a network.
bstorage includes a Bundle trait that allows "packing" the entire storage into a single file, and then "unpacking" it back into its "normal" state.
use ;
use ;
use ;
use Uuid;
// Set storage path
let storage_path = temp_dir.join;
// Create storage or open existed one
let mut storage = create.expect;
let my_record = MyRecord ;
// Save record into storage
storage
.set
.expect;
// Pack storage into file
let packed = temp_dir.join;
storage.pack.expect;
// Remove origin storage
remove_dir_all.expect;
drop;
// Unpack storage
let storage =
unpack.expect;
// Remove bundle file
remove_file.expect;
// Read record from unpacked storage
let recovered: MyRecord = storage
.get
.expect
.expect;
assert_eq!
Searching Records in Storage
To implement searching for records in the storage, you should use the Search trait, which provides access to two methods: find and filter.
use ;
use ;
use ;
use Uuid;
let mut storage = create.unwrap;
let a = ;
let b = ;
let mut i = 0;
for a in a.iter
for b in b.iter
let = storage.find.unwrap.expect;
assert_eq!;
let = storage.find.unwrap.expect;
assert_eq!;
assert!;
storage.clear.unwrap;
remove_dir_all.unwrap;
And example of filtering
use ;
use ;
use ;
use Uuid;
let mut storage = create.unwrap;
let a = ;
let b = ;
let mut i = 0;
for a in a.iter
for b in b.iter
let found = storage.filter.unwrap;
assert_eq!;
for in found.into_iter
let found = storage.filter.unwrap;
assert_eq!;
for in found.into_iter
assert_eq!;
storage.clear.unwrap;
remove_dir_all.unwrap;
Contributing
Contributions are welcome! Please read the short Contributing Guide.