1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
//! Wayland protocol code-generation machinnery
//!
//! This crate provides procedural macros for generating the rust code associated with a
//! Wayland XML protocol specification, for use with the `wayland-client`, `wayland-server`
//! and `wayland-backend` crates.
//!
//! Before trying to use this crate, you may check if the protocol extension you want to use
//! is not already exposed in the `wayland-protocols` crate.
//!
//! ## Example usage
//!
//! Below is a template for generating the code for a custom protocol client-side. Server-side
//! is identical, just replacing `client` by `server`. The path to the XML file is relative to the
//! crate root.
//!
//! ```rust,ignore
//! // Generate the bindings in their own module
//! pub mod my_protocol {
//! use wayland_client;
//! // import objects from the core protocol if needed
//! use wayland_client::protocol::*;
//!
//! // This module hosts a low-level representation of the protocol objects
//! // you will not need to interact with it yourself, but the code generated
//! // by the generate_client_code! macro will use it
//! pub mod __interfaces {
//! // import the interfaces from the core protocol if needed
//! use wayland_client::protocol::__interfaces::*;
//! wayland_scanner::generate_interfaces!("./path/to/the/protocol.xml");
//! }
//! use self::__interfaces::*;
//!
//! // This macro generates the actual types that represent the wayland objects of
//! // your custom protocol
//! wayland_scanner::generate_client_code!("./path/to/the/protocol.xml");
//! }
//! ```
use std::{ffi::OsString, path::PathBuf};
mod c_interfaces;
mod client_gen;
mod common;
mod interfaces;
mod parse;
mod protocol;
mod server_gen;
mod token;
mod util;
/// Proc-macro for generating low-level interfaces associated with an XML specification
#[proc_macro]
pub fn generate_interfaces(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
let path: OsString = token::parse_lit_str_token(stream).into();
let path = if let Some(manifest_dir) = std::env::var_os("CARGO_MANIFEST_DIR") {
let mut buf = PathBuf::from(manifest_dir);
buf.push(path);
buf
} else {
path.into()
};
let file = match std::fs::File::open(&path) {
Ok(file) => file,
Err(e) => panic!("Failed to open protocol file {}: {}", path.display(), e),
};
let protocol = parse::parse(file);
interfaces::generate(&protocol, true).into()
}
/// Proc-macro for generating client-side API associated with an XML specification
#[proc_macro]
pub fn generate_client_code(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
let path: OsString = token::parse_lit_str_token(stream).into();
let path = if let Some(manifest_dir) = std::env::var_os("CARGO_MANIFEST_DIR") {
let mut buf = PathBuf::from(manifest_dir);
buf.push(path);
buf
} else {
path.into()
};
let file = match std::fs::File::open(&path) {
Ok(file) => file,
Err(e) => panic!("Failed to open protocol file {}: {}", path.display(), e),
};
let protocol = parse::parse(file);
client_gen::generate_client_objects(&protocol).into()
}
/// Proc-macro for generating server-side API associated with an XML specification
#[proc_macro]
pub fn generate_server_code(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
let path: OsString = token::parse_lit_str_token(stream).into();
let path = if let Some(manifest_dir) = std::env::var_os("CARGO_MANIFEST_DIR") {
let mut buf = PathBuf::from(manifest_dir);
buf.push(path);
buf
} else {
path.into()
};
let file = match std::fs::File::open(&path) {
Ok(file) => file,
Err(e) => panic!("Failed to open protocol file {}: {}", path.display(), e),
};
let protocol = parse::parse(file);
server_gen::generate_server_objects(&protocol).into()
}
#[cfg(test)]
fn format_rust_code(code: &str) -> String {
use std::{
io::Write,
process::{Command, Stdio},
};
if let Ok(mut proc) = Command::new("rustfmt")
.arg("--emit=stdout")
.arg("--edition=2018")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
//.stderr(Stdio::null())
.spawn()
{
{
let stdin = proc.stdin.as_mut().unwrap();
stdin.write_all(code.as_bytes()).unwrap();
}
if let Ok(output) = proc.wait_with_output() {
if output.status.success() {
return std::str::from_utf8(&output.stdout).unwrap().to_owned();
}
}
}
panic!("Rustfmt failed!");
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum Side {
/// wayland client applications
Client,
/// wayland compositors
Server,
}