#protocols #generation #glue #dispatch #proto #wayland-protocol #yutani

yutani-codegen

为Yutani生成协议调度粘合代码

1个不稳定版本

0.0.0 2022年11月5日

#35 in #wayland-protocol

MIT许可证

23KB
487

yutani-codegen

yutani生成代码。

Wayland使用XML(或在yutani中为TOML)指定协议,包含所有必要的自动生成调度粘合代码的信息,以便实现Wayland协议可以像定义所需函数一样简单。

用法

此crate可以用于构建脚本或宏。使用构建脚本可以减少所需的工作量,可能提高编译时间,并且还会更好地与Rust Analyzer集成。

为了生成的代码不是完全让人眼花缭乱,您应该使用rustfmt对其进行清理。

一个示例build.rs脚本

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:?}")
    }
}

依赖项

~0.6–1.2MB
~27K SLoC