Skip to main content

rakata_formats_derive/
lib.rs

1//! The derive behind `rakata-formats`' typed GFF views.
2//!
3//! Consumers never name this crate. `rakata-formats` re-exports
4//! [`GffModel`](macro@GffModel) unconditionally, so a view writes
5//! `#[derive(GffModel)]` and nothing else.
6//!
7//! # The seven facts a field carries
8//!
9//! The attribute vocabulary is not a list of features. It is one key per fact,
10//! and the facts came first:
11//!
12//! 1. **Its label.** What the container calls it. The only positional
13//!    argument, because every field has one and it is never in doubt.
14//! 2. **Its shape.** Whether a scalar sits under the label, a struct, or a
15//!    list, and for a list how an element's struct id is decided. Read from
16//!    the declared Rust type, so it is usually written nowhere.
17//! 3. **Its liveness.** What the engine does with it, in each direction, with
18//!    the finding cited.
19//! 4. **Its absent-value.** What the engine holds when a file omits the
20//!    label, with the finding cited.
21//! 5. **Whether it is required.** Whether absence costs more than a default.
22//! 6. **Its constraint.** What range the engine accepts.
23//! 7. **Its omission.** Whether this writer stops emitting at a value, on
24//!    what condition, against how many files.
25//!
26//! Everything else a schema entry holds is derived rather than declared. The
27//! reader's substitute is the clearest case: it exists exactly when this
28//! derive generates the reader, so a field whose codec is hand-written cannot
29//! claim one, and that is a property of the grammar rather than a rule
30//! somebody has to remember.
31//!
32//! # Why the shape is one fact and not three
33//!
34//! The vocabulary this replaced spelled the shape across a type column and a
35//! children column, with no room at all for a list's element struct id or for
36//! a field whose element schema is chosen at run time. Treating the shape as
37//! one fact is what stops each of those costing another struct field: it is a
38//! variant, not a column.
39
40mod model;
41mod model_field;
42
43/// Derives `Default`, the reader, the writer and the schema for a GFF struct.
44///
45/// See the [crate docs](self) for the vocabulary. Errors are reported at the
46/// span of the offending field or attribute rather than at the derive.
47#[proc_macro_derive(GffModel, attributes(gff, gff_entry, gff_manual_element))]
48pub fn derive_gff_model(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
49    let input = syn::parse_macro_input!(input as syn::DeriveInput);
50    model::expand(&input)
51        .unwrap_or_else(syn::Error::into_compile_error)
52        .into()
53}