Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/wayland-scanner/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/wayland-scanner/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"3d43eeabb2b34d3defc25c7773bbf1be4749e0e8235d3ddefe054439b7c2d5fe","LICENSE.txt":"10e5daea68c3ab7da6468ea51860e9d4ac87ea6a9a2d34127beff17b7193b618","README.md":"b9ca6e35045e5f66c8ec7198636e59dd52d3a5591bb65526090d0e07d9f9fdc4","src/c_code_gen.rs":"a0444ff61e75be34cfe5be48a0d230c7f009dc54414fb1b8d4cab99018ca5a83","src/c_interface_gen.rs":"92f6e1ab0366b8f3fb6fffa04fac6a8c13bc40c0851899225e4033ead2a21916","src/common_gen.rs":"b4dd7f5e412b69e10c197add797ba9f1f2a6580e84b443f62d3a656bc3724720","src/lib.rs":"9492f18d20bf98193a1e1011bea3b5cd1b3828f248e876604d693f7a83017764","src/parse.rs":"d8ad45bc19c86cc50dfb31d530227682098f2632003df5b0a14a19f5628dde4b","src/protocol.rs":"79a2b53b70eb72819a480f5b28058d5b78c985303915c3ede8a073cc944025e3","src/side.rs":"5e398f59f987a41c09f818c369f6fffb560977d988b971d002d920c5af218137","src/util.rs":"47a9844e8aa375705ee74dcd2541613f8ab2466b065eb1091bbd40c98a351b5f"},"package":"8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"}
|
||||
38
third-party/vendor/wayland-scanner/Cargo.toml
vendored
Normal file
38
third-party/vendor/wayland-scanner/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "wayland-scanner"
|
||||
version = "0.29.5"
|
||||
authors = ["Victor Berger <victor.berger@m4x.org>"]
|
||||
description = "Wayland Scanner for generating rust APIs from XML wayland protocol files. Intended for use with wayland-sys. You should only need this crate if you are working on custom wayland protocol extensions. Look at the crate wayland-client for usable bindings."
|
||||
documentation = "https://smithay.github.io/wayland-rs/wayland_scanner/"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"wayland",
|
||||
"codegen",
|
||||
]
|
||||
categories = [
|
||||
"gui",
|
||||
"api-bindings",
|
||||
]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/smithay/wayland-rs"
|
||||
|
||||
[dependencies.proc-macro2]
|
||||
version = "1.0.11"
|
||||
|
||||
[dependencies.quote]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.xml-rs]
|
||||
version = ">=0.7, <0.9"
|
||||
19
third-party/vendor/wayland-scanner/LICENSE.txt
vendored
Normal file
19
third-party/vendor/wayland-scanner/LICENSE.txt
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2015 Victor Berger
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
12
third-party/vendor/wayland-scanner/README.md
vendored
Normal file
12
third-party/vendor/wayland-scanner/README.md
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[](https://crates.io/crates/wayland-scanner)
|
||||
[](https://docs.rs/wayland-scanner)
|
||||
[](https://github.com/Smithay/wayland-rs/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||
[](https://codecov.io/gh/Smithay/wayland-rs)
|
||||
|
||||
# wayland-scanner
|
||||
|
||||
Code-generation for Wayland protocols, to be used with `wayland-client` or `wayland-server`
|
||||
to integrate them with your own protocol extensions.
|
||||
|
||||
Most general protocol extensions are already exposed by the `wayland-protocols` crate, so you
|
||||
don't need to use `wayland-scanner` directly to support them.
|
||||
550
third-party/vendor/wayland-scanner/src/c_code_gen.rs
vendored
Normal file
550
third-party/vendor/wayland-scanner/src/c_code_gen.rs
vendored
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
use std::iter;
|
||||
|
||||
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||
use quote::quote;
|
||||
|
||||
use crate::common_gen::*;
|
||||
use crate::protocol::*;
|
||||
use crate::util::*;
|
||||
use crate::Side;
|
||||
|
||||
pub(crate) fn generate_protocol_client(protocol: Protocol) -> TokenStream {
|
||||
// Force the fallback to work around https://github.com/alexcrichton/proc-macro2/issues/218
|
||||
proc_macro2::fallback::force();
|
||||
|
||||
let modules = protocol.interfaces.iter().map(|iface| {
|
||||
let doc_attr = iface.description.as_ref().map(description_to_doc_attr);
|
||||
let mod_name = Ident::new(&iface.name, Span::call_site());
|
||||
let iface_name = Ident::new(&snake_to_camel(&iface.name), Span::call_site());
|
||||
|
||||
let enums = &iface.enums;
|
||||
|
||||
let ident = Ident::new("Request", Span::call_site());
|
||||
let requests = gen_messagegroup(
|
||||
&ident,
|
||||
Side::Client,
|
||||
false,
|
||||
&iface.requests,
|
||||
Some(messagegroup_c_addon(&ident, &iface_name, Side::Client, false, &iface.requests)),
|
||||
);
|
||||
|
||||
let ident = Ident::new("Event", Span::call_site());
|
||||
let events = gen_messagegroup(
|
||||
&ident,
|
||||
Side::Client,
|
||||
true,
|
||||
&iface.events,
|
||||
Some(messagegroup_c_addon(&ident, &iface_name, Side::Client, true, &iface.events)),
|
||||
);
|
||||
|
||||
let interface = gen_interface(
|
||||
&iface_name,
|
||||
&iface.name,
|
||||
iface.version,
|
||||
Some(interface_c_addon(&iface.name)),
|
||||
Side::Client,
|
||||
);
|
||||
|
||||
let object_methods = gen_object_methods(&iface_name, &iface.requests, Side::Client);
|
||||
let sinces = gen_since_constants(&iface.requests, &iface.events);
|
||||
let c_interface = super::c_interface_gen::generate_interface(iface);
|
||||
|
||||
quote! {
|
||||
#doc_attr
|
||||
pub mod #mod_name {
|
||||
use std::os::raw::c_char;
|
||||
use super::{
|
||||
Proxy, AnonymousObject, Interface, MessageGroup, MessageDesc, ArgumentType,
|
||||
Object, Message, Argument, ObjectMetadata, types_null, NULLPTR, Main, smallvec,
|
||||
};
|
||||
use super::sys::common::{wl_interface, wl_array, wl_argument, wl_message};
|
||||
use super::sys::client::*;
|
||||
|
||||
#(#enums)*
|
||||
#requests
|
||||
#events
|
||||
#interface
|
||||
#object_methods
|
||||
#sinces
|
||||
#c_interface
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let c_prefix = super::c_interface_gen::generate_interfaces_prefix(&protocol);
|
||||
|
||||
quote! {
|
||||
#c_prefix
|
||||
|
||||
#(#modules)*
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn generate_protocol_server(protocol: Protocol) -> TokenStream {
|
||||
// Force the fallback to work around https://github.com/alexcrichton/proc-macro2/issues/218
|
||||
proc_macro2::fallback::force();
|
||||
|
||||
let modules = protocol
|
||||
.interfaces
|
||||
.iter()
|
||||
// display and registry are handled specially
|
||||
.filter(|iface| iface.name != "wl_display" && iface.name != "wl_registry")
|
||||
.map(|iface| {
|
||||
let doc_attr = iface.description.as_ref().map(description_to_doc_attr);
|
||||
let mod_name = Ident::new(&iface.name, Span::call_site());
|
||||
let iface_name = Ident::new(&snake_to_camel(&iface.name), Span::call_site());
|
||||
|
||||
let enums = &iface.enums;
|
||||
|
||||
let ident = Ident::new("Request", Span::call_site());
|
||||
let requests = gen_messagegroup(
|
||||
&ident,
|
||||
Side::Server,
|
||||
true,
|
||||
&iface.requests,
|
||||
Some(messagegroup_c_addon(
|
||||
&ident,
|
||||
&iface_name,
|
||||
Side::Server,
|
||||
true,
|
||||
&iface.requests,
|
||||
)),
|
||||
);
|
||||
|
||||
let ident = Ident::new("Event", Span::call_site());
|
||||
let events = gen_messagegroup(
|
||||
&ident,
|
||||
Side::Server,
|
||||
false,
|
||||
&iface.events,
|
||||
Some(messagegroup_c_addon(
|
||||
&ident,
|
||||
&iface_name,
|
||||
Side::Server,
|
||||
false,
|
||||
&iface.events,
|
||||
)),
|
||||
);
|
||||
|
||||
let interface = gen_interface(
|
||||
&Ident::new(&snake_to_camel(&iface.name), Span::call_site()),
|
||||
&iface.name,
|
||||
iface.version,
|
||||
Some(interface_c_addon(&iface.name)),
|
||||
Side::Server,
|
||||
);
|
||||
let object_methods = gen_object_methods(&iface_name, &iface.events, Side::Server);
|
||||
let sinces = gen_since_constants(&iface.requests, &iface.events);
|
||||
let c_interface = super::c_interface_gen::generate_interface(iface);
|
||||
|
||||
quote! {
|
||||
#doc_attr
|
||||
pub mod #mod_name {
|
||||
use std::os::raw::c_char;
|
||||
use super::{
|
||||
Resource, AnonymousObject, Interface, MessageGroup, MessageDesc, Main, smallvec,
|
||||
ArgumentType, Object, Message, Argument, ObjectMetadata, types_null, NULLPTR
|
||||
};
|
||||
use super::sys::common::{wl_argument, wl_interface, wl_array, wl_message};
|
||||
use super::sys::server::*;
|
||||
|
||||
#(#enums)*
|
||||
#requests
|
||||
#events
|
||||
#interface
|
||||
#object_methods
|
||||
#sinces
|
||||
#c_interface
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let c_prefix = super::c_interface_gen::generate_interfaces_prefix(&protocol);
|
||||
|
||||
quote! {
|
||||
#c_prefix
|
||||
#(#modules)*
|
||||
}
|
||||
}
|
||||
|
||||
fn messagegroup_c_addon(
|
||||
name: &Ident,
|
||||
parent_iface: &Ident,
|
||||
side: Side,
|
||||
receiver: bool,
|
||||
messages: &[Message],
|
||||
) -> TokenStream {
|
||||
let from_raw_c_body = if receiver {
|
||||
let match_arms = messages
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, msg)| {
|
||||
let pattern = Literal::u16_unsuffixed(i as u16);
|
||||
let msg_name = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
|
||||
let msg_name_qualified = quote!(#name::#msg_name);
|
||||
let (args_binding, result) = if msg.args.is_empty() {
|
||||
(None, msg_name_qualified)
|
||||
} else {
|
||||
let len = Literal::usize_unsuffixed(msg.args.len());
|
||||
|
||||
let fields = msg.args.iter().enumerate().map(|(j, arg)| {
|
||||
let field_name = Ident::new(
|
||||
&format!("{}{}", if is_keyword(&arg.name) { "_" } else { "" }, arg.name),
|
||||
Span::call_site(),
|
||||
);
|
||||
|
||||
let idx = Literal::usize_unsuffixed(j);
|
||||
let field_value = match arg.typ {
|
||||
Type::Uint => {
|
||||
if let Some(ref enu) = arg.enum_ {
|
||||
let enum_type = dotted_to_relname(enu);
|
||||
quote!(#enum_type::from_raw(_args[#idx].u).ok_or(())?)
|
||||
} else {
|
||||
quote!(_args[#idx].u)
|
||||
}
|
||||
}
|
||||
Type::Int => {
|
||||
if let Some(ref enu) = arg.enum_ {
|
||||
let enum_type = dotted_to_relname(enu);
|
||||
quote!(#enum_type::from_raw(_args[#idx].i as u32).ok_or(())?)
|
||||
} else {
|
||||
quote!(_args[#idx].i)
|
||||
}
|
||||
}
|
||||
Type::Fixed => quote!((_args[#idx].f as f64) / 256.),
|
||||
Type::String => {
|
||||
let string_conversion = quote! {
|
||||
::std::ffi::CStr::from_ptr(_args[#idx].s).to_string_lossy().into_owned()
|
||||
};
|
||||
|
||||
if arg.allow_null {
|
||||
quote! {
|
||||
if _args[#idx].s.is_null() { None } else { Some(#string_conversion) }
|
||||
}
|
||||
} else {
|
||||
string_conversion
|
||||
}
|
||||
}
|
||||
Type::Array => {
|
||||
let array_conversion = quote! {
|
||||
{
|
||||
let array = &*_args[#idx].a;
|
||||
::std::slice::from_raw_parts(array.data as *const u8, array.size)
|
||||
.to_owned()
|
||||
}
|
||||
};
|
||||
|
||||
if arg.allow_null {
|
||||
quote! {
|
||||
if _args[#idx].a.is_null() { None } else { Some(#array_conversion) }
|
||||
}
|
||||
} else {
|
||||
array_conversion
|
||||
}
|
||||
}
|
||||
Type::Fd => quote!(_args[#idx].h),
|
||||
Type::Object => {
|
||||
let object_name = side.object_name();
|
||||
let object_conversion = if let Some(ref iface) = arg.interface {
|
||||
let iface_mod = Ident::new(iface, Span::call_site());
|
||||
let iface_type = Ident::new(&snake_to_camel(iface), Span::call_site());
|
||||
|
||||
quote! {
|
||||
#object_name::<super::#iface_mod::#iface_type>::from_c_ptr(
|
||||
_args[#idx].o as *mut _,
|
||||
).into()
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#object_name::<AnonymousObject>::from_c_ptr(_args[#idx].o as *mut _).into()
|
||||
}
|
||||
};
|
||||
|
||||
if arg.allow_null {
|
||||
quote! {
|
||||
if _args[#idx].o.is_null() { None } else { Some(#object_conversion) }
|
||||
}
|
||||
} else {
|
||||
object_conversion
|
||||
}
|
||||
}
|
||||
Type::NewId => {
|
||||
let new_id_conversion = if let Some(ref iface) = arg.interface {
|
||||
let iface_mod = Ident::new(iface, Span::call_site());
|
||||
let iface_type = Ident::new(&snake_to_camel(iface), Span::call_site());
|
||||
|
||||
match side {
|
||||
Side::Client => {
|
||||
quote! {
|
||||
Main::<super::#iface_mod::#iface_type>::from_c_ptr(
|
||||
_args[#idx].o as *mut _
|
||||
)
|
||||
}
|
||||
}
|
||||
Side::Server => {
|
||||
quote! {
|
||||
{
|
||||
let me = Resource::<#parent_iface>::from_c_ptr(obj as *mut _);
|
||||
me.make_child_for::<super::#iface_mod::#iface_type>(_args[#idx].n).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// bind-like function
|
||||
quote!(panic!("Cannot unserialize anonymous new id."))
|
||||
};
|
||||
|
||||
if arg.allow_null {
|
||||
quote! {
|
||||
if _args[#idx].o.is_null() { None } else { Some(#new_id_conversion) }
|
||||
}
|
||||
} else {
|
||||
new_id_conversion
|
||||
}
|
||||
}
|
||||
Type::Destructor => panic!("An argument cannot have type \"destructor\"."),
|
||||
};
|
||||
|
||||
quote!(#field_name: #field_value)
|
||||
});
|
||||
|
||||
let result = quote! {
|
||||
#msg_name_qualified {
|
||||
#(#fields,)*
|
||||
}
|
||||
};
|
||||
|
||||
let args_binding = quote! {
|
||||
let _args = ::std::slice::from_raw_parts(args, #len);
|
||||
};
|
||||
|
||||
(Some(args_binding), result)
|
||||
};
|
||||
|
||||
quote! {
|
||||
#pattern => {
|
||||
#args_binding
|
||||
Ok(#result)
|
||||
}
|
||||
}
|
||||
})
|
||||
.chain(iter::once(quote!(_ => return Err(()))));
|
||||
|
||||
quote! {
|
||||
match opcode {
|
||||
#(#match_arms,)*
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let panic_message = format!("{}::from_raw_c can not be used {:?}-side.", name, side);
|
||||
quote!(panic!(#panic_message))
|
||||
};
|
||||
|
||||
let as_raw_c_in_body = if receiver {
|
||||
let panic_message = format!("{}::as_raw_c_in can not be used {:?}-side.", name, side);
|
||||
quote!(panic!(#panic_message))
|
||||
} else {
|
||||
let match_arms = messages.iter().enumerate().map(|(i, msg)| {
|
||||
let msg_name = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
|
||||
let pattern = if msg.args.is_empty() {
|
||||
quote!(#name::#msg_name)
|
||||
} else {
|
||||
let fields = msg.args.iter().flat_map(|arg| {
|
||||
// Client-side newid request do not contain a placeholder
|
||||
if side == Side::Client && arg.typ == Type::NewId && arg.interface.is_some() {
|
||||
None
|
||||
} else {
|
||||
Some(Ident::new(
|
||||
&format!("{}{}", if is_keyword(&arg.name) { "_" } else { "" }, arg.name),
|
||||
Span::call_site(),
|
||||
))
|
||||
}
|
||||
});
|
||||
|
||||
quote!(#name::#msg_name { #(#fields),* })
|
||||
};
|
||||
|
||||
let buffer_len = Literal::usize_unsuffixed(
|
||||
msg.args.len()
|
||||
+ 2 * msg
|
||||
.args
|
||||
.iter()
|
||||
.filter(|arg| arg.typ == Type::NewId && arg.interface.is_none())
|
||||
.count(),
|
||||
);
|
||||
|
||||
let mut j = 0;
|
||||
let args_array_init_stmts = msg.args.iter().map(|arg| {
|
||||
let idx = Literal::usize_unsuffixed(j);
|
||||
let arg_name = Ident::new(
|
||||
&format!("{}{}", if is_keyword(&arg.name) { "_" } else { "" }, arg.name),
|
||||
Span::call_site(),
|
||||
);
|
||||
|
||||
let res = match arg.typ {
|
||||
Type::Uint => {
|
||||
if arg.enum_.is_some() {
|
||||
quote! {
|
||||
_args_array[#idx].u = #arg_name.to_raw();
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
_args_array[#idx].u = #arg_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::Int => {
|
||||
if arg.enum_.is_some() {
|
||||
quote! {
|
||||
_args_array[#idx].i = #arg_name.to_raw() as i32;
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
_args_array[#idx].i = #arg_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::Fixed => quote! {
|
||||
_args_array[#idx].f = (#arg_name * 256.) as i32;
|
||||
},
|
||||
Type::String => {
|
||||
let arg_variable = Ident::new(&format!("_arg_{}", j), Span::call_site());
|
||||
if arg.allow_null {
|
||||
quote! {
|
||||
let #arg_variable = #arg_name.map(|s| ::std::ffi::CString::new(s).unwrap());
|
||||
_args_array[#idx].s =
|
||||
(&#arg_variable).as_ref().map(|s| s.as_ptr()).unwrap_or(::std::ptr::null());
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
let #arg_variable = ::std::ffi::CString::new(#arg_name).unwrap();
|
||||
_args_array[#idx].s = #arg_variable.as_ptr();
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::Array => {
|
||||
let arg_variable = Ident::new(&format!("_arg_{}", j), Span::call_site());
|
||||
if arg.allow_null {
|
||||
quote! {
|
||||
let #arg_variable = #arg_name.as_ref().map(|vec| wl_array {
|
||||
size: vec.len(),
|
||||
alloc: vec.capacity(),
|
||||
data: vec.as_ptr() as *mut _,
|
||||
});
|
||||
_args_array[#idx].a = #arg_variable
|
||||
.as_ref()
|
||||
.map(|a| a as *const wl_array)
|
||||
.unwrap_or(::std::ptr::null());
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
let #arg_variable = wl_array {
|
||||
size: #arg_name.len(),
|
||||
alloc: #arg_name.capacity(),
|
||||
data: #arg_name.as_ptr() as *mut _,
|
||||
};
|
||||
_args_array[#idx].a = &#arg_variable;
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::Fd => quote! {
|
||||
_args_array[#idx].h = #arg_name;
|
||||
},
|
||||
Type::Object => {
|
||||
if arg.allow_null {
|
||||
quote! {
|
||||
_args_array[#idx].o = #arg_name
|
||||
.map(|o| o.as_ref().c_ptr() as *mut _)
|
||||
.unwrap_or(::std::ptr::null_mut());
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
_args_array[#idx].o = #arg_name.as_ref().c_ptr() as *mut _;
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::NewId => {
|
||||
if arg.interface.is_some() {
|
||||
if side == Side::Client {
|
||||
quote! {
|
||||
_args_array[#idx].o = ::std::ptr::null_mut() as *mut _;
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
_args_array[#idx].o = #arg_name.c_ptr() as *mut _;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert!(
|
||||
side != Side::Server,
|
||||
"Cannot serialize anonymous NewID from server."
|
||||
);
|
||||
|
||||
// The arg is actually (string, uint, NULL)
|
||||
let arg_variable = Ident::new(&format!("_arg_{}_s", j), Span::call_site());
|
||||
let idx1 = Literal::usize_unsuffixed(j + 1);
|
||||
let idx2 = Literal::usize_unsuffixed(j + 2);
|
||||
|
||||
let res = quote! {
|
||||
let #arg_variable = ::std::ffi::CString::new(#arg_name.0).unwrap();
|
||||
_args_array[#idx].s = #arg_variable.as_ptr();
|
||||
_args_array[#idx1].u = #arg_name.1;
|
||||
_args_array[#idx2].o = ::std::ptr::null_mut();
|
||||
};
|
||||
|
||||
j += 2;
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
Type::Destructor => panic!("An argument cannot have type \"destructor\"."),
|
||||
};
|
||||
|
||||
j += 1;
|
||||
|
||||
res
|
||||
});
|
||||
|
||||
let idx = Literal::u32_unsuffixed(i as u32);
|
||||
|
||||
quote! {
|
||||
#pattern => {
|
||||
let mut _args_array: [wl_argument; #buffer_len] = unsafe { ::std::mem::zeroed() };
|
||||
#(#args_array_init_stmts)*
|
||||
|
||||
f(#idx, &mut _args_array)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
match self {
|
||||
#(#match_arms,)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
unsafe fn from_raw_c(
|
||||
obj: *mut ::std::os::raw::c_void,
|
||||
opcode: u32,
|
||||
args: *const wl_argument,
|
||||
) -> Result<#name, ()> {
|
||||
#from_raw_c_body
|
||||
}
|
||||
|
||||
fn as_raw_c_in<F, T>(self, f: F) -> T where F: FnOnce(u32, &mut [wl_argument]) -> T {
|
||||
#as_raw_c_in_body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn interface_c_addon(low_name: &str) -> TokenStream {
|
||||
let iface_name = Ident::new(&format!("{}_interface", low_name), Span::call_site());
|
||||
quote! {
|
||||
fn c_interface() -> *const wl_interface {
|
||||
unsafe { &#iface_name }
|
||||
}
|
||||
}
|
||||
}
|
||||
179
third-party/vendor/wayland-scanner/src/c_interface_gen.rs
vendored
Normal file
179
third-party/vendor/wayland-scanner/src/c_interface_gen.rs
vendored
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
use std::cmp;
|
||||
use std::iter::repeat;
|
||||
|
||||
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||
use quote::quote;
|
||||
|
||||
use crate::protocol::*;
|
||||
use crate::util::null_terminated_byte_string_literal;
|
||||
|
||||
pub(crate) fn generate_interfaces_prefix(protocol: &Protocol) -> TokenStream {
|
||||
let longest_nulls = protocol.interfaces.iter().fold(0, |max, interface| {
|
||||
let request_longest_null = interface.requests.iter().fold(0, |max, request| {
|
||||
if request.all_null() {
|
||||
cmp::max(request.args.len(), max)
|
||||
} else {
|
||||
max
|
||||
}
|
||||
});
|
||||
let events_longest_null = interface.events.iter().fold(0, |max, event| {
|
||||
if event.all_null() {
|
||||
cmp::max(event.args.len(), max)
|
||||
} else {
|
||||
max
|
||||
}
|
||||
});
|
||||
cmp::max(max, cmp::max(request_longest_null, events_longest_null))
|
||||
});
|
||||
|
||||
let types_null_len = Literal::usize_unsuffixed(longest_nulls);
|
||||
|
||||
let nulls = repeat(quote!(NULLPTR as *const sys::common::wl_interface)).take(longest_nulls);
|
||||
|
||||
quote! {
|
||||
use std::os::raw::{c_char, c_void};
|
||||
|
||||
const NULLPTR: *const c_void = 0 as *const c_void;
|
||||
static mut types_null: [*const sys::common::wl_interface; #types_null_len] = [
|
||||
#(#nulls,)*
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn generate_interface(interface: &Interface) -> TokenStream {
|
||||
let requests = gen_messages(interface, &interface.requests, "requests");
|
||||
let events = gen_messages(interface, &interface.events, "events");
|
||||
|
||||
let interface_ident = Ident::new(&format!("{}_interface", interface.name), Span::call_site());
|
||||
let name_value = null_terminated_byte_string_literal(&interface.name);
|
||||
let version_value = Literal::i32_unsuffixed(interface.version as i32);
|
||||
let request_count_value = Literal::i32_unsuffixed(interface.requests.len() as i32);
|
||||
let requests_value = if interface.requests.is_empty() {
|
||||
quote!(NULLPTR as *const wl_message)
|
||||
} else {
|
||||
let requests_ident = Ident::new(&format!("{}_requests", interface.name), Span::call_site());
|
||||
quote!(unsafe { &#requests_ident as *const _ })
|
||||
};
|
||||
let event_count_value = Literal::i32_unsuffixed(interface.events.len() as i32);
|
||||
let events_value = if interface.events.is_empty() {
|
||||
quote!(NULLPTR as *const wl_message)
|
||||
} else {
|
||||
let events_ident = Ident::new(&format!("{}_events", interface.name), Span::call_site());
|
||||
quote!(unsafe { &#events_ident as *const _ })
|
||||
};
|
||||
|
||||
quote!(
|
||||
#requests
|
||||
#events
|
||||
|
||||
/// C representation of this interface, for interop
|
||||
pub static mut #interface_ident: wl_interface = wl_interface {
|
||||
name: #name_value as *const u8 as *const c_char,
|
||||
version: #version_value,
|
||||
request_count: #request_count_value,
|
||||
requests: #requests_value,
|
||||
event_count: #event_count_value,
|
||||
events: #events_value,
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
fn gen_messages(interface: &Interface, messages: &[Message], which: &str) -> TokenStream {
|
||||
if messages.is_empty() {
|
||||
return TokenStream::new();
|
||||
}
|
||||
|
||||
let types_arrays = messages.iter().filter_map(|msg| {
|
||||
if msg.all_null() {
|
||||
None
|
||||
} else {
|
||||
let array_ident = Ident::new(
|
||||
&format!("{}_{}_{}_types", interface.name, which, msg.name),
|
||||
Span::call_site(),
|
||||
);
|
||||
let array_len = Literal::usize_unsuffixed(msg.args.len());
|
||||
let array_values = msg.args.iter().map(|arg| match (arg.typ, &arg.interface) {
|
||||
(Type::Object, &Some(ref inter)) | (Type::NewId, &Some(ref inter)) => {
|
||||
let module = Ident::new(inter, Span::call_site());
|
||||
let interface_ident =
|
||||
Ident::new(&format!("{}_interface", inter), Span::call_site());
|
||||
quote!(unsafe { &super::#module::#interface_ident as *const wl_interface })
|
||||
}
|
||||
_ => quote!(NULLPTR as *const wl_interface),
|
||||
});
|
||||
|
||||
Some(quote! {
|
||||
static mut #array_ident: [*const wl_interface; #array_len] = [
|
||||
#(#array_values,)*
|
||||
];
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
let message_array_ident =
|
||||
Ident::new(&format!("{}_{}", interface.name, which), Span::call_site());
|
||||
let message_array_len = Literal::usize_unsuffixed(messages.len());
|
||||
let message_array_values = messages.iter().map(|msg| {
|
||||
let name_value = null_terminated_byte_string_literal(&msg.name);
|
||||
let signature_value = Literal::byte_string(&message_signature(msg));
|
||||
|
||||
let types_ident = if msg.all_null() {
|
||||
Ident::new("types_null", Span::call_site())
|
||||
} else {
|
||||
Ident::new(
|
||||
&format!("{}_{}_{}_types", interface.name, which, msg.name),
|
||||
Span::call_site(),
|
||||
)
|
||||
};
|
||||
|
||||
quote! {
|
||||
wl_message {
|
||||
name: #name_value as *const u8 as *const c_char,
|
||||
signature: #signature_value as *const u8 as *const c_char,
|
||||
types: unsafe { &#types_ident as *const _ },
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#(#types_arrays)*
|
||||
|
||||
/// C-representation of the messages of this interface, for interop
|
||||
pub static mut #message_array_ident: [wl_message; #message_array_len] = [
|
||||
#(#message_array_values,)*
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
fn message_signature(msg: &Message) -> Vec<u8> {
|
||||
let mut res = Vec::new();
|
||||
|
||||
if msg.since > 1 {
|
||||
res.extend_from_slice(msg.since.to_string().as_bytes());
|
||||
}
|
||||
|
||||
for arg in &msg.args {
|
||||
if arg.typ.nullable() && arg.allow_null {
|
||||
res.push(b'?');
|
||||
}
|
||||
match arg.typ {
|
||||
Type::NewId => {
|
||||
if arg.interface.is_none() {
|
||||
res.extend_from_slice(b"su");
|
||||
}
|
||||
res.push(b'n');
|
||||
}
|
||||
Type::Uint => res.push(b'u'),
|
||||
Type::Fixed => res.push(b'f'),
|
||||
Type::String => res.push(b's'),
|
||||
Type::Object => res.push(b'o'),
|
||||
Type::Array => res.push(b'a'),
|
||||
Type::Fd => res.push(b'h'),
|
||||
Type::Int => res.push(b'i'),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
res.push(0);
|
||||
res
|
||||
}
|
||||
897
third-party/vendor/wayland-scanner/src/common_gen.rs
vendored
Normal file
897
third-party/vendor/wayland-scanner/src/common_gen.rs
vendored
Normal file
|
|
@ -0,0 +1,897 @@
|
|||
#[allow(unused_imports)]
|
||||
#[allow(deprecated)]
|
||||
use std::ascii::AsciiExt;
|
||||
use std::iter;
|
||||
use std::str;
|
||||
|
||||
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
|
||||
use crate::protocol::*;
|
||||
use crate::util::*;
|
||||
use crate::Side;
|
||||
|
||||
pub(crate) fn to_doc_attr(text: &str) -> TokenStream {
|
||||
let text = text.lines().map(str::trim).collect::<Vec<_>>().join("\n");
|
||||
let text = text.trim();
|
||||
|
||||
quote!(#[doc = #text])
|
||||
}
|
||||
|
||||
pub(crate) fn description_to_doc_attr(&(ref short, ref long): &(String, String)) -> TokenStream {
|
||||
to_doc_attr(&format!("{}\n\n{}", short, long))
|
||||
}
|
||||
|
||||
impl ToTokens for Enum {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let enum_decl;
|
||||
let enum_impl;
|
||||
|
||||
let doc_attr = self.description.as_ref().map(description_to_doc_attr);
|
||||
let ident = Ident::new(&snake_to_camel(&self.name), Span::call_site());
|
||||
|
||||
if self.bitfield {
|
||||
let entries = self.entries.iter().map(|entry| {
|
||||
let doc_attr = entry
|
||||
.description
|
||||
.as_ref()
|
||||
.map(description_to_doc_attr)
|
||||
.or_else(|| entry.summary.as_ref().map(|s| to_doc_attr(s)));
|
||||
|
||||
let prefix = if entry.name.chars().next().unwrap().is_numeric() { "_" } else { "" };
|
||||
let ident = Ident::new(
|
||||
&format!("{}{}", prefix, snake_to_camel(&entry.name)),
|
||||
Span::call_site(),
|
||||
);
|
||||
|
||||
let value = Literal::u32_unsuffixed(entry.value);
|
||||
|
||||
quote! {
|
||||
#doc_attr
|
||||
const #ident = #value;
|
||||
}
|
||||
});
|
||||
|
||||
enum_decl = quote! {
|
||||
bitflags! {
|
||||
#doc_attr
|
||||
pub struct #ident: u32 {
|
||||
#(#entries)*
|
||||
}
|
||||
}
|
||||
};
|
||||
enum_impl = quote! {
|
||||
impl #ident {
|
||||
pub fn from_raw(n: u32) -> Option<#ident> {
|
||||
Some(#ident::from_bits_truncate(n))
|
||||
}
|
||||
|
||||
pub fn to_raw(&self) -> u32 {
|
||||
self.bits()
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
let variants = self.entries.iter().map(|entry| {
|
||||
let doc_attr = entry
|
||||
.description
|
||||
.as_ref()
|
||||
.map(description_to_doc_attr)
|
||||
.or_else(|| entry.summary.as_ref().map(|s| to_doc_attr(s)));
|
||||
|
||||
let prefix = if entry.name.chars().next().unwrap().is_numeric() { "_" } else { "" };
|
||||
let variant = Ident::new(
|
||||
&format!("{}{}", prefix, snake_to_camel(&entry.name)),
|
||||
Span::call_site(),
|
||||
);
|
||||
|
||||
let value = Literal::u32_unsuffixed(entry.value);
|
||||
|
||||
quote! {
|
||||
#doc_attr
|
||||
#variant = #value
|
||||
}
|
||||
});
|
||||
|
||||
enum_decl = quote! {
|
||||
#doc_attr
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum #ident {
|
||||
#(#variants,)*
|
||||
}
|
||||
};
|
||||
|
||||
let match_arms = self.entries.iter().map(|entry| {
|
||||
let value = Literal::u32_unsuffixed(entry.value);
|
||||
|
||||
let prefix = if entry.name.chars().next().unwrap().is_numeric() { "_" } else { "" };
|
||||
let variant = Ident::new(
|
||||
&format!("{}{}", prefix, snake_to_camel(&entry.name)),
|
||||
Span::call_site(),
|
||||
);
|
||||
|
||||
quote! {
|
||||
#value => Some(#ident::#variant)
|
||||
}
|
||||
});
|
||||
|
||||
enum_impl = quote! {
|
||||
impl #ident {
|
||||
pub fn from_raw(n: u32) -> Option<#ident> {
|
||||
match n {
|
||||
#(#match_arms,)*
|
||||
_ => Option::None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_raw(&self) -> u32 {
|
||||
*self as u32
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
enum_decl.to_tokens(tokens);
|
||||
enum_impl.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn gen_since_constants(requests: &[Message], events: &[Message]) -> TokenStream {
|
||||
let req_constants = requests.iter().map(|msg| {
|
||||
let cstname =
|
||||
Ident::new(&format!("REQ_{}_SINCE", msg.name.to_ascii_uppercase()), Span::call_site());
|
||||
let since = msg.since;
|
||||
quote! {
|
||||
/// The minimal object version supporting this request
|
||||
pub const #cstname: u32 = #since;
|
||||
}
|
||||
});
|
||||
let evt_constants = events.iter().map(|msg| {
|
||||
let cstname =
|
||||
Ident::new(&format!("EVT_{}_SINCE", msg.name.to_ascii_uppercase()), Span::call_site());
|
||||
let since = msg.since;
|
||||
quote! {
|
||||
/// The minimal object version supporting this event
|
||||
pub const #cstname: u32 = #since;
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#(#req_constants)*
|
||||
#(#evt_constants)*
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn gen_messagegroup(
|
||||
name: &Ident,
|
||||
side: Side,
|
||||
receiver: bool,
|
||||
messages: &[Message],
|
||||
addon: Option<TokenStream>,
|
||||
) -> TokenStream {
|
||||
let variants = messages.iter().map(|msg| {
|
||||
let mut docs = String::new();
|
||||
if let Some((ref short, ref long)) = msg.description {
|
||||
docs += &format!("{}\n\n{}\n", short, long.trim());
|
||||
}
|
||||
if let Some(Type::Destructor) = msg.typ {
|
||||
docs += &format!(
|
||||
"\nThis is a destructor, once {} this object cannot be used any longer.",
|
||||
if receiver { "received" } else { "sent" },
|
||||
);
|
||||
}
|
||||
if msg.since > 1 {
|
||||
docs += &format!("\nOnly available since version {} of the interface", msg.since);
|
||||
}
|
||||
|
||||
let doc_attr = to_doc_attr(&docs);
|
||||
let msg_name = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
|
||||
let msg_variant_decl = if msg.args.is_empty() {
|
||||
msg_name.into_token_stream()
|
||||
} else {
|
||||
let fields = msg.args.iter().flat_map(|arg| {
|
||||
let field_name = Ident::new(
|
||||
&format!("{}{}", if is_keyword(&arg.name) { "_" } else { "" }, arg.name),
|
||||
Span::call_site(),
|
||||
);
|
||||
let field_type_inner = if let Some(ref enu) = arg.enum_ {
|
||||
dotted_to_relname(enu)
|
||||
} else {
|
||||
match arg.typ {
|
||||
Type::Uint => quote!(u32),
|
||||
Type::Int => quote!(i32),
|
||||
Type::Fixed => quote!(f64),
|
||||
Type::String => quote!(String),
|
||||
Type::Array => quote!(Vec<u8>),
|
||||
Type::Fd => quote!(::std::os::unix::io::RawFd),
|
||||
Type::Object => {
|
||||
if let Some(ref iface) = arg.interface {
|
||||
let iface_mod = Ident::new(iface, Span::call_site());
|
||||
let iface_type =
|
||||
Ident::new(&snake_to_camel(iface), Span::call_site());
|
||||
quote!(super::#iface_mod::#iface_type)
|
||||
} else {
|
||||
quote!(AnonymousObject)
|
||||
}
|
||||
}
|
||||
Type::NewId if !receiver && side == Side::Client => {
|
||||
// Client-side sending does not have a pre-existing object
|
||||
// so skip serializing it
|
||||
if arg.interface.is_some() {
|
||||
return None;
|
||||
} else {
|
||||
quote!((String, u32))
|
||||
}
|
||||
}
|
||||
Type::NewId => {
|
||||
let object_name = if side == Side::Server && !receiver {
|
||||
Ident::new("Resource", Span::call_site())
|
||||
} else {
|
||||
Ident::new("Main", Span::call_site())
|
||||
};
|
||||
if let Some(ref iface) = arg.interface {
|
||||
let iface_mod = Ident::new(iface, Span::call_site());
|
||||
let iface_type =
|
||||
Ident::new(&snake_to_camel(iface), Span::call_site());
|
||||
quote!(#object_name<super::#iface_mod::#iface_type>)
|
||||
} else {
|
||||
// bind-like function
|
||||
quote!((String, u32, AnonymousObject))
|
||||
}
|
||||
}
|
||||
Type::Destructor => panic!("An argument cannot have type \"destructor\"."),
|
||||
}
|
||||
};
|
||||
|
||||
let field_type = if arg.allow_null {
|
||||
quote!(Option<#field_type_inner>)
|
||||
} else {
|
||||
field_type_inner.into_token_stream()
|
||||
};
|
||||
Some(quote! {
|
||||
#field_name: #field_type
|
||||
})
|
||||
});
|
||||
|
||||
quote! {
|
||||
#msg_name {
|
||||
#(#fields,)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#doc_attr
|
||||
#msg_variant_decl
|
||||
}
|
||||
});
|
||||
|
||||
let message_array_values = messages.iter().map(|msg| {
|
||||
let name_value = &msg.name;
|
||||
let since_value = Literal::u32_unsuffixed(msg.since);
|
||||
let signature_values = msg.args.iter().map(|arg| {
|
||||
let common_type = arg.typ.common_type();
|
||||
quote!(super::ArgumentType::#common_type)
|
||||
});
|
||||
let is_destructor = msg.typ == Some(Type::Destructor);
|
||||
|
||||
quote! {
|
||||
super::MessageDesc {
|
||||
name: #name_value,
|
||||
since: #since_value,
|
||||
signature: &[
|
||||
#(#signature_values,)*
|
||||
],
|
||||
destructor: #is_destructor,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let map_type = if side == Side::Client { quote!(ProxyMap) } else { quote!(ResourceMap) };
|
||||
|
||||
// Can't be a closure because closures are never Copy / Clone in rustc < 1.26.0, and we supports 1.21.0
|
||||
fn map_fn((msg, name): (&Message, &Ident)) -> TokenStream {
|
||||
let msg_type = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
|
||||
let msg_type_qualified = quote!(#name::#msg_type);
|
||||
|
||||
if msg.args.is_empty() {
|
||||
msg_type_qualified
|
||||
} else {
|
||||
quote!(#msg_type_qualified { .. })
|
||||
}
|
||||
}
|
||||
|
||||
let message_match_patterns = messages.iter().zip(iter::repeat(name)).map(map_fn);
|
||||
|
||||
let mut is_destructor_match_arms = messages
|
||||
.iter()
|
||||
.zip(message_match_patterns.clone())
|
||||
.filter(|&(msg, _)| msg.typ == Some(Type::Destructor))
|
||||
.map(|(_, pattern)| quote!(#pattern => true))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if messages.len() > is_destructor_match_arms.len() {
|
||||
is_destructor_match_arms.push(quote!(_ => false));
|
||||
}
|
||||
|
||||
let opcode_match_arms = message_match_patterns.clone().enumerate().map(|(opcode, pattern)| {
|
||||
let value = Literal::u16_unsuffixed(opcode as u16);
|
||||
quote!(#pattern => #value)
|
||||
});
|
||||
|
||||
let since_match_arms = messages.iter().zip(message_match_patterns).map(|(msg, pattern)| {
|
||||
let since = Literal::u32_unsuffixed(msg.since as u32);
|
||||
quote!(#pattern => #since)
|
||||
});
|
||||
|
||||
let child_match_arms = messages
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(opcode, msg)| {
|
||||
let mut it = msg.args.iter().filter_map(|a| {
|
||||
if a.typ == Type::NewId {
|
||||
a.interface.as_ref()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
it.next().map(|new_iface| {
|
||||
assert!(
|
||||
it.next().is_none(),
|
||||
"Got a message with more than one new_id in {}.{}",
|
||||
name,
|
||||
msg.name
|
||||
);
|
||||
|
||||
let pattern = Literal::u16_unsuffixed(opcode as u16);
|
||||
let new_iface_mod = Ident::new(new_iface, Span::call_site());
|
||||
let new_iface_type = Ident::new(&snake_to_camel(new_iface), Span::call_site());
|
||||
|
||||
quote! {
|
||||
#pattern => Some(Object::from_interface::<super::#new_iface_mod::#new_iface_type>(
|
||||
version,
|
||||
meta.child(),
|
||||
))
|
||||
}
|
||||
})
|
||||
})
|
||||
.chain(iter::once(quote!(_ => None)));
|
||||
|
||||
let from_raw_body = if receiver {
|
||||
let match_arms = messages
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(opcode, msg)| {
|
||||
let pattern = Literal::u16_unsuffixed(opcode as u16);
|
||||
let msg_type = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
|
||||
let msg_type_qualified = quote!(#name::#msg_type);
|
||||
|
||||
let block = if msg.args.is_empty() {
|
||||
quote!(Ok(#msg_type_qualified))
|
||||
} else {
|
||||
let fields = msg.args.iter().map(|arg| {
|
||||
let field_name = Ident::new(
|
||||
&format!("{}{}", if is_keyword(&arg.name) { "_" } else { "" }, arg.name),
|
||||
Span::call_site(),
|
||||
);
|
||||
let some_code_path = match arg.typ {
|
||||
Type::Int => {
|
||||
if let Some(ref enu) = arg.enum_ {
|
||||
let enum_ident = dotted_to_relname(enu);
|
||||
quote!(#enum_ident::from_raw(val as u32).ok_or(())?)
|
||||
} else {
|
||||
quote!(val)
|
||||
}
|
||||
}
|
||||
Type::Uint => {
|
||||
if let Some(ref enu) = arg.enum_ {
|
||||
let enum_ident = dotted_to_relname(enu);
|
||||
quote!(#enum_ident::from_raw(val).ok_or(())?)
|
||||
} else {
|
||||
quote!(val)
|
||||
}
|
||||
}
|
||||
Type::Fixed => quote!((val as f64) / 256.),
|
||||
Type::Array => {
|
||||
if arg.allow_null {
|
||||
quote!(if val.len() == 0 { None } else { Some(*val) })
|
||||
} else {
|
||||
quote!(*val)
|
||||
}
|
||||
}
|
||||
Type::String => {
|
||||
let string_conversion = quote! {
|
||||
let s = String::from_utf8(val.into_bytes())
|
||||
.unwrap_or_else(|e| String::from_utf8_lossy(&e.into_bytes()).into());
|
||||
};
|
||||
|
||||
if arg.allow_null {
|
||||
quote! {
|
||||
#string_conversion
|
||||
if s.len() == 0 { None } else { Some(s) }
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#string_conversion
|
||||
s
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::Fd => quote!(val),
|
||||
Type::Object => {
|
||||
let map_lookup = if side == Side::Client {
|
||||
quote!(map.get_or_dead(val).into())
|
||||
} else {
|
||||
quote!(map.get(val).ok_or(())?.into())
|
||||
};
|
||||
if arg.allow_null {
|
||||
quote!(if val == 0 { None } else { Some(#map_lookup) })
|
||||
} else {
|
||||
map_lookup
|
||||
}
|
||||
}
|
||||
Type::NewId => {
|
||||
let map_lookup = quote!(map.get_new(val).ok_or(())?);
|
||||
if arg.allow_null {
|
||||
quote!(if val == 0 { None } else { Some(#map_lookup) })
|
||||
} else {
|
||||
map_lookup
|
||||
}
|
||||
}
|
||||
Type::Destructor => panic!("An argument cannot have type destructor!"),
|
||||
};
|
||||
|
||||
let common_type = arg.typ.common_type();
|
||||
|
||||
quote! {
|
||||
#field_name: {
|
||||
if let Some(Argument::#common_type(val)) = args.next() {
|
||||
#some_code_path
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
{
|
||||
let mut args = msg.args.into_iter();
|
||||
|
||||
Ok(#msg_type_qualified {
|
||||
#(#fields,)*
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
quote!(#pattern => #block)
|
||||
})
|
||||
.chain(iter::once(quote!(_ => Err(()))));
|
||||
|
||||
quote! {
|
||||
match msg.opcode {
|
||||
#(#match_arms,)*
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let panic_message = format!("{}::from_raw can not be used {:?}-side.", name, side);
|
||||
quote!(panic!(#panic_message))
|
||||
};
|
||||
|
||||
let into_raw_body = if receiver {
|
||||
let panic_message = format!("{}::into_raw can not be used {:?}-side.", name, side);
|
||||
quote!(panic!(#panic_message))
|
||||
} else {
|
||||
let match_arms = messages.iter().enumerate().map(|(opcode, msg)| {
|
||||
let msg_type = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
|
||||
let msg_type_qualified = quote!(#name::#msg_type);
|
||||
|
||||
let pattern = if msg.args.is_empty() {
|
||||
msg_type_qualified
|
||||
} else {
|
||||
let fields = msg.args.iter().flat_map(|arg| {
|
||||
// Client-side newid request do not contain a placeholder
|
||||
if side == Side::Client && arg.typ == Type::NewId && arg.interface.is_some() {
|
||||
None
|
||||
} else {
|
||||
Some(Ident::new(
|
||||
&format!("{}{}", if is_keyword(&arg.name) { "_" } else { "" }, arg.name),
|
||||
Span::call_site(),
|
||||
))
|
||||
}
|
||||
});
|
||||
quote!(#msg_type_qualified { #(#fields),* })
|
||||
};
|
||||
|
||||
let opcode_value = Literal::u16_unsuffixed(opcode as u16);
|
||||
let args_values = msg.args.iter().map(|arg| {
|
||||
let arg_ident = Ident::new(
|
||||
&format!("{}{}", if is_keyword(&arg.name) { "_" } else { "" }, arg.name),
|
||||
Span::call_site(),
|
||||
);
|
||||
match arg.typ {
|
||||
Type::Int => {
|
||||
if arg.enum_.is_some() {
|
||||
quote!(Argument::Int(#arg_ident.to_raw() as i32))
|
||||
} else {
|
||||
quote!(Argument::Int(#arg_ident))
|
||||
}
|
||||
}
|
||||
Type::Uint => {
|
||||
if arg.enum_.is_some() {
|
||||
quote!(Argument::Uint(#arg_ident.to_raw()))
|
||||
} else {
|
||||
quote!(Argument::Uint(#arg_ident))
|
||||
}
|
||||
}
|
||||
Type::Fixed => quote!(Argument::Fixed((#arg_ident * 256.) as i32)),
|
||||
Type::String => {
|
||||
if arg.allow_null {
|
||||
quote! {
|
||||
Argument::Str(Box::new(unsafe {
|
||||
::std::ffi::CString::from_vec_unchecked(
|
||||
#arg_ident.map(Into::into).unwrap_or_else(Vec::new),
|
||||
)
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
Argument::Str(Box::new(unsafe {
|
||||
::std::ffi::CString::from_vec_unchecked(#arg_ident.into())
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::Array => {
|
||||
if arg.allow_null {
|
||||
quote!(Argument::Array(Box::new(#arg_ident.unwrap_or_else(Vec::new))))
|
||||
} else {
|
||||
quote!(Argument::Array(Box::new(#arg_ident)))
|
||||
}
|
||||
}
|
||||
Type::Fd => quote!(Argument::Fd(#arg_ident)),
|
||||
Type::NewId => {
|
||||
if arg.interface.is_some() {
|
||||
let id = if side == Side::Client {
|
||||
quote!(0)
|
||||
} else {
|
||||
quote!(#arg_ident.id())
|
||||
};
|
||||
quote!(Argument::NewId(#id))
|
||||
} else {
|
||||
let id = if side == Side::Client {
|
||||
quote!(0)
|
||||
} else {
|
||||
quote!(#arg_ident.2.id())
|
||||
};
|
||||
quote! {
|
||||
Argument::Str(Box::new(unsafe {
|
||||
::std::ffi::CString::from_vec_unchecked(#arg_ident.0.into())
|
||||
})),
|
||||
Argument::Uint(#arg_ident.1),
|
||||
Argument::NewId(#id)
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::Object => {
|
||||
if arg.allow_null {
|
||||
quote!(Argument::Object(#arg_ident.map(|o| o.as_ref().id()).unwrap_or(0)))
|
||||
} else {
|
||||
quote!(Argument::Object(#arg_ident.as_ref().id()))
|
||||
}
|
||||
}
|
||||
Type::Destructor => panic!("An argument cannot have type Destructor"),
|
||||
}
|
||||
});
|
||||
|
||||
quote!(#pattern => Message {
|
||||
sender_id: sender_id,
|
||||
opcode: #opcode_value,
|
||||
args: smallvec![
|
||||
#(#args_values,)*
|
||||
],
|
||||
})
|
||||
});
|
||||
|
||||
quote! {
|
||||
match self {
|
||||
#(#match_arms,)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum #name {
|
||||
#(#variants,)*
|
||||
}
|
||||
|
||||
impl super::MessageGroup for #name {
|
||||
const MESSAGES: &'static [super::MessageDesc] = &[
|
||||
#(#message_array_values,)*
|
||||
];
|
||||
|
||||
type Map = super::#map_type;
|
||||
|
||||
fn is_destructor(&self) -> bool {
|
||||
match *self {
|
||||
#(#is_destructor_match_arms,)*
|
||||
}
|
||||
}
|
||||
|
||||
fn opcode(&self) -> u16 {
|
||||
match *self {
|
||||
#(#opcode_match_arms,)*
|
||||
}
|
||||
}
|
||||
|
||||
fn since(&self) -> u32 {
|
||||
match *self {
|
||||
#(#since_match_arms,)*
|
||||
}
|
||||
}
|
||||
|
||||
fn child<Meta: ObjectMetadata>(opcode: u16, version: u32, meta: &Meta) -> Option<Object<Meta>> {
|
||||
match opcode {
|
||||
#(#child_match_arms,)*
|
||||
}
|
||||
}
|
||||
|
||||
fn from_raw(msg: Message, map: &mut Self::Map) -> Result<Self, ()> {
|
||||
#from_raw_body
|
||||
}
|
||||
|
||||
fn into_raw(self, sender_id: u32) -> Message {
|
||||
#into_raw_body
|
||||
}
|
||||
|
||||
#addon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn gen_interface(
|
||||
name: &Ident,
|
||||
low_name: &str,
|
||||
version: u32,
|
||||
addon: Option<TokenStream>,
|
||||
side: Side,
|
||||
) -> TokenStream {
|
||||
let object_type = side.object_name();
|
||||
let version_lit = Literal::u32_unsuffixed(version);
|
||||
|
||||
quote! {
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct #name(#object_type<#name>);
|
||||
|
||||
impl AsRef<#object_type<#name>> for #name {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &#object_type<Self> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<#object_type<#name>> for #name {
|
||||
#[inline]
|
||||
fn from(value: #object_type<Self>) -> Self {
|
||||
#name(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<#name> for #object_type<#name> {
|
||||
#[inline]
|
||||
fn from(value: #name) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for #name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("{:?}", self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Interface for #name {
|
||||
type Request = Request;
|
||||
type Event = Event;
|
||||
const NAME: &'static str = #low_name;
|
||||
const VERSION: u32 = #version_lit;
|
||||
|
||||
#addon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn method_prototype<'a>(
|
||||
iname: &Ident,
|
||||
msg: &'a Message,
|
||||
side: Side,
|
||||
) -> (TokenStream, Option<&'a Arg>) {
|
||||
let mut it = msg.args.iter().filter(|arg| arg.typ == Type::NewId);
|
||||
let mut newid = it.next();
|
||||
assert!(
|
||||
newid.is_none() || it.next().is_none(),
|
||||
"Request {}.{} returns more than one new_id",
|
||||
iname,
|
||||
msg.name
|
||||
);
|
||||
|
||||
// Serverside we don't deal with NewId arguments and treat them as objects.
|
||||
if side == Side::Server {
|
||||
newid = None;
|
||||
}
|
||||
|
||||
let fn_name = Ident::new(
|
||||
&format!("{}{}", if is_keyword(&msg.name) { "_" } else { "" }, msg.name),
|
||||
Span::call_site(),
|
||||
);
|
||||
|
||||
let mut args = Vec::new();
|
||||
|
||||
let generics = if let Some(arg) = newid {
|
||||
if arg.interface.is_none() {
|
||||
args.push(quote!(version: u32));
|
||||
Some(quote!(T: Interface + From<Proxy<T>> + AsRef<Proxy<T>>))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
.into_iter();
|
||||
|
||||
args.extend(msg.args.iter().filter_map(|arg| {
|
||||
let arg_type_inner = if let Some(ref name) = arg.enum_ {
|
||||
dotted_to_relname(name)
|
||||
} else {
|
||||
let mut typ = arg.typ;
|
||||
if typ == Type::NewId && side == Side::Server {
|
||||
typ = Type::Object;
|
||||
}
|
||||
match typ {
|
||||
Type::Object => arg
|
||||
.interface
|
||||
.as_ref()
|
||||
.map(|iface| {
|
||||
let iface_mod = Ident::new(iface, Span::call_site());
|
||||
let iface_type = Ident::new(&snake_to_camel(iface), Span::call_site());
|
||||
quote!(&super::#iface_mod::#iface_type)
|
||||
})
|
||||
.unwrap_or(quote!(&super::AnonymousObject)),
|
||||
Type::NewId => {
|
||||
// client-side, the return-type handles that
|
||||
return None;
|
||||
}
|
||||
_ => arg.typ.rust_type(),
|
||||
}
|
||||
};
|
||||
|
||||
let arg_name = Ident::new(
|
||||
&format!("{}{}", if is_keyword(&arg.name) { "_" } else { "" }, arg.name),
|
||||
Span::call_site(),
|
||||
);
|
||||
|
||||
let arg_type =
|
||||
if arg.allow_null { quote!(Option<#arg_type_inner>) } else { arg_type_inner };
|
||||
|
||||
Some(quote!(#arg_name: #arg_type))
|
||||
}));
|
||||
|
||||
let return_type = if let Some(arg) = newid {
|
||||
match arg.interface {
|
||||
Some(ref iface) => {
|
||||
let iface_mod = Ident::new(iface, Span::call_site());
|
||||
let iface_type = Ident::new(&snake_to_camel(iface), Span::call_site());
|
||||
|
||||
quote!(Main<super::#iface_mod::#iface_type>)
|
||||
}
|
||||
None => quote!(Main<T>),
|
||||
}
|
||||
} else {
|
||||
quote!(())
|
||||
};
|
||||
|
||||
let prototype = quote! {
|
||||
pub fn #fn_name#(<#generics>)*(&self, #(#args),*) -> #return_type
|
||||
};
|
||||
|
||||
(prototype, newid)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_object_methods(name: &Ident, messages: &[Message], side: Side) -> TokenStream {
|
||||
let outgoing_message_type = Ident::new(
|
||||
match side {
|
||||
Side::Client => "Request",
|
||||
Side::Server => "Event",
|
||||
},
|
||||
Span::call_site(),
|
||||
);
|
||||
|
||||
let method_impls = messages.iter().map(|msg| {
|
||||
let mut docs = String::new();
|
||||
if let Some((ref short, ref long)) = msg.description {
|
||||
docs += &format!("{}\n\n{}\n", short, long);
|
||||
}
|
||||
if let Some(Type::Destructor) = msg.typ {
|
||||
docs += "\nThis is a destructor, you cannot send requests to this object any longer once this method is called.";
|
||||
}
|
||||
if msg.since > 1 {
|
||||
docs += &format!("\nOnly available since version {} of the interface.", msg.since);
|
||||
}
|
||||
|
||||
let doc_attr = to_doc_attr(&docs);
|
||||
|
||||
let msg_name = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
|
||||
let (proto, return_type) = method_prototype(name, msg, side);
|
||||
|
||||
let msg_init = if msg.args.is_empty() {
|
||||
TokenStream::new()
|
||||
} else {
|
||||
let args = msg.args.iter().flat_map(|arg| {
|
||||
let arg_name = Ident::new(
|
||||
&format!("{}{}", if is_keyword(&arg.name) { "_" } else { "" }, arg.name),
|
||||
Span::call_site(),
|
||||
);
|
||||
let arg_value = match (arg.typ, side) {
|
||||
(Type::NewId, Side::Client) => {
|
||||
if arg.interface.is_some() {
|
||||
return None;
|
||||
} else {
|
||||
quote!((T::NAME.into(), version))
|
||||
}
|
||||
},
|
||||
(Type::NewId, Side::Server) => {
|
||||
if arg.allow_null {
|
||||
quote!(#arg_name.map(|o| o.as_ref().clone()))
|
||||
} else {
|
||||
quote!(#arg_name.as_ref().clone())
|
||||
}
|
||||
}
|
||||
(Type::Object, _) => {
|
||||
if arg.allow_null {
|
||||
quote!(#arg_name.map(|o| o.clone()))
|
||||
} else {
|
||||
quote!(#arg_name.clone())
|
||||
}
|
||||
}
|
||||
_ => quote!(#arg_name),
|
||||
};
|
||||
|
||||
Some(quote!(#arg_name: #arg_value))
|
||||
});
|
||||
|
||||
quote!({ #(#args),* })
|
||||
};
|
||||
|
||||
let send_stmt = match return_type {
|
||||
Some(ret_type) if ret_type.interface.is_none() => {
|
||||
quote!(self.0.send(msg, Some(version)).unwrap())
|
||||
}
|
||||
Some(_) => quote!(self.0.send(msg, None).unwrap()),
|
||||
None => if side == Side::Client {
|
||||
quote! { self.0.send::<AnonymousObject>(msg, None); }
|
||||
} else {
|
||||
quote! { self.0.send(msg); }
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#doc_attr
|
||||
#proto {
|
||||
let msg = #outgoing_message_type::#msg_name #msg_init;
|
||||
#send_stmt
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
impl #name {
|
||||
#(#method_impls)*
|
||||
}
|
||||
}
|
||||
}
|
||||
203
third-party/vendor/wayland-scanner/src/lib.rs
vendored
Normal file
203
third-party/vendor/wayland-scanner/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
//! Wayland scanner crate
|
||||
//!
|
||||
//!
|
||||
//! This crate is a rust equivalent of the wayland-scanner tool from the
|
||||
//! official wayland C library.
|
||||
//!
|
||||
//! You can use in your build script to generate the rust code for any
|
||||
//! wayland protocol file, to use alongside the `wayland_client` and
|
||||
//! `wayland_server` crate to build your applications.
|
||||
//!
|
||||
//! ## How to use this crate
|
||||
//!
|
||||
//! This crate is to be used in a build script. It provides the function `generate_code`.
|
||||
//! It'll allow you to generate the code to use with the `wayland_client` or
|
||||
//! `wayland_server` crates for any XML wayland protocol file (NB: you don't
|
||||
//! need to do it for the core protocol, which is already included in both crates).
|
||||
//!
|
||||
//! First, have the XML files you want to use in your project, somewhere the build script
|
||||
//! will be able to read them.
|
||||
//!
|
||||
//! Then, you'll need to invoke `generate_code` for each of these files.
|
||||
//!
|
||||
//! A sample build script:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! extern crate wayland_scanner;
|
||||
//!
|
||||
//! use std::env::var;
|
||||
//! use std::path::Path;
|
||||
//!
|
||||
//! use wayland_scanner::{Side, generate_code};
|
||||
//!
|
||||
//! // Location of the xml file, relative to the `Cargo.toml`
|
||||
//! let protocol_file = "./my_protocol.xml";
|
||||
//!
|
||||
//! // Target directory for the generate files
|
||||
//! let out_dir_str = var("OUT_DIR").unwrap();
|
||||
//! let out_dir = Path::new(&out_dir_str);
|
||||
//!
|
||||
//! generate_code(
|
||||
//! protocol_file,
|
||||
//! out_dir.join("my_protocol_api.rs"),
|
||||
//! Side::Client, // Replace by `Side::Server` for server-side code
|
||||
//! );
|
||||
//! ```
|
||||
//!
|
||||
//! The above example will output a `.rs` file in the `OUT_DIR` defined by
|
||||
//! cargo. Then, you'll need to include this generated file (using the
|
||||
//! macro of the same name) to make this code available in your crate.
|
||||
//!
|
||||
//! ```ignore
|
||||
//! // The generated code will import stuff from wayland_commons
|
||||
//! extern crate wayland_commons;
|
||||
//! extern crate wayland_client;
|
||||
//!
|
||||
//! // Re-export only the actual code, and then only use this re-export
|
||||
//! // The `generated` module below is just some boilerplate to properly isolate stuff
|
||||
//! // and avoid exposing internal details.
|
||||
//! //
|
||||
//! // You can use all the types from my_protocol as if they went from `wayland_client::protocol`.
|
||||
//! pub use generated::client as my_protocol;
|
||||
//!
|
||||
//! mod generated {
|
||||
//! // The generated code tends to trigger a lot of warnings
|
||||
//! // so we isolate it into a very permissive module
|
||||
//! #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
|
||||
//! #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
|
||||
//!
|
||||
//! pub mod client {
|
||||
//! // These imports are used by the generated code
|
||||
//! pub(crate) use wayland_client::{Main, Attached, Proxy, ProxyMap, AnonymousObject};
|
||||
//! pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
|
||||
//! pub(crate) use wayland_commons::{Interface, MessageGroup};
|
||||
//! pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
|
||||
//! pub(crate) use wayland_commons::smallvec;
|
||||
//! pub(crate) use wayland_client::protocol::{$($import),*};
|
||||
//! pub(crate) use wayland_client::sys;
|
||||
//! // If you protocol interacts with objects from other protocols, you'll need to import
|
||||
//! // their modules, like so:
|
||||
//! pub(crate) use wayland_client::protocol::{wl_surface, wl_region};
|
||||
//! include!(concat!(env!("OUT_DIR"), "/my_protocol_code.rs"));
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![warn(missing_docs)]
|
||||
// disable clippy lints that are not compatible with rust 1.41
|
||||
#![allow(clippy::match_like_matches_macro)]
|
||||
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
mod c_code_gen;
|
||||
mod c_interface_gen;
|
||||
mod common_gen;
|
||||
mod parse;
|
||||
mod protocol;
|
||||
mod side;
|
||||
mod util;
|
||||
|
||||
pub use side::Side;
|
||||
|
||||
fn load_xml<P: AsRef<Path>>(prot: P) -> protocol::Protocol {
|
||||
let pfile = File::open(prot.as_ref())
|
||||
.unwrap_or_else(|_| panic!("Unable to open protocol file `{}`.", prot.as_ref().display()));
|
||||
parse::parse_stream(pfile)
|
||||
}
|
||||
|
||||
/// Generate the code for a protocol
|
||||
///
|
||||
/// See this crate toplevel documentation for details.
|
||||
///
|
||||
/// Args:
|
||||
///
|
||||
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
|
||||
/// the build script using this function.
|
||||
/// - `target`: the path of the file to store the code in.
|
||||
/// - `side`: the side (client or server) to generate code for.
|
||||
pub fn generate_code<P1: AsRef<Path>, P2: AsRef<Path>>(prot: P1, target: P2, side: Side) {
|
||||
generate_code_with_destructor_events(prot, target, side, &[]);
|
||||
}
|
||||
|
||||
/// Generate the code for a protocol with aditionnal destructor events
|
||||
///
|
||||
/// Same as `generate_code`, but allows you to additionnaly specify some events
|
||||
/// (in the format `("interface_name", "event_name")`) as being destructor, as this
|
||||
/// information is not encoded in the protocol files but instead written in the
|
||||
/// protocol documentation.
|
||||
pub fn generate_code_with_destructor_events<P1: AsRef<Path>, P2: AsRef<Path>>(
|
||||
prot: P1,
|
||||
target: P2,
|
||||
side: Side,
|
||||
events: &[(&str, &str)],
|
||||
) {
|
||||
let mut protocol = load_xml(prot);
|
||||
|
||||
for interface in &mut protocol.interfaces {
|
||||
for event in &mut interface.events {
|
||||
if events.contains(&(&interface.name, &event.name)) {
|
||||
event.typ = Some(crate::protocol::Type::Destructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut out =
|
||||
OpenOptions::new().write(true).truncate(true).create(true).open(&target).unwrap();
|
||||
|
||||
let output = match side {
|
||||
Side::Client => c_code_gen::generate_protocol_client(protocol),
|
||||
Side::Server => c_code_gen::generate_protocol_server(protocol),
|
||||
};
|
||||
|
||||
write!(&mut out, "{}", output).unwrap();
|
||||
}
|
||||
|
||||
let _ = Command::new("rustfmt").arg(target.as_ref()).status();
|
||||
}
|
||||
|
||||
/// Generate the code for a protocol from/to IO streams
|
||||
///
|
||||
/// Like `generate_code`, but takes IO Streams directly rather than filenames
|
||||
///
|
||||
/// Args:
|
||||
///
|
||||
/// - `protocol`: an object `Read`-able containing the XML protocol file
|
||||
/// - `target`: a `Write`-able object to which the generated code will be outputted to
|
||||
/// - `side`: the side (client or server) to generate code for.
|
||||
pub fn generate_code_streams<P1: Read, P2: Write>(protocol: P1, target: &mut P2, side: Side) {
|
||||
generate_code_streams_with_destructor_events(protocol, target, side, &[])
|
||||
}
|
||||
|
||||
/// Generate the code for a protocol from/to IO streams with aditionnal destructor events
|
||||
///
|
||||
/// Same as `generate_code_streams`, but allows you to additionnaly specify some events
|
||||
/// (in the format `("interface_name", "event_name")`) as being destructor, as this
|
||||
/// information is not encoded in the protocol files but instead written in the documentation
|
||||
/// of the protocol.
|
||||
pub fn generate_code_streams_with_destructor_events<P1: Read, P2: Write>(
|
||||
protocol: P1,
|
||||
target: &mut P2,
|
||||
side: Side,
|
||||
events: &[(&str, &str)],
|
||||
) {
|
||||
let mut protocol = parse::parse_stream(protocol);
|
||||
|
||||
for interface in &mut protocol.interfaces {
|
||||
for event in &mut interface.events {
|
||||
if events.contains(&(&interface.name, &event.name)) {
|
||||
event.typ = Some(crate::protocol::Type::Destructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let output = match side {
|
||||
Side::Client => c_code_gen::generate_protocol_client(protocol),
|
||||
Side::Server => c_code_gen::generate_protocol_server(protocol),
|
||||
};
|
||||
|
||||
write!(target, "{}", output).unwrap();
|
||||
}
|
||||
298
third-party/vendor/wayland-scanner/src/parse.rs
vendored
Normal file
298
third-party/vendor/wayland-scanner/src/parse.rs
vendored
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
use crate::protocol::*;
|
||||
use std::io::Read;
|
||||
use xml::attribute::OwnedAttribute;
|
||||
use xml::reader::ParserConfig;
|
||||
use xml::reader::XmlEvent;
|
||||
use xml::EventReader;
|
||||
|
||||
macro_rules! extract_from(
|
||||
($it: expr => $pattern: pat => $result: expr) => (
|
||||
match $it.next() {
|
||||
Ok($pattern) => { $result },
|
||||
e => panic!("Ill-formed protocol file: {:?}", e)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
macro_rules! extract_end_tag(
|
||||
($it: expr => $tag: expr) => (
|
||||
extract_from!($it => XmlEvent::EndElement { name } => {
|
||||
assert!(name.local_name == $tag, "Ill-formed protocol file");
|
||||
});
|
||||
)
|
||||
);
|
||||
|
||||
pub fn parse_stream<S: Read>(stream: S) -> Protocol {
|
||||
let mut reader =
|
||||
EventReader::new_with_config(stream, ParserConfig::new().trim_whitespace(true));
|
||||
reader.next().expect("Could not read from event reader");
|
||||
parse_protocol(reader)
|
||||
}
|
||||
|
||||
fn parse_protocol<R: Read>(mut reader: EventReader<R>) -> Protocol {
|
||||
let mut protocol = extract_from!(
|
||||
reader => XmlEvent::StartElement { name, attributes, .. } => {
|
||||
assert!(name.local_name == "protocol", "Missing protocol toplevel tag");
|
||||
assert!(attributes[0].name.local_name == "name", "Protocol must have a name");
|
||||
Protocol::new(attributes[0].value.clone())
|
||||
}
|
||||
);
|
||||
|
||||
loop {
|
||||
match reader.next() {
|
||||
Ok(XmlEvent::StartElement { name, attributes, .. }) => {
|
||||
match &name.local_name[..] {
|
||||
"copyright" => {
|
||||
// parse the copyright
|
||||
let copyright = match reader.next() {
|
||||
Ok(XmlEvent::Characters(copyright))
|
||||
| Ok(XmlEvent::CData(copyright)) => copyright,
|
||||
e => panic!("Ill-formed protocol file: {:?}", e),
|
||||
};
|
||||
|
||||
extract_end_tag!(reader => "copyright");
|
||||
protocol.copyright = Some(copyright);
|
||||
}
|
||||
"interface" => {
|
||||
protocol.interfaces.push(parse_interface(&mut reader, attributes));
|
||||
}
|
||||
"description" => {
|
||||
protocol.description = Some(parse_description(&mut reader, attributes));
|
||||
}
|
||||
_ => panic!(
|
||||
"Ill-formed protocol file: unexpected token `{}` in protocol {}",
|
||||
name.local_name, protocol.name
|
||||
),
|
||||
}
|
||||
}
|
||||
Ok(XmlEvent::EndElement { name }) => {
|
||||
assert!(
|
||||
name.local_name == "protocol",
|
||||
"Unexpected closing token `{}`",
|
||||
name.local_name
|
||||
);
|
||||
break;
|
||||
}
|
||||
e => panic!("Ill-formed protocol file: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
protocol
|
||||
}
|
||||
|
||||
fn parse_interface<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Interface {
|
||||
let mut interface = Interface::new();
|
||||
for attr in attrs {
|
||||
match &attr.name.local_name[..] {
|
||||
"name" => interface.name = attr.value,
|
||||
"version" => interface.version = attr.value.parse().unwrap(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match reader.next() {
|
||||
Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
|
||||
"description" => {
|
||||
interface.description = Some(parse_description(reader, attributes))
|
||||
}
|
||||
"request" => interface.requests.push(parse_request(reader, attributes)),
|
||||
"event" => interface.events.push(parse_event(reader, attributes)),
|
||||
"enum" => interface.enums.push(parse_enum(reader, attributes)),
|
||||
_ => panic!("Unexpected tocken: `{}`", name.local_name),
|
||||
},
|
||||
Ok(XmlEvent::EndElement { ref name }) if name.local_name == "interface" => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
interface
|
||||
}
|
||||
|
||||
fn parse_description<R: Read>(
|
||||
reader: &mut EventReader<R>,
|
||||
attrs: Vec<OwnedAttribute>,
|
||||
) -> (String, String) {
|
||||
let mut summary = String::new();
|
||||
for attr in attrs {
|
||||
if &attr.name.local_name[..] == "summary" {
|
||||
summary = attr.value.split_whitespace().collect::<Vec<_>>().join(" ");
|
||||
}
|
||||
}
|
||||
|
||||
let description = match reader.next() {
|
||||
Ok(XmlEvent::Characters(txt)) => {
|
||||
extract_end_tag!(reader => "description");
|
||||
txt
|
||||
}
|
||||
Ok(XmlEvent::EndElement { ref name }) if name.local_name == "description" => String::new(),
|
||||
e => panic!("Ill-formed protocol file: {:?}", e),
|
||||
};
|
||||
|
||||
(summary, description)
|
||||
}
|
||||
|
||||
fn parse_request<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Message {
|
||||
let mut request = Message::new();
|
||||
for attr in attrs {
|
||||
match &attr.name.local_name[..] {
|
||||
"name" => request.name = attr.value,
|
||||
"type" => request.typ = Some(parse_type(&attr.value)),
|
||||
"since" => request.since = attr.value.parse().unwrap(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match reader.next() {
|
||||
Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
|
||||
"description" => request.description = Some(parse_description(reader, attributes)),
|
||||
"arg" => request.args.push(parse_arg(reader, attributes)),
|
||||
_ => panic!("Unexpected tocken: `{}`", name.local_name),
|
||||
},
|
||||
Ok(XmlEvent::EndElement { ref name }) if name.local_name == "request" => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
request
|
||||
}
|
||||
|
||||
fn parse_enum<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Enum {
|
||||
let mut enu = Enum::new();
|
||||
for attr in attrs {
|
||||
match &attr.name.local_name[..] {
|
||||
"name" => enu.name = attr.value,
|
||||
"since" => enu.since = attr.value.parse().unwrap(),
|
||||
"bitfield" => {
|
||||
if &attr.value[..] == "true" {
|
||||
enu.bitfield = true
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match reader.next() {
|
||||
Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
|
||||
"description" => enu.description = Some(parse_description(reader, attributes)),
|
||||
"entry" => enu.entries.push(parse_entry(reader, attributes)),
|
||||
_ => panic!("Unexpected tocken: `{}`", name.local_name),
|
||||
},
|
||||
Ok(XmlEvent::EndElement { ref name }) if name.local_name == "enum" => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
enu
|
||||
}
|
||||
|
||||
fn parse_event<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Message {
|
||||
let mut event = Message::new();
|
||||
for attr in attrs {
|
||||
match &attr.name.local_name[..] {
|
||||
"name" => event.name = attr.value,
|
||||
"type" => event.typ = Some(parse_type(&attr.value)),
|
||||
"since" => event.since = attr.value.parse().unwrap(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match reader.next() {
|
||||
Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
|
||||
"description" => event.description = Some(parse_description(reader, attributes)),
|
||||
"arg" => event.args.push(parse_arg(reader, attributes)),
|
||||
_ => panic!("Unexpected tocken: `{}`", name.local_name),
|
||||
},
|
||||
Ok(XmlEvent::EndElement { ref name }) if name.local_name == "event" => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
event
|
||||
}
|
||||
|
||||
fn parse_arg<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Arg {
|
||||
let mut arg = Arg::new();
|
||||
for attr in attrs {
|
||||
match &attr.name.local_name[..] {
|
||||
"name" => arg.name = attr.value,
|
||||
"type" => arg.typ = parse_type(&attr.value),
|
||||
"summary" => {
|
||||
arg.summary = Some(attr.value.split_whitespace().collect::<Vec<_>>().join(" "))
|
||||
}
|
||||
"interface" => arg.interface = Some(attr.value),
|
||||
"allow-null" => {
|
||||
if attr.value == "true" {
|
||||
arg.allow_null = true
|
||||
}
|
||||
}
|
||||
"enum" => arg.enum_ = Some(attr.value),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match reader.next() {
|
||||
Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
|
||||
"description" => arg.description = Some(parse_description(reader, attributes)),
|
||||
_ => panic!("Unexpected tocken: `{}`", name.local_name),
|
||||
},
|
||||
Ok(XmlEvent::EndElement { ref name }) if name.local_name == "arg" => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
arg
|
||||
}
|
||||
|
||||
fn parse_type(txt: &str) -> Type {
|
||||
match txt {
|
||||
"int" => Type::Int,
|
||||
"uint" => Type::Uint,
|
||||
"fixed" => Type::Fixed,
|
||||
"string" => Type::String,
|
||||
"object" => Type::Object,
|
||||
"new_id" => Type::NewId,
|
||||
"array" => Type::Array,
|
||||
"fd" => Type::Fd,
|
||||
"destructor" => Type::Destructor,
|
||||
e => panic!("Unexpected type: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_entry<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Entry {
|
||||
let mut entry = Entry::new();
|
||||
for attr in attrs {
|
||||
match &attr.name.local_name[..] {
|
||||
"name" => entry.name = attr.value,
|
||||
"value" => {
|
||||
entry.value = if attr.value.starts_with("0x") {
|
||||
u32::from_str_radix(&attr.value[2..], 16).unwrap()
|
||||
} else {
|
||||
attr.value.parse().unwrap()
|
||||
};
|
||||
}
|
||||
"since" => entry.since = attr.value.parse().unwrap(),
|
||||
"summary" => {
|
||||
entry.summary = Some(attr.value.split_whitespace().collect::<Vec<_>>().join(" "))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match reader.next() {
|
||||
Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
|
||||
"description" => entry.description = Some(parse_description(reader, attributes)),
|
||||
_ => panic!("Unexpected tocken: `{}`", name.local_name),
|
||||
},
|
||||
Ok(XmlEvent::EndElement { ref name }) if name.local_name == "entry" => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
entry
|
||||
}
|
||||
178
third-party/vendor/wayland-scanner/src/protocol.rs
vendored
Normal file
178
third-party/vendor/wayland-scanner/src/protocol.rs
vendored
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Protocol {
|
||||
pub name: String,
|
||||
pub copyright: Option<String>,
|
||||
pub description: Option<(String, String)>,
|
||||
pub interfaces: Vec<Interface>,
|
||||
}
|
||||
|
||||
impl Protocol {
|
||||
pub fn new(name: String) -> Protocol {
|
||||
Protocol { name, copyright: None, description: None, interfaces: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Interface {
|
||||
pub name: String,
|
||||
pub version: u32,
|
||||
pub description: Option<(String, String)>,
|
||||
pub requests: Vec<Message>,
|
||||
pub events: Vec<Message>,
|
||||
pub enums: Vec<Enum>,
|
||||
}
|
||||
|
||||
impl Interface {
|
||||
pub fn new() -> Interface {
|
||||
Interface {
|
||||
name: String::new(),
|
||||
version: 1,
|
||||
description: None,
|
||||
requests: Vec::new(),
|
||||
events: Vec::new(),
|
||||
enums: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Message {
|
||||
pub name: String,
|
||||
pub typ: Option<Type>,
|
||||
pub since: u32,
|
||||
pub description: Option<(String, String)>,
|
||||
pub args: Vec<Arg>,
|
||||
pub type_index: usize,
|
||||
}
|
||||
|
||||
impl Message {
|
||||
pub fn new() -> Message {
|
||||
Message {
|
||||
name: String::new(),
|
||||
typ: None,
|
||||
since: 1,
|
||||
description: None,
|
||||
args: Vec::new(),
|
||||
type_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_null(&self) -> bool {
|
||||
self.args
|
||||
.iter()
|
||||
.all(|a| !((a.typ == Type::Object || a.typ == Type::NewId) && a.interface.is_some()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Arg {
|
||||
pub name: String,
|
||||
pub typ: Type,
|
||||
pub interface: Option<String>,
|
||||
pub summary: Option<String>,
|
||||
pub description: Option<(String, String)>,
|
||||
pub allow_null: bool,
|
||||
pub enum_: Option<String>,
|
||||
}
|
||||
|
||||
impl Arg {
|
||||
pub fn new() -> Arg {
|
||||
Arg {
|
||||
name: String::new(),
|
||||
typ: Type::Object,
|
||||
interface: None,
|
||||
summary: None,
|
||||
description: None,
|
||||
allow_null: false,
|
||||
enum_: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Enum {
|
||||
pub name: String,
|
||||
pub since: u16,
|
||||
pub description: Option<(String, String)>,
|
||||
pub entries: Vec<Entry>,
|
||||
pub bitfield: bool,
|
||||
}
|
||||
|
||||
impl Enum {
|
||||
pub fn new() -> Enum {
|
||||
Enum {
|
||||
name: String::new(),
|
||||
since: 1,
|
||||
description: None,
|
||||
entries: Vec::new(),
|
||||
bitfield: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Entry {
|
||||
pub name: String,
|
||||
pub value: u32,
|
||||
pub since: u16,
|
||||
pub description: Option<(String, String)>,
|
||||
pub summary: Option<String>,
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
pub fn new() -> Entry {
|
||||
Entry { name: String::new(), value: 0, since: 1, description: None, summary: None }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum Type {
|
||||
Int,
|
||||
Uint,
|
||||
Fixed,
|
||||
String,
|
||||
Object,
|
||||
NewId,
|
||||
Array,
|
||||
Fd,
|
||||
Destructor,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn nullable(self) -> bool {
|
||||
match self {
|
||||
Type::String | Type::Object | Type::NewId | Type::Array => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rust_type(self) -> TokenStream {
|
||||
match self {
|
||||
Type::Int => quote!(i32),
|
||||
Type::Uint => quote!(u32),
|
||||
Type::Fixed => quote!(f64),
|
||||
Type::Array => quote!(Vec<u8>),
|
||||
Type::Fd => quote!(::std::os::unix::io::RawFd),
|
||||
Type::String => quote!(String),
|
||||
Type::Object => quote!(ProxyId),
|
||||
_ => quote!(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn common_type(self) -> TokenStream {
|
||||
match self {
|
||||
Type::Int => quote!(Int),
|
||||
Type::Uint => quote!(Uint),
|
||||
Type::Fixed => quote!(Fixed),
|
||||
Type::Array => quote!(Array),
|
||||
Type::Fd => quote!(Fd),
|
||||
Type::String => quote!(Str),
|
||||
Type::Object => quote!(Object),
|
||||
Type::NewId => quote!(NewId),
|
||||
Type::Destructor => panic!("Destructor is not a valid argument type."),
|
||||
}
|
||||
}
|
||||
}
|
||||
27
third-party/vendor/wayland-scanner/src/side.rs
vendored
Normal file
27
third-party/vendor/wayland-scanner/src/side.rs
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use proc_macro2::{Ident, Span};
|
||||
|
||||
use self::Side::{Client, Server};
|
||||
|
||||
/// Side to generate
|
||||
///
|
||||
/// This enum represents the two possible sides of
|
||||
/// the protocol API that can be generated.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Side {
|
||||
/// wayland client applications
|
||||
Client,
|
||||
/// wayland compositors
|
||||
Server,
|
||||
}
|
||||
|
||||
impl Side {
|
||||
pub(crate) fn object_name(self) -> Ident {
|
||||
Ident::new(
|
||||
match self {
|
||||
Client => "Proxy",
|
||||
Server => "Resource",
|
||||
},
|
||||
Span::call_site(),
|
||||
)
|
||||
}
|
||||
}
|
||||
68
third-party/vendor/wayland-scanner/src/util.rs
vendored
Normal file
68
third-party/vendor/wayland-scanner/src/util.rs
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||
use quote::ToTokens;
|
||||
|
||||
pub fn is_keyword(txt: &str) -> bool {
|
||||
match txt {
|
||||
"abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue"
|
||||
| "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if"
|
||||
| "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut"
|
||||
| "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" | "return"
|
||||
| "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" | "true"
|
||||
| "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while"
|
||||
| "yield" | "__handler" | "__object" => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_camel_keyword(txt: &str) -> bool {
|
||||
match txt {
|
||||
"Self" => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn snake_to_camel(input: &str) -> String {
|
||||
let result = input
|
||||
.split('_')
|
||||
.flat_map(|s| {
|
||||
let mut first = true;
|
||||
s.chars().map(move |c| {
|
||||
if first {
|
||||
first = false;
|
||||
c.to_ascii_uppercase()
|
||||
} else {
|
||||
c
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect::<String>();
|
||||
|
||||
if is_camel_keyword(&result) {
|
||||
format!("_{}", &result)
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dotted_to_relname(input: &str) -> TokenStream {
|
||||
let mut it = input.split('.');
|
||||
match (it.next(), it.next()) {
|
||||
(Some(module), Some(name)) => {
|
||||
let module = Ident::new(module, Span::call_site());
|
||||
let ident = Ident::new(&snake_to_camel(name), Span::call_site());
|
||||
quote::quote!(super::#module::#ident)
|
||||
}
|
||||
(Some(name), None) => {
|
||||
Ident::new(&snake_to_camel(name), Span::call_site()).into_token_stream()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn null_terminated_byte_string_literal(string: &str) -> Literal {
|
||||
let mut val = Vec::with_capacity(string.len() + 1);
|
||||
val.extend_from_slice(string.as_bytes());
|
||||
val.push(0);
|
||||
|
||||
Literal::byte_string(&val)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue