Implementations in accordance with the v0 specification.
Includes an API for manipulating the FEF format. This implements an unstable version of the FEF specification, so the stability of this API is not guaranteed.
# Overview
Reading and writing FEF files (or any part of them) is done using the [`read`] and [`mod@write`] modules respectively. The main focus of the FEF format (and by extension this library) is embedding FEF structures into other files, so functions for reading and writing FEF structures from/to files are provided. If you choose to read whole files at once, members of the [`mod@file`] module will be used. If you want to read only a part of a file, members of [`expr`], [`metadata`], and [`config`] modules will be used. If you just need definitions of identifiers, you can use the [`tokens`] module. Common traits are in the [`traits`] module, but other traits are in their respective `traits` submodules of the modules they are related to. Modules also contain their own `error` submodules, which contain error types specific to that module (see [Stability of Error Handling](#very-unstable-parts) for more information on errors).
# Examples
Here you can find some simple examples of using the library. Other examples can be found in the documentation of the respective modules.
## Expression tree reading
Let's consider a situation where we should read one expression from a byte stream (eg. a partially read file), return the expression while also detecting when to stop reading.
```rust
# fn main() -> Result<(), Box<dyn std::error::Error>> {
# let file: Vec<u8> = vec![0x10, 0x38, 0x02, 0x38, 0x01, 0x00];
# use std::io::Read;
use fef::v0::read::read_expression_into_tree;
use fef::v0::config::DEFAULT_CONFIG;
use fef::v0::expr::Expr;
use fef::v0::expr::ExprTree;
let mut reader = // ... getting the reader here
# file.as_slice();
let expr: Expr<ExprTree> = read_expression_into_tree(&mut reader, &DEFAULT_CONFIG)?.into(); // Read the expression
# assert!(matches!(expr, Expr::Addition(_)));
# let mut next: [u8; 1] = [0];
# reader.read_exact(&mut next)?;
# assert_eq!(next[0], 0x00);
# assert!(reader.is_empty());
# Ok(())
# }
```
# Stability
This is a v0 implementation of a v0 specification. This means that breaking changes might be introduced without warning.
In the current state however, it is expected that only "small" breaking changes will be introduced for the most part (see [exceptions](#very-unstable-parts) bellow). A breaking change is considered "small" if it breaks some supported usage of the library, but migration to the newer version will be relatively easy (e.g. changing a function name, parameter order, location in the module hierarchy, etc.). If you need to avoid breaking code on updates, you should pin the version of this library in your `Cargo.toml` file.
The specification is not expected to have many significant changes.
## Very Unstable Parts
There are a few parts of the API, that will change significantly in the future. This concerns mainly the machine readable error structure and handling. All errors currently implement the [`Error`](std::error::Error) trait and that is planned to remain the same. However, the error types and their structure will change significantly in the future.