SingleFile

This library is designed to be a dead-simple way of accessing and manipulating files, treating those files as if they represent some Rust value.

Usage

singlefile provides a generic Container type, along with type alias variants for different use cases. Container is named so to indicate that it contains and manages a file and a value.

```rust // A readable, writable container use singlefile::container::ContainerWritable;

[derive(Serialize, Deserialize, Default)]

struct MyData { magic_number: i32 }

// Attempts to open 'mydata.json', creating it from default if it does not exist, // expecting data that the Json format can decode into MyData. let mut mycontainer = ContainerWritable::::createordefault("mydata.json", Json)?; // For regular Containers, Deref and DerefMut can be used to access the contained type println!("magicnumber: {}", mycontainer.magicnumber); // 0 (as long as the file didn't exist before) mycontainer.magicnumber += 1; // Write the new state of MyData to disk my_container.commit()?; ```

We'd then expect the resulting my_data.json to look like:

json { "magic_number": 1 }

Shared and async containers

singlefile also provides a ContainerShared type that can be used from multiple threads, as well as a ContainerAsync that can be used from multiple threads and spawns its operations asynchronously. Currently, ContainerAsync can only be guaranteed to work alongside Tokio.

The shared container types can be enabled with the shared cargo feature. The async container types can be enabled with the shared-async cargo feature.

```rust // A readable, writable container with multiple-ownership use singlefile::container_shared::ContainerSharedWritable;

// ContainerShared types may be cloned cheaply, they behave like Arcs let mycontainer = ContainerSharedWritable::::createordefault("mydata.json", Json)?;

// Get access to the contained MyData, increment it, and commit changes to disk std::thread::spawn(move || { mycontainer.operatemutcommit(|mydata| { mydata.magicnumber += 1; Ok::<(), Infallible>(()) }); }); ```

File formats

singlefile is serialization framework-agnostic, so you will need a FileFormat adapter before you are able to read and write a given file format to disk.

Here is how you'd write a Json adapter for the above examples, using serde.

```rust use serde::ser::Serialize; use serde::de::DeserializeOwned; use singlefile::FileFormat; use std::io::{Read, Write};

struct Json;

impl FileFormat for Json where T: Serialize + DeserializeOwned { type FormatError = serde_json::Error;

fn towriter(&self, writer: W, value: &T) -> Result<(), Self::FormatError> { serdejson::towriterpretty(writer, value).map_err(From::from) }

fn fromreader(&self, reader: R) -> Result { serdejson::fromreader(reader).maperr(From::from) } } ```