Compare commits

..

2 commits

6 changed files with 66 additions and 27 deletions

View file

@ -12,7 +12,6 @@ members = ["protogen"]
byteorder = "1.5.0"
bytes = "1.10.0"
nix = "0.29.0"
protogen = { version = "0.1.0", path = "protogen" }
sendfd = { version = "0.4", features = [ "tokio" ] }
serde = "1.0.218"
serde_derive = "1.0.218"
@ -20,3 +19,6 @@ tokio = { version = "1.43.0", features = [ "fs", "net", "rt", "rt-multi-thread",
toml = "0.8.20"
tracing = "0.1.41"
tracing-subscriber = "0.3.19"
[build-dependencies]
protogen = { version = "0.1.0", path = "protogen" }

19
build.rs Normal file
View file

@ -0,0 +1,19 @@
use std::{env, path::Path};
fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let out_file = Path::new(&out_dir).join("proto_generated.rs");
std::fs::write(&out_file, protogen::generate_from_dir("proto"))
.expect("unable to write to file");
// If rustfmt is present, run rustfmt so that the generated file is somewhat human-readable
std::process::Command::new("rustfmt")
.arg(out_file.to_str().expect("utf8 error"))
.output()
.ok();
println!("cargo::rerun-if-changed=build.rs");
println!("cargo::rerun-if-changed=proto");
println!("cargo::rerun-if-changed=protogen");
}

View file

@ -3,9 +3,6 @@ name = "protogen"
version = "0.1.0"
edition = "2024"
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "1.0.93"
quick-xml = "0.37.2"

View file

@ -1,17 +1,42 @@
use std::path::PathBuf;
use std::path::Path;
use quick_xml::events::Event;
use quote::{format_ident, quote};
use syn::{Ident, LitStr, parse_macro_input};
use syn::Ident;
use types::{WlArgType, WlInterface, WlMsg, WlMsgType};
mod types;
#[proc_macro]
pub fn wayland_proto_gen(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input: LitStr = parse_macro_input!(item);
let p = PathBuf::from(input.value());
let file_name = p.file_stem().expect("No file name provided");
pub fn generate_from_dir(p: impl AsRef<Path>) -> String {
let (gen_code, (add_parsers_fn, add_object_types_fn)): (Vec<_>, (Vec<_>, Vec<_>)) =
std::fs::read_dir(p)
.expect("cannot open directory")
.filter_map(|f| f.ok())
.filter(|f| {
f.file_name()
.to_str()
.expect("utf8 encoding error")
.ends_with(".xml")
})
.map(|f| generate_from_xml_file(f.path()))
.unzip();
quote! {
#( #gen_code )*
pub fn wl_init_parsers() {
#( #add_parsers_fn(); )*
}
pub fn wl_init_known_types() {
#( #add_object_types_fn(); )*
}
}
.to_string()
}
fn generate_from_xml_file(p: impl AsRef<Path>) -> (proc_macro2::TokenStream, (Ident, Ident)) {
let file_name = p.as_ref().file_stem().expect("No file name provided");
let xml_str = std::fs::read_to_string(&p).expect("Unable to read from file");
let mut reader = quick_xml::Reader::from_str(&xml_str);
reader.config_mut().trim_text(true);
@ -63,13 +88,15 @@ pub fn wayland_proto_gen(item: proc_macro::TokenStream) -> proc_macro::TokenStre
}
}
let file_name_snake = file_name.to_str().unwrap().replace("-", "_");
// A function to add all event/request parsers to WL_EVENT_PARSERS and WL_REQUEST_PARSERS
let add_parsers_fn = format_ident!("wl_init_parsers_{}", file_name.to_str().unwrap());
let add_parsers_fn = format_ident!("wl_init_parsers_{}", file_name_snake);
// A function to add all known interfaces to the WL_KNOWN_OBJECT_TYPES map from name -> Rust type
let add_object_types_fn = format_ident!("wl_init_known_types_{}", file_name.to_str().unwrap());
let add_object_types_fn = format_ident!("wl_init_known_types_{}", file_name_snake);
quote! {
let ret_code = quote! {
#( #code )*
fn #add_parsers_fn() {
@ -80,8 +107,9 @@ pub fn wayland_proto_gen(item: proc_macro::TokenStream) -> proc_macro::TokenStre
fn #add_object_types_fn() {
#( WL_KNOWN_OBJECT_TYPES.write().unwrap().insert(#known_interface_names, #known_interface_consts); )*
}
}
.into()
};
(ret_code, (add_parsers_fn, add_object_types_fn))
}
fn handle_interface(

View file

@ -113,6 +113,7 @@ impl WlMsg {
.collect();
quote! {
#[allow(unused)]
pub struct #struct_name<'a> {
_phantom: std::marker::PhantomData<&'a ()>,
#( pub #field_names: #field_types, )*
@ -145,6 +146,7 @@ impl WlMsg {
WlMsgType::#msg_type
}
#[allow(unused)]
fn try_from_msg_impl(msg: &crate::codec::WlRawMsg) -> WaylandProtocolParsingOutcome<#struct_name> {
let payload = msg.payload();
let mut pos = 0usize;

View file

@ -7,7 +7,6 @@ use std::{
};
use byteorder::ByteOrder;
use protogen::wayland_proto_gen;
use crate::{
codec::WlRawMsg,
@ -218,13 +217,5 @@ pub fn lookup_known_object_type(name: &str) -> Option<WlObjectType> {
/// The default object ID of wl_display
pub const WL_DISPLAY_OBJECT_ID: u32 = 1;
wayland_proto_gen!("proto/wayland.xml");
/// Install all available Wayland protocol parsers for use by [decode_event] and [decode_request].
pub fn wl_init_parsers() {
wl_init_parsers_wayland();
}
pub fn wl_init_known_types() {
wl_init_known_types_wayland();
}
// Include code generated by build.rs
include!(concat!(env!("OUT_DIR"), "/proto_generated.rs"));