Some documentation; wrapper functions moved into own module

This commit is contained in:
Cerber Ursi
2021-11-27 19:09:13 +07:00
parent 71f6a104cc
commit 30b9b84255
7 changed files with 198 additions and 23 deletions
+2
View File
@@ -1,3 +1,5 @@
//! Error returned by Corona serializer.
use serde::ser;
use thiserror::Error;
+54
View File
@@ -0,0 +1,54 @@
//! Convenience functions to be used with Corona.
use crate::ser::{SerResult, Corona};
use crate::error::CoronaError;
use serde::Serialize;
/// Write generated Rust code to the provided [`Write`][std::io::Write] implementation.
pub fn write(value: impl Serialize, target: impl std::io::Write) -> SerResult {
value.serialize(&mut Corona::new(target))
}
/// Writes generated Rust code to file.
///
/// This is probably the most common way to use `corona`. When Cargo runs your crate's build task,
/// it sets the `OUT_DIR` environment variable to the path to build target directory (see
/// [Cargo reference](https://doc.rust-lang.org/cargo/reference/environment-variables.html) for more).
/// So, you can use it in two steps:
/// 1. Generate the Rust code and write it to temporary file:
/// ```no_run
/// # let value = ();
/// let path: std::path::PathBuf = [
/// std::env::var("OUT_DIR").expect("No build target path set"),
/// "file_name.rs".into()
/// ].iter().collect();
/// corona::to_file(value, path).expect("Write failed");
/// ```
/// 2. [Include][include] the generated Rust code wherever it is needed:
/// ```ignore
/// let value = include!(concat!(env!(OUT_DIR), "/file_name.rs"));
/// ```
///
/// [include]: https://doc.rust-lang.org/stable/std/macro.include.html
pub fn to_file(value: impl Serialize, target: impl AsRef<std::path::Path>) -> SerResult {
value.serialize(&mut Corona::new(std::fs::File::create(target)?))
}
/// Convenience wrapper around [`to_file`].
///
/// This function finds out where the output directory is by looking at `OUT_DIR` environment variable
/// and creates the file with the provided name there.
pub fn to_out_dir(value: impl Serialize, file_name: impl AsRef<str>) -> SerResult {
let path: std::path::PathBuf = [
std::env::var("OUT_DIR").expect("OUT_DIR not set, check if you're running this from the build script"),
file_name.as_ref().into()
].iter().collect();
value.serialize(&mut Corona::new(std::fs::File::create(path)?))
}
/// Obtain string with generated Rust code.
pub fn to_string(value: impl Serialize) -> Result<String, CoronaError> {
let mut out = Vec::new();
value.serialize(&mut Corona::new(&mut out))?;
Ok(String::from_utf8(out)?)
}
+36 -16
View File
@@ -1,19 +1,39 @@
use crate::ser::SerResult;
use serde::Serialize;
//! Serde serializer generating Rust code.
//!
//! This crate can be used to "embed" something into code, having only some serialized
//! data, like JSON or YAML. This way, you'll mostly escape runtime cost of deserialization,
//! nearly as if you've written the same data directly in code by hand.
//! Of course, in most cases this cost is already negligible, but for crates which use
//! large blobs of data this crate can come in handy, improving startup times.
//!
//! ## Usage
//! In general, to embed some code into crate, you have to use the build script
//! and [`include!`][include] macro. Inside the build script, you'll generate
//! some code with one of the [functions][funcs] provided by `corona`,
//! and then include the generated file, like this:
//! ```ignore
//! let value = include!(concat!(env!(OUT_DIR), "/file_name.rs"));
//! ```
//!
//! ## Limitations
//! There are some cases when `corona` will be unable to generate valid code. Namely:
//! 1. Since Serde doesn't provide us the full path to the type in question (and in most cases it's simply unable to),
//! all the structs and enums used during value construction must be in scope.
//! As a consequence, all of them must have distinct names - otherwise, there will be name clashes.
//! 2. This serializer is intended for use with derived implementation. It may return bogus results
//! when used with customized `Serialize`.
//! 3. It is impossible to consume code for the type with private fields outside from the module it is defined in.
//! In fact, to be able to use this type with `corona`, you'll have to distribute two copies of your crate,
//! one of which would only export the definition with derived `Serialize` to be used by serializer
//! during the build-time of the second copy. (Isn't this a bit too complex?)
//! 4. It is impossible to use empty tuple structs (i.e. `Empty()`).
//! From the Serde's point of view, they are indistinguishable from unit structs (i.e. `Unit`),
//! but the same Rust syntax can't be used for both, and, since ordinary unit structs are much
//! more common, it was decided to correctly handle them.
//!
//! [include]: https://doc.rust-lang.org/stable/std/macro.include.html
pub mod error;
pub mod ser;
pub fn write(value: impl Serialize, target: impl std::io::Write) -> SerResult {
value.serialize(&mut ser::Corona::new(target))
}
pub fn to_file(value: impl Serialize, target: impl AsRef<std::path::Path>) -> SerResult {
value.serialize(&mut ser::Corona::new(std::fs::File::create(target)?))
}
pub fn to_string(value: impl Serialize) -> Result<String, error::CoronaError> {
let mut out = Vec::new();
value.serialize(&mut ser::Corona::new(&mut out))?;
Ok(String::from_utf8(out)?)
}
pub mod funcs;
pub use funcs::{to_file, to_out_dir, to_string, write};
+6
View File
@@ -1,9 +1,15 @@
//! Implementation of the Corona serializer.
use crate::error::CoronaError;
use serde::ser;
use std::io::Write;
pub(crate) type SerResult = Result<(), CoronaError>;
/// Main serializer implementation.
///
/// Users are usually encouraged to use [`to_out_dir`][crate::funcs::to_out_dir] or, in special cases,
/// [`to_file`][crate::funcs::to_file], [`write`][crate::funcs::write] or [`to_string`][crate::funcs::to_string].
pub struct Corona<W: Write> {
writer: W,
inside: bool,