1 unstable release
0.0.0 | Nov 5, 2022 |
---|
#33 in #glue
23KB
487 lines
yutani-codegen
Code generation for yutani.
Wayland specifies protocols in XML (or TOML in the case of yutani
) with all of the necessary information to
automatically generate dispatch glue so that implementing a Wayland protocol can be as simple as defining
the required functions.
Usage
This crate can be used either in a build script or macro. Using a build script reduces the amount of work required, potentially improving compile times, and will also integrate better with Rust Analyzer.
So that the generated code isn't a complete eye-bleed you should clean it up with rustfmt
.
An example build.rs
script:
use heck::ToKebabCase;
use std::{io::Write, fs::File, process::Command};
const PROTO_DIR: &'static str = "src/wayland/proto";
const PROTOCOLS: &'static [&'static str] = &[
"wayland",
"xdg_shell",
"linux_dmabuf_unstable_v1"
];
fn main() {
// Generate the proto module to import the generated code
let mod_path = &format!("{PROTO_DIR}/mod.rs");
let mut proto_mod = match File::create(mod_path) {
Ok(proto_mod) => proto_mod,
Err(error) => panic!("Failed to create Rust source file '{mod_path}': {error:?}")
};
if let Err(error) = writeln!(proto_mod, "// Auto-Generated file. Do not edit.") {
panic!("Failed to write Rust source file '{mod_path}': {error:?}")
}
// Generate Wayland dispatch glue
for protocol in PROTOCOLS {
if let Err(error) = writeln!(proto_mod, "mod {protocol};\npub use {protocol}::*;") {
panic!("Failed to write Rust source file '{mod_path}': {error:?}")
}
yutani_codegen(protocol)
}
}
fn yutani_codegen(protocol: &str) {
let spec = &format!("protocol/{}.toml", protocol.to_kebab_case());
let proto = &format!("{PROTO_DIR}/{protocol}.rs");
println!("cargo:rerun-if-changed={spec}");
println!("cargo:rerun-if-changed={proto}");
let code = match yutani_codegen::protocol(spec) {
Ok(code) => code,
Err(error) => panic!("Failed to read protocol specification '{spec}': {error:?}")
};
let mut proto_file = match File::create(proto) {
Ok(proto_file) => proto_file,
Err(error) => panic!("Failed to create Rust source file '{proto}': {error:?}")
};
if let Err(error) = writeln!(proto_file, "// Auto-Generated file. Do not edit.\n#![allow(dead_code)]\n\n{}", code) {
panic!("Failed to write Rust source file '{proto}': {error:?}")
}
if let Err(error) = Command::new("rustfmt").arg(proto).status() {
panic!("Failed to run rustfmt on Rust source file '{proto}': {error:?}")
}
}
Dependencies
~2MB
~46K SLoC