Structural scratch space for generated Rust code
Code generators that emit raw TokenStreams face a practical problem: a single
type definition often requires several top-level items--the struct or enum
itself, impl blocks, helper functions, etc. Some of them live together; others
live somewhere else entirely (a serde default helper in a defaults module,
say). Emitting everything into one flat stream makes related items drift apart;
routing some output into separate mods involves annoying bookkeeping.
codespace holds the code during generation. A Codespace owns a tree of
Mods; each Mod holds named items (opaque TokenStream fragments) and named
(Mod) submodules. Items are added under a "::"-delimited path--intermediate
segments name modules; the final segment is a sort key that is never emitted:
use codespace::Codespace;
use quote::quote;
let mut cs = Codespace::default();
cs.add_item("Status", quote! { pub enum Status { Active, Inactive } });
cs.add_item("defaults::status_default", quote! {
pub fn status_default() -> Status { Status::Active }
});Adding an item under an existing key appends those tokens, so a type and its
impl blocks can accumulate separately and still render together. Each Mod
also carries optional metadata: visibility, doc paragraphs, attributes.
codespace never parses, validates, or understands the fragments it holds, and
makes no naming decisions. Module names are the exception--invalid names
(including Rust keywords) are caller bugs and panic. See the crate docs for
details.
Generators can output tokens into a single TokenStream with
Codespace::into_stream or into multiple files with Codespace::into_files,
where each TokenStream is intended for a particular file path. The former is
good for proc macro implementation or calls from a build.rs file; the latter
can be well-suited for a stand-alone crate generator.
Both forms are deterministic and unformatted. Callers process the emitted
TokenStreams and apply formatting as needed with rustfmt
or prettyplease.
A Codespace may also include the external dependencies that its code
requires. Generators register what they emit with Codespace::add_dependency;
entries are kept by the identifier the code uses, and registrations under one
identifier merge. Nesting one codespace in another with
Codespace::add_mod_from_codespace carries its list along, and
Codespace::to_toml_dependencies writes the [dependencies] section of a
Cargo.toml for everything registered. codespace never infers a dependency
from the code it holds.
- Early alpha; API unstable.
- Part of the typify/progenitor code-generation stack.