# binroots   [![Version]][crate] [![Downloads]][crate] [![Docs]][docs.rs] [![License]][apache] [![Liberapay]][payurl]
[Version]: https://img.shields.io/crates/v/binroots
[crate]: https://crates.io/crates/binroots
[Downloads]: https://img.shields.io/crates/d/binroots
[Docs]: https://img.shields.io/badge/docs.rs-d2991d?&logo=docs.rs
[docs.rs]: https://docs.rs/binroots
[License]: https://img.shields.io/crates/l/binroots
[apache]: https://www.apache.org/licenses/LICENSE-2.0
[Liberapay]: https://img.shields.io/liberapay/patrons/reebcw
[payurl]: https://liberapay.com/reebcw/
Binroots is a (cross-platform!) crate that provides a simple and efficient way to save Rust data structures to disk. It allows you to save each field of a struct or enum variant as a separate file, making it easy to store reactive data, allowing end-users and hackers to watch individual files for changes and automate command-line tools for your app.
## Project Status
Writing the initial commit of this crate took me about 7 hours. There are no unit tests yet, and it requires nightly Rust. If you care about your code, please do not use this in production (yet!). I can't guarantee that your files will remain safe. If you're interested in the development of binroots, check out the [planned features](#planned-features) and follow my [Twitter](https://twitter.com/carterisonline/) (no promises of whatever else you'll see on there)
## Installation
Add it to your project using `cargo add binroots`
## Setting up a struct
To save a struct, annotate it with `#[binroots_struct]`:
```rust
use binroots::binroots_struct;
#[binroots_struct]
struct Status {
connections: usize,
is_online: bool,
activity: Activity,
}
```
`#[binroots_struct]` Automatically derives `Debug`, `Default` and `serde::Serialize`. It wraps each field in `BinrootsField`, which allows saving of individual fields without having to serialize the entire struct.
## Setting up an enum
In the struct above, we use an enum named `Activity`. Here's how it can be defined:
```rust
use binroots::binroots_enum;
#[binroots_enum]
enum Activity {
None, // <- Automatically chosen as the default value
Playing(String),
}
```
`#[binroots_enum]` Also automatically derives `Debug`, `Default` and `serde::Serialize`. Wrapper types aren't needed.
In order to satisfy `Default`, it also picks the first variant named either `None`, `Nothing`, `Default`, or `Empty`. **If you wish to use a different default type**, you may annotate the enum with `#[binroots_enum(manual)]`, and mark a unit variant with `#[default]`.
## Saving data
In this example, we initialize `status` using `Status::default` (generated by `#[binroots_struct]`)
When saving a struct annotated with `#[binroots_struct]`, it will save to a subfolder named after the struct in `kebab-case`. In this example, on Unix, it saves to `/tmp/<crate name>/status`, and `%LOCALAPPDATA\<crate name>\cache\status` on Windows.
```rust
use binroots::save::{RootType, SaveError};
fn main() -> Result<(), SaveError> {
let mut status = Status::default();
*status.is_online = true;
status.save()?; // <- Saves the entire struct to the disk
*status.activity = Activity::Playing("video gamb".into());
status.activity.save(Status::ROOT_FOLDER, RootType::InMemory)?; // <- Only saves status.activity to the disk
Ok(())
}
```
After saving, the `status` folder should look like this:
```bash
/tmp/binroots/status
├── activity => "Playing"
├── activity.value => "video gamb"
├── connections => "0"
└── is_online => "true"
```
<h2 id="planned-features"> Planned Features </h2>
I'm most likely going to add these in order. If it's not on this list, it's either implemented or unconsidered.
- Setting `hFile = INVALID_HANDLE_VALUE` on Windows when using in-memory storage. Currently can only save to persistent storage on Windows.
- Unit tests lol
- Union support
- Unify `#[binroots_*]` macros into a single `#[binroots]` macro
- `Self::enable_autosave(self) -> Self` for reactive data
- `Deserialize`
- `Send + Sync`
- `BinrootsField::watch(Fn(T))` for socket-ish behavior
- `Self::enable_rx(self) -> Self` for true two-way reactive data
- Async support?
- Dual free/commercial license