Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Initial x11rb-async implementation #790

Merged
merged 10 commits into from
Feb 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[workspace]
members = ["generator", "xcbgen-rs", "x11rb-protocol", "x11rb", "cairo-example", "xtrace-example"]
members = ["generator", "xcbgen-rs", "x11rb-protocol", "x11rb", "x11rb-async", "cairo-example", "xtrace-example"]
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
PROTO=xcb-proto-1.15.2
PROTO_OUT=x11rb-protocol/src/protocol
X11RB_OUT=x11rb/src/protocol
ASYNC_OUT=x11rb-async/src/protocol

generate:
mkdir -p "$(PROTO_OUT)" "$(X11RB_OUT)"
cargo run -p x11rb-generator -- "$(PROTO)/src" "$(PROTO_OUT)" "$(X11RB_OUT)"
mkdir -p "$(PROTO_OUT)" "$(X11RB_OUT)" "$(ASYNC_OUT)"
cargo run -p x11rb-generator -- "$(PROTO)/src" "$(PROTO_OUT)" "$(X11RB_OUT)" "$(ASYNC_OUT)"

.PHONY: generate
33 changes: 23 additions & 10 deletions generator/src/generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,20 @@ pub(crate) struct Generated {
pub(crate) file_name: PathBuf,
pub(crate) proto: String,
pub(crate) x11rb: String,
pub(crate) async_: String,
}

pub(crate) fn generate(module: &xcbgen::defs::Module) -> Vec<Generated> {
let mut out_map = Vec::new();

let mut main_proto_out = Output::new();
let mut main_x11rb_out = Output::new();
for out in [&mut main_proto_out, &mut main_x11rb_out] {
let mut main_async_out = Output::new();
for out in [
&mut main_proto_out,
&mut main_x11rb_out,
&mut main_async_out,
] {
write_code_header(out);
outln!(out, "//! Bindings to the X11 protocol.");
outln!(out, "//!");
Expand Down Expand Up @@ -86,23 +92,30 @@ pub(crate) fn generate(module: &xcbgen::defs::Module) -> Vec<Generated> {
for ns in module.sorted_namespaces() {
let mut ns_proto_out = Output::new();
let mut ns_x11rb_out = Output::new();
let mut ns_async_out = Output::new();
let wrapper_info = resources::for_extension(&ns.header);
namespace::generate(
module,
&ns,
&caches,
&mut ns_proto_out,
&mut ns_x11rb_out,
&mut ns_async_out,
&mut enum_cases,
wrapper_info,
);
out_map.push(Generated {
file_name: PathBuf::from(format!("{}.rs", ns.header)),
proto: ns_proto_out.into_data(),
x11rb: ns_x11rb_out.into_data(),
async_: ns_async_out.into_data(),
});

for out in [&mut main_proto_out, &mut main_x11rb_out] {
for out in [
&mut main_proto_out,
&mut main_x11rb_out,
&mut main_async_out,
] {
if ext_has_feature(&ns.header) {
outln!(out, "#[cfg(feature = \"{}\")]", ns.header);
}
Expand All @@ -114,19 +127,19 @@ pub(crate) fn generate(module: &xcbgen::defs::Module) -> Vec<Generated> {
requests_replies::generate(&mut main_proto_out, module, enum_cases);
error_events::generate(&mut main_proto_out, module);

outln!(main_x11rb_out, "");
outln!(main_x11rb_out, "pub use x11rb_protocol::protocol::Request;");
outln!(main_x11rb_out, "pub use x11rb_protocol::protocol::Reply;");
outln!(
main_x11rb_out,
"pub use x11rb_protocol::protocol::ErrorKind;"
);
outln!(main_x11rb_out, "pub use x11rb_protocol::protocol::Event;");
for out in [&mut main_async_out, &mut main_x11rb_out] {
outln!(out, "");
outln!(out, "pub use x11rb_protocol::protocol::Request;");
outln!(out, "pub use x11rb_protocol::protocol::Reply;");
outln!(out, "pub use x11rb_protocol::protocol::ErrorKind;");
outln!(out, "pub use x11rb_protocol::protocol::Event;");
}

out_map.push(Generated {
file_name: PathBuf::from("mod.rs"),
proto: main_proto_out.into_data(),
x11rb: main_x11rb_out.into_data(),
async_: main_async_out.into_data(),
});
out_map
}
Expand Down
36 changes: 36 additions & 0 deletions generator/src/generator/namespace/async_switch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use std::fmt;

/// Emit sync or async code.
#[derive(Debug, PartialEq)]
pub(super) enum ImplMode {
Sync,
Async,
}

impl ImplMode {
pub(super) fn fn_async(&self) -> impl fmt::Display {
match self {
ImplMode::Sync => "",
ImplMode::Async => "async ",
}
}

pub(super) fn dot_await(&self) -> impl fmt::Display {
match self {
ImplMode::Sync => "",
ImplMode::Async => ".await",
}
}

pub(super) fn ret_ty(&self, inner: impl fmt::Display, named: bool) -> impl fmt::Display {
let (begin, end) = match self {
ImplMode::Sync => ("", "".to_string()),
ImplMode::Async => (
"Pin<Box<dyn Future<Output = ",
format!("> + Send + '{}>>", if named { "future" } else { "_" },),
),
};

format!("{}{}{}", begin, inner, end)
}
}
18 changes: 15 additions & 3 deletions generator/src/generator/namespace/header.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::async_switch::ImplMode;
use crate::generator::output::Output;

use xcbgen::defs as xcbdefs;
Expand All @@ -8,7 +9,12 @@ pub(super) enum Mode {
X11rb,
}

pub(super) fn write_header(out: &mut Output, ns: &xcbdefs::Namespace, mode: Mode) {
pub(super) fn write_header(
out: &mut Output,
ns: &xcbdefs::Namespace,
mode: Mode,
poll_mode: ImplMode,
) {
if let Some(info) = &ns.ext_info {
outln!(out, "//! Bindings to the `{}` X11 extension.", info.name);
} else {
Expand Down Expand Up @@ -89,6 +95,11 @@ pub(super) fn write_header(out: &mut Output, ns: &xcbdefs::Namespace, mode: Mode
outln!(out, "use crate::errors::ConnectionError;");
outln!(out, "#[allow(unused_imports)]");
outln!(out, "use crate::errors::ReplyOrIdError;");

if poll_mode == ImplMode::Async {
outln!(out, "use std::future::Future;");
outln!(out, "use std::pin::Pin;");
}
}

let mut imports = ns
Expand Down Expand Up @@ -151,11 +162,12 @@ pub(super) fn write_header(out: &mut Output, ns: &xcbdefs::Namespace, mode: Mode
if mode == Mode::X11rb {
outln!(out, "");
outln!(out, "/// Get the major opcode of this extension");
outln!(out, "fn major_opcode<Conn: RequestConnection + ?Sized>(conn: &Conn) -> Result<u8, ConnectionError> {{");
outln!(out, "{}fn major_opcode<Conn: RequestConnection + ?Sized>(conn: &Conn) -> Result<u8, ConnectionError> {{", poll_mode.fn_async());
out.indented(|out| {
outln!(
out,
"let info = conn.extension_information(X11_EXTENSION_NAME)?;",
"let info = conn.extension_information(X11_EXTENSION_NAME){}?;",
poll_mode.dot_await()
);
outln!(
out,
Expand Down
41 changes: 39 additions & 2 deletions generator/src/generator/namespace/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use super::output::Output;
use super::requests_replies::{EnumCases, PerModuleEnumCases};
use super::{get_ns_name_prefix, special_cases};

mod async_switch;
mod expr_to_str;
mod header;
pub(super) mod helpers;
Expand All @@ -37,12 +38,14 @@ pub(super) fn generate(
caches: &RefCell<Caches>,
proto_out: &mut Output,
x11rb_out: &mut Output,
async_out: &mut Output,
enum_cases: &mut EnumCases,
resource_info: &[super::ResourceInfo<'_>],
) {
NamespaceGenerator::new(module, ns, caches).generate(
proto_out,
x11rb_out,
async_out,
enum_cases,
resource_info,
);
Expand Down Expand Up @@ -81,15 +84,34 @@ impl<'ns, 'c> NamespaceGenerator<'ns, 'c> {
&self,
proto_out: &mut Output,
x11rb_out: &mut Output,
async_out: &mut Output,
enum_cases: &mut EnumCases,
resource_info: &[super::ResourceInfo<'_>],
) {
super::write_code_header(proto_out);
super::write_code_header(x11rb_out);
header::write_header(proto_out, self.ns, header::Mode::Protocol);
header::write_header(x11rb_out, self.ns, header::Mode::X11rb);
super::write_code_header(async_out);
header::write_header(
proto_out,
self.ns,
header::Mode::Protocol,
async_switch::ImplMode::Sync,
);
header::write_header(
x11rb_out,
self.ns,
header::Mode::X11rb,
async_switch::ImplMode::Sync,
);
header::write_header(
async_out,
self.ns,
header::Mode::X11rb,
async_switch::ImplMode::Async,
);

let mut trait_out = Output::new();
let mut async_trait_out = Output::new();

for def in self.ns.src_order_defs.borrow().iter() {
match def {
Expand All @@ -100,7 +122,9 @@ impl<'ns, 'c> NamespaceGenerator<'ns, 'c> {
request_def,
proto_out,
x11rb_out,
async_out,
&mut trait_out,
&mut async_trait_out,
cases_entry,
)
}
Expand Down Expand Up @@ -159,6 +183,19 @@ impl<'ns, 'c> NamespaceGenerator<'ns, 'c> {
"impl<C: RequestConnection + ?Sized> ConnectionExt for C {{}}",
);

outln!(
async_out,
"/// Extension trait defining the requests of this extension.",
);
outln!(async_out, "pub trait ConnectionExt: RequestConnection {{");
out!(async_out.indent(), "{}", async_trait_out.into_data());
outln!(async_out, "}}");
outln!(async_out, "");
outln!(
async_out,
"impl<C: RequestConnection + ?Sized> ConnectionExt for C {{}}",
);

for info in resource_info {
resource_wrapper::generate(self, x11rb_out, info);
}
Expand Down
Loading