4 releases
0.2.1 | Oct 2, 2021 |
---|---|
0.2.0 | Sep 19, 2021 |
0.1.1 | Jul 26, 2021 |
0.1.0 | Jul 23, 2021 |
#1388 in Parser implementations
180KB
4K
SLoC
Flexpiler
This crate aims to provide deserialisation (and eventually serialisation) in such a way that the user can customise the format in which rust objects are written and read on-the-fly. The idea is to reduce the load on a private developer who wants to jump-start their own project and not bother too much about how their data is stored.
Currently this crate is in its early stages and only supports deserialisation of a reduced form of rust structs and enums with a format that mirrors how structs and enums are initialised in rust itself.
How to use
The project uses its sister crate flexpiler_derive
to provide a #[derive]
macro. This macro generates code such that the struct / enum being derived gains an impl of flexpiler::Deserialize
. From thereon you can call YourType::deserialize(reader_mut_ref)
to deserialize the type from a string or file reader.
extern crate flexpiler;
#[derive(flexpiler::Deserialize)]
struct MyPoint {
x: i32,
y: i32,
}
#[test]
fn basic() {
// Trait that implements deserialize<...>(...)
use flexpiler::Deserialize;
// namespace of common flexpiler reader implementations
use flexpiler::common::reader;
// Provide data via reading a string
// You may at this point provide a file handle or similar instead
let mut reader = reader::String::from(
"MyPoint{x:5,y:7}"
);
// Try and deserialize our object, modifying the reader in the process
let parse_result = MyPoint::deserialize(&mut reader);
// flexpiler deserialization ends in a std::result::Result
let my_point = match parse_result {
Ok(value) => value,
Err(error) => {
assert!(false, "parade() test ended in a failed deserialization:\n{}", error);
return;
}
};
// Check if our deserialized object contains the correct values for its fields
assert_eq!(my_point.x, 5);
assert_eq!(my_point.y, 7);
}
Current limitations
Updated last: version 0.2.0
The project does not support as many standard types as I'd like. In particular HashMap<KeyType, DataType>
and various primitive types are on the menu to be implemented by me for now.
Flexpiler currently uses a custom flexpiler::reader::Trait
implementation for its parsing, and expects the user to convert their filereader or stringreader or other types of readers into a type that implements it. The project should instead contain various common implementations and possibly support implicit conversion from common practice types such as BufReader
.
rust unions are not supported as of now.
The project cannot handle generics as of yet.
Plans for the future
Being an alpha crate, the API of this project is subject to change at each "minor" increment (x.y.z => x.y+1.z). However for now the desired API to be used from outside follows the upcoming non well defined vision:
use flexpiler::{Deserialize}
struct CakeFormat {
// [ some error handling functionality of an unspecified format ]
}
#[derive(flexpiler::Deserialize)]
#[flexpiler_format = CakeFormat]
#[flexpiler_format_style = "{[glazing]}\n{[cream]}\n{[flour_in_grams]}"]
struct MyCustomizedType {
glazing: std::string,
cream: MyCreamType,
flour_in_grams:i32,
}
[#test]
fn test_flexpiler() {
use flexpiler::Deserialize;
use flexpiler::common::reader;
let mut reader = reader::String::from(
"{\"Strawberry\"}\n{MyCreamType::Vanilla}\n{525}"
);
let parse_result = MyCustomizedType::deserialize(&mut reader);
let my_customized_type = match parse_result {
Ok(value) => value,
Err(error) => {
assert!(false, "test_flexpiler() test ended in a failed deserialization:\n{}", error);
return;
}
};
assert_eq!(my_customized_type.glazing.as_str(), "Strawberry");
assert_eq!(my_customized_type.cream, MyCreamType::Vanilla);
assert_eq!(my_customized_type.flour_in_grams, 525);
}
Notice that the project cannot do this yet. But this is the kind of thing we are aiming for in the future.
How it works
In essence, the derive macro featured creates an intermediate struct holding your data until final construction of the object. It then writes the entire deserialize
function including parsing and error forwarding from scratch assuming every sub-type has its own Deserialize
implementation.
Deserialize
is already implemented in flexpiler::common::deserializer
for various common types such as i32, std::string. However currently for some standard classes you would need to provide a flexpiler::Deserialization
implementation.
Dependencies
~1.5MB
~37K SLoC