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.
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:
```rust
use heck::ToKebabCase;
use std::{io::Write, fs::File, process::Command};
const PROTODIR: &'static str = "src/wayland/proto"; const PROTOCOLS: &'static [&'static str] = &[ "wayland", "xdgshell", "linuxdmabufunstable_v1" ];
fn main() { // Generate the proto module to import the generated code let modpath = &format!("{PROTODIR}/mod.rs"); let mut protomod = match File::create(modpath) { Ok(protomod) => protomod, Err(error) => panic!("Failed to create Rust source file '{modpath}': {error:?}") }; if let Err(error) = writeln!(protomod, "// Auto-Generated file. Do not edit.") { panic!("Failed to write Rust source file '{modpath}': {error:?}") } // Generate Wayland dispatch glue for protocol in PROTOCOLS { if let Err(error) = writeln!(protomod, "mod {protocol};\npub use {protocol}::*;") { panic!("Failed to write Rust source file '{modpath}': {error:?}") } yutanicodegen(protocol) } }
fn yutanicodegen(protocol: &str) { let spec = &format!("protocol/{}.toml", protocol.tokebabcase()); let proto = &format!("{PROTODIR}/{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:?}")
}
} ```