A little more documentation for preserves-schema
This commit is contained in:
parent
f009920dd7
commit
8db860648b
|
@ -1,4 +1,38 @@
|
|||
//! Implementation of the Schema-to-Rust compiler.
|
||||
//! Implementation of the Schema-to-Rust compiler; this is the core of the
|
||||
//! [preserves-schema-rs][] program.
|
||||
//!
|
||||
//! See the [documentation for preserves-schema-rs][preserves-schema-rs] for examples of how to
|
||||
//! use the compiler programmatically from a `build.rs` script, but very briefly, use
|
||||
//! [preserves-schemac](https://preserves.dev/doc/preserves-schemac.html) to generate a
|
||||
//! metaschema instance `*.prb` file, and then put something like this in `build.rs`:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! use preserves_schema::compiler::*;
|
||||
//!
|
||||
//! const PATH_TO_PRB_FILE: &'static str = "your-metaschema-instance-file.prb";
|
||||
//!
|
||||
//! fn main() -> Result<(), std::io::Error> {
|
||||
//! let buildroot = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
|
||||
//!
|
||||
//! let mut gen_dir = buildroot.clone();
|
||||
//! gen_dir.push("src/schemas");
|
||||
//! let mut c = CompilerConfig::new(gen_dir, "crate::schemas".to_owned());
|
||||
//!
|
||||
//! let inputs = expand_inputs(&vec![PATH_TO_PRB_FILE.to_owned()])?;
|
||||
//! c.load_schemas_and_bundles(&inputs)?;
|
||||
//! compile(&c)
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! plus something like this in your `lib.rs` or main program:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! pub mod schemas {
|
||||
//! include!(concat!(env!("OUT_DIR"), "/src/schemas/mod.rs"));
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [preserves-schema-rs]: https://preserves.dev/doc/preserves-schema-rs.html
|
||||
|
||||
pub mod context;
|
||||
pub mod cycles;
|
||||
|
@ -31,11 +65,18 @@ use std::io::Read;
|
|||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Names a Schema module within a (collection of) Schema bundle(s).
|
||||
pub type ModulePath = Vec<String>;
|
||||
|
||||
/// Implement this trait to extend the compiler with custom code generation support. The main
|
||||
/// code generators are also implemented as plugins.
|
||||
///
|
||||
/// For an example of its use outside the core compiler, see [`build.rs` for the `syndicate-rs` project](https://git.syndicate-lang.org/syndicate-lang/syndicate-rs/src/commit/60e6c6badfcbcbccc902994f4f32db6048f60d1f/syndicate/build.rs).
|
||||
pub trait Plugin: std::fmt::Debug {
|
||||
/// Use `_module_ctxt` to emit code at a per-module level.
|
||||
fn generate_module(&self, _module_ctxt: &mut ModuleContext) {}
|
||||
|
||||
/// Use `module_ctxt` to emit code at a per-Schema-[Definition] level.
|
||||
fn generate_definition(
|
||||
&self,
|
||||
module_ctxt: &mut ModuleContext,
|
||||
|
@ -112,17 +153,30 @@ impl ExternalModule {
|
|||
}
|
||||
}
|
||||
|
||||
/// Main entry point to the compiler.
|
||||
#[derive(Debug)]
|
||||
pub struct CompilerConfig {
|
||||
/// All known Schema modules, indexed by [ModulePath] and annotated with a [Purpose].
|
||||
pub bundle: Map<ModulePath, (Schema, Purpose)>,
|
||||
/// Where output Rust code files will be placed.
|
||||
pub output_dir: PathBuf,
|
||||
/// Fully-qualified Rust module prefix to use for each generated module.
|
||||
pub fully_qualified_module_prefix: String,
|
||||
/// Rust module path to the [preserves_schema::support][crate::support] module.
|
||||
pub support_crate: String,
|
||||
/// External modules for cross-referencing.
|
||||
pub external_modules: Map<ModulePath, ExternalModule>,
|
||||
/// Plugins active in this compiler instance.
|
||||
pub plugins: Vec<Box<dyn Plugin>>,
|
||||
/// If true, a directive is emitted in each module instructing
|
||||
/// [rustfmt](https://github.com/rust-lang/rustfmt) to ignore it.
|
||||
pub rustfmt_skip: bool,
|
||||
}
|
||||
|
||||
/// Loads a [Schema] or [Bundle] from path `i` into `bundle` for the given `purpose`.
|
||||
///
|
||||
/// If `i` holds a [Schema], then the file stem of `i` is used as the module name when placing
|
||||
/// the schema in `bundle`.
|
||||
pub fn load_schema_or_bundle_with_purpose(
|
||||
bundle: &mut Map<ModulePath, (Schema, Purpose)>,
|
||||
i: &PathBuf,
|
||||
|
@ -136,6 +190,11 @@ pub fn load_schema_or_bundle_with_purpose(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Loads a [Schema] or [Bundle] from raw binary encoded value `input` into `bundle` for the
|
||||
/// given `purpose`.
|
||||
///
|
||||
/// If `input` corresponds to a [Schema], then `prefix` is used as its module name; otherwise,
|
||||
/// it's a [Bundle], and `prefix` is ignored.
|
||||
pub fn load_schema_or_bundle_bin_with_purpose(
|
||||
bundle: &mut Map<ModulePath, (Schema, Purpose)>,
|
||||
prefix: &str,
|
||||
|
@ -167,6 +226,10 @@ fn bundle_prefix(i: &PathBuf) -> io::Result<&str> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Loads a [Schema] or [Bundle] from path `i` into `bundle`.
|
||||
///
|
||||
/// If `i` holds a [Schema], then the file stem of `i` is used as the module name when placing
|
||||
/// the schema in `bundle`.
|
||||
pub fn load_schema_or_bundle(bundle: &mut Map<ModulePath, Schema>, i: &PathBuf) -> io::Result<()> {
|
||||
let mut f = File::open(&i)?;
|
||||
let mut bs = vec![];
|
||||
|
@ -174,6 +237,10 @@ pub fn load_schema_or_bundle(bundle: &mut Map<ModulePath, Schema>, i: &PathBuf)
|
|||
load_schema_or_bundle_bin(bundle, bundle_prefix(i)?, &bs[..])
|
||||
}
|
||||
|
||||
/// Loads a [Schema] or [Bundle] from raw binary encoded value `input` into `bundle`.
|
||||
///
|
||||
/// If `input` corresponds to a [Schema], then `prefix` is used as its module name; otherwise,
|
||||
/// it's a [Bundle], and `prefix` is ignored.
|
||||
pub fn load_schema_or_bundle_bin(
|
||||
bundle: &mut Map<ModulePath, Schema>,
|
||||
prefix: &str,
|
||||
|
@ -201,6 +268,8 @@ pub fn load_schema_or_bundle_bin(
|
|||
}
|
||||
|
||||
impl CompilerConfig {
|
||||
/// Construct a [CompilerConfig] configured to send output files to `output_dir`, and to
|
||||
/// use `fully_qualified_module_prefix` as the Rust module prefix for generated code.
|
||||
pub fn new(output_dir: PathBuf, fully_qualified_module_prefix: String) -> Self {
|
||||
CompilerConfig {
|
||||
bundle: Map::new(),
|
||||
|
@ -279,6 +348,7 @@ impl CompilerConfig {
|
|||
}
|
||||
}
|
||||
|
||||
/// Expands a vector of [mod@glob]s to a vector of actual paths.
|
||||
pub fn expand_inputs(globs: &Vec<String>) -> io::Result<Vec<PathBuf>> {
|
||||
let mut result = Vec::new();
|
||||
for g in globs.iter() {
|
||||
|
@ -324,6 +394,7 @@ impl Schema {
|
|||
}
|
||||
}
|
||||
|
||||
/// Main entry point: runs the compilation process.
|
||||
pub fn compile(config: &CompilerConfig) -> io::Result<()> {
|
||||
let mut b = BundleContext::new(config);
|
||||
|
||||
|
|
Loading…
Reference in New Issue