core: Add client code generation (#6)

Adds a `--client` flag for client code
This commit is contained in:
Vaxry 2024-06-20 00:17:58 +02:00 committed by GitHub
parent 1419520d5f
commit 38140181fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -9,30 +9,29 @@
#include <filesystem> #include <filesystem>
bool waylandEnums = false; bool waylandEnums = false;
bool clientCode = false;
bool noInterfaces = false;
struct SRequestArgument { struct SRequestArgument {
std::string wlType; std::string wlType;
std::string interface; std::string interface;
std::string enumName; std::string enumName;
std::string name; std::string name;
bool newType = false;
bool allowNull = false; bool allowNull = false;
}; };
struct SRequest { struct SWaylandFunction {
std::vector<SRequestArgument> args;
std::string name;
std::string since;
};
struct SEvent {
std::vector<SRequestArgument> args; std::vector<SRequestArgument> args;
std::string name; std::string name;
std::string since; std::string since;
std::string newIdType = ""; // client only
bool destructor = false;
}; };
struct SInterface { struct SInterface {
std::vector<SRequest> requests; std::vector<SWaylandFunction> requests;
std::vector<SEvent> events; std::vector<SWaylandFunction> events;
std::string name; std::string name;
int version = 1; int version = 1;
}; };
@ -187,12 +186,17 @@ void parseXML(pugi::xml_document& doc) {
} }
for (auto& rq : iface.children("request")) { for (auto& rq : iface.children("request")) {
SRequest srq; SWaylandFunction srq;
srq.name = rq.attribute("name").as_string(); srq.name = rq.attribute("name").as_string();
srq.since = rq.attribute("since").as_string(); srq.since = rq.attribute("since").as_string();
srq.destructor = rq.attribute("type").as_string() == std::string{"destructor"};
for (auto& arg : rq.children("arg")) { for (auto& arg : rq.children("arg")) {
SRequestArgument sargm; SRequestArgument sargm;
if (arg.attribute("type").as_string() == std::string{"new_id"} && clientCode)
srq.newIdType = arg.attribute("interface").as_string();
sargm.newType = arg.attribute("type").as_string() == std::string{"new_id"} && clientCode;
sargm.name = sanitize(arg.attribute("name").as_string()); sargm.name = sanitize(arg.attribute("name").as_string());
sargm.wlType = arg.attribute("type").as_string(); sargm.wlType = arg.attribute("type").as_string();
sargm.interface = arg.attribute("interface").as_string(); sargm.interface = arg.attribute("interface").as_string();
@ -206,9 +210,10 @@ void parseXML(pugi::xml_document& doc) {
} }
for (auto& ev : iface.children("event")) { for (auto& ev : iface.children("event")) {
SEvent sev; SWaylandFunction sev;
sev.name = ev.attribute("name").as_string(); sev.name = ev.attribute("name").as_string();
sev.since = ev.attribute("since").as_string(); sev.since = ev.attribute("since").as_string();
sev.destructor = ev.attribute("type").as_string() == std::string{"destructor"};
for (auto& arg : ev.children("arg")) { for (auto& arg : ev.children("arg")) {
SRequestArgument sargm; SRequestArgument sargm;
@ -231,19 +236,20 @@ void parseXML(pugi::xml_document& doc) {
void parseHeader() { void parseHeader() {
// add some boilerplate // add some boilerplate
HEADER += R"#(#pragma once HEADER += std::format(R"#(#pragma once
#include <functional> #include <functional>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <wayland-server.h> {}
#define F std::function #define F std::function
struct wl_client; {}
struct wl_resource;
)#"; )#",
(clientCode ? "#include <wayland-client.h>" : "#include <wayland-server.h>"),
(clientCode ? "struct wl_proxy;\ntypedef wl_proxy wl_resource;" : "struct wl_client;\nstruct wl_resource;"));
// parse all enums // parse all enums
if (!waylandEnums) { if (!waylandEnums) {
@ -294,12 +300,18 @@ struct wl_resource;
const auto IFACE_CLASS_NAME_CAMEL = camelize("C_" + iface.name); const auto IFACE_CLASS_NAME_CAMEL = camelize("C_" + iface.name);
// begin the class // begin the class
HEADER += std::format(R"#( HEADER +=
std::format(R"#(
class {} {{ class {} {{
public: public:
{}(wl_client* client, uint32_t version, uint32_t id); {}({});
~{}(); ~{}();
)#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, (clientCode ? "wl_resource*" : "wl_client* client, uint32_t version, uint32_t id"), IFACE_CLASS_NAME_CAMEL);
if (!clientCode) {
HEADER += std::format(R"#(
// set a listener for when this resource is _being_ destroyed // set a listener for when this resource is _being_ destroyed
void setOnDestroy(F<void({}*)> handler) {{ void setOnDestroy(F<void({}*)> handler) {{
onDestroy = handler; onDestroy = handler;
@ -339,17 +351,41 @@ class {} {{
int version() {{ int version() {{
return wl_resource_get_version(pResource); return wl_resource_get_version(pResource);
}} }}
)#", )#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL); IFACE_CLASS_NAME_CAMEL);
} else {
HEADER += R"#(
// set the data for this resource
void setData(void* data) {{
pData = data;
}}
// get the data for this resource
void* data() {{
return pData;
}}
// get the raw wl_resource (wl_proxy) ptr
wl_resource* resource() {{
return pResource;
}}
// get the resource version
int version() {{
return wl_proxy_get_version(pResource);
}}
)#";
}
// add all setters for requests // add all setters for requests
HEADER += "\n // --------------- Requests --------------- //\n\n"; HEADER += "\n // --------------- Requests --------------- //\n\n";
for (auto& rq : iface.requests) { for (auto& rq : (clientCode ? iface.events : iface.requests)) {
std::string args = ", "; std::string args = ", ";
for (auto& arg : rq.args) { for (auto& arg : rq.args) {
if (arg.newType)
continue;
args += WPTypeToCType(arg, false) + ", "; args += WPTypeToCType(arg, false) + ", ";
} }
@ -363,9 +399,11 @@ class {} {{
HEADER += "\n // --------------- Events --------------- //\n\n"; HEADER += "\n // --------------- Events --------------- //\n\n";
for (auto& ev : iface.events) { for (auto& ev : (!clientCode ? iface.events : iface.requests)) {
std::string args = ""; std::string args = "";
for (auto& arg : ev.args) { for (auto& arg : ev.args) {
if (arg.newType)
continue;
args += WPTypeToCType(arg, true) + ", "; args += WPTypeToCType(arg, true) + ", ";
} }
@ -374,13 +412,16 @@ class {} {{
args.pop_back(); args.pop_back();
} }
HEADER += std::format(" void {}({});\n", camelize("send_" + ev.name), args); HEADER += std::format(" {} {}({});\n", ev.newIdType.empty() ? "void" : "wl_proxy*", camelize("send_" + ev.name), args);
} }
// dangerous ones // dangerous ones
for (auto& ev : iface.events) { if (!clientCode) {
for (auto& ev : (!clientCode ? iface.events : iface.requests)) {
std::string args = ""; std::string args = "";
for (auto& arg : ev.args) { for (auto& arg : ev.args) {
if (arg.newType)
continue;
args += WPTypeToCType(arg, true, true) + ", "; args += WPTypeToCType(arg, true, true) + ", ";
} }
@ -391,6 +432,7 @@ class {} {{
HEADER += std::format(" void {}({});\n", camelize("send_" + ev.name + "_raw"), args); HEADER += std::format(" void {}({});\n", camelize("send_" + ev.name + "_raw"), args);
} }
}
// end events // end events
@ -400,10 +442,12 @@ class {} {{
// start requests storage // start requests storage
HEADER += " struct {\n"; HEADER += " struct {\n";
for (auto& rq : iface.requests) { for (auto& rq : (clientCode ? iface.events : iface.requests)) {
std::string args = ", "; std::string args = ", ";
for (auto& arg : rq.args) { for (auto& arg : rq.args) {
if (arg.newType)
continue;
args += WPTypeToCType(arg, false) + ", "; args += WPTypeToCType(arg, false) + ", ";
} }
@ -419,6 +463,7 @@ class {} {{
HEADER += " } requests;\n"; HEADER += " } requests;\n";
// constant resource stuff // constant resource stuff
if (!clientCode) {
HEADER += std::format(R"#( HEADER += std::format(R"#(
void onDestroyCalled(); void onDestroyCalled();
@ -430,6 +475,12 @@ class {} {{
void* pData = nullptr;)#", void* pData = nullptr;)#",
IFACE_CLASS_NAME_CAMEL); IFACE_CLASS_NAME_CAMEL);
} else {
HEADER += R"#(
wl_resource* pResource = nullptr;
void* pData = nullptr;)#";
}
HEADER += "\n};\n\n"; HEADER += "\n};\n\n";
} }
@ -513,11 +564,13 @@ static const wl_interface* dummyTypes[] = { nullptr };
const auto IFACE_CLASS_NAME_CAMEL = camelize("C_" + iface.name); const auto IFACE_CLASS_NAME_CAMEL = camelize("C_" + iface.name);
// create handlers // create handlers
for (auto& rq : iface.requests) { for (auto& rq : (clientCode ? iface.events : iface.requests)) {
const auto REQUEST_NAME = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_" + rq.name); const auto REQUEST_NAME = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_" + rq.name);
std::string argsC = ", "; std::string argsC = ", ";
for (auto& arg : rq.args) { for (auto& arg : rq.args) {
if (arg.newType)
continue;
argsC += WPTypeToCType(arg, false) + " " + arg.name + ", "; argsC += WPTypeToCType(arg, false) + " " + arg.name + ", ";
} }
@ -534,6 +587,7 @@ static const wl_interface* dummyTypes[] = { nullptr };
argsN.pop_back(); argsN.pop_back();
} }
if (!clientCode) {
SOURCE += std::format(R"#( SOURCE += std::format(R"#(
static void {}(wl_client* client, wl_resource* resource{}) {{ static void {}(wl_client* client, wl_resource* resource{}) {{
const auto PO = ({}*)wl_resource_get_user_data(resource); const auto PO = ({}*)wl_resource_get_user_data(resource);
@ -542,9 +596,20 @@ static void {}(wl_client* client, wl_resource* resource{}) {{
}} }}
)#", )#",
REQUEST_NAME, argsC, IFACE_CLASS_NAME_CAMEL, camelize(rq.name), camelize(rq.name), argsN); REQUEST_NAME, argsC, IFACE_CLASS_NAME_CAMEL, camelize(rq.name), camelize(rq.name), argsN);
} else {
SOURCE += std::format(R"#(
static void {}(void* data, void* resource{}) {{
const auto PO = ({}*)data;
if (PO && PO->requests.{})
PO->requests.{}(PO{});
}}
)#",
REQUEST_NAME, argsC, IFACE_CLASS_NAME_CAMEL, camelize(rq.name), camelize(rq.name), argsN);
}
} }
// destroy handler // destroy handler
if (!clientCode) {
SOURCE += std::format(R"#( SOURCE += std::format(R"#(
static void _{}__DestroyListener(wl_listener* l, void* d) {{ static void _{}__DestroyListener(wl_listener* l, void* d) {{
{}* pResource = wl_container_of(l, pResource, resourceDestroyListener); {}* pResource = wl_container_of(l, pResource, resourceDestroyListener);
@ -552,6 +617,7 @@ static void _{}__DestroyListener(wl_listener* l, void* d) {{
}} }}
)#", )#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL); IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
}
// create vtable // create vtable
@ -562,7 +628,7 @@ static const void* {}[] = {{
)#", )#",
IFACE_VTABLE_NAME); IFACE_VTABLE_NAME);
for (auto& rq : iface.requests) { for (auto& rq : (clientCode ? iface.events : iface.requests)) {
const auto REQUEST_NAME = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_" + rq.name); const auto REQUEST_NAME = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_" + rq.name);
SOURCE += std::format(" (void*){},\n", REQUEST_NAME); SOURCE += std::format(" (void*){},\n", REQUEST_NAME);
} }
@ -572,11 +638,13 @@ static const void* {}[] = {{
// create events // create events
int evid = 0; int evid = 0;
for (auto& ev : iface.events) { for (auto& ev : (!clientCode ? iface.events : iface.requests)) {
const auto EVENT_NAME = camelize("send_" + ev.name); const auto EVENT_NAME = camelize("send_" + ev.name);
std::string argsC = ""; std::string argsC = "";
for (auto& arg : ev.args) { for (auto& arg : ev.args) {
if (arg.newType)
continue;
argsC += WPTypeToCType(arg, true) + " " + arg.name + ", "; argsC += WPTypeToCType(arg, true) + " " + arg.name + ", ";
} }
@ -587,15 +655,18 @@ static const void* {}[] = {{
std::string argsN = ", "; std::string argsN = ", ";
for (auto& arg : ev.args) { for (auto& arg : ev.args) {
if (arg.newType)
continue;
if (!WPTypeToCType(arg, true).starts_with("C")) if (!WPTypeToCType(arg, true).starts_with("C"))
argsN += arg.name + ", "; argsN += arg.name + ", ";
else else
argsN += arg.name + "->pResource, "; argsN += (arg.name + " ? " + arg.name + "->pResource : nullptr, ");
} }
argsN.pop_back(); argsN.pop_back();
argsN.pop_back(); argsN.pop_back();
if (!clientCode) {
SOURCE += std::format(R"#( SOURCE += std::format(R"#(
void {}::{}({}) {{ void {}::{}({}) {{
if (!pResource) if (!pResource)
@ -604,17 +675,36 @@ void {}::{}({}) {{
}} }}
)#", )#",
IFACE_CLASS_NAME_CAMEL, EVENT_NAME, argsC, evid, argsN); IFACE_CLASS_NAME_CAMEL, EVENT_NAME, argsC, evid, argsN);
} else {
std::string retType = ev.newIdType.empty() ? "void" : "wl_proxy";
std::string ptrRetType = ev.newIdType.empty() ? "void" : "wl_proxy*";
std::string flags = ev.destructor ? "1" : "0";
SOURCE += std::format(R"#(
{} {}::{}({}) {{
if (!pResource)
return{};
auto proxy = wl_proxy_marshal_flags((wl_proxy*)pResource, {}, {}, wl_proxy_get_version((wl_proxy*)pResource), {}{}{});{}
}}
)#",
ptrRetType, IFACE_CLASS_NAME_CAMEL, EVENT_NAME, argsC, (ev.newIdType.empty() ? "" : " nullptr"), evid,
(ev.newIdType.empty() ? "nullptr" : "&" + ev.newIdType + "_interface"), flags, (!ev.newIdType.empty() ? ", nullptr" : ""), argsN,
(ev.newIdType.empty() ? "\n proxy;" : "\n\n return proxy;"));
}
evid++; evid++;
} }
// dangerous // dangerous
if (!clientCode) {
evid = 0; evid = 0;
for (auto& ev : iface.events) { for (auto& ev : iface.events) {
const auto EVENT_NAME = camelize("send_" + ev.name + "_raw"); const auto EVENT_NAME = camelize("send_" + ev.name + "_raw");
std::string argsC = ""; std::string argsC = "";
for (auto& arg : ev.args) { for (auto& arg : ev.args) {
if (arg.newType)
continue;
argsC += WPTypeToCType(arg, true, true) + " " + arg.name + ", "; argsC += WPTypeToCType(arg, true, true) + " " + arg.name + ", ";
} }
@ -625,6 +715,8 @@ void {}::{}({}) {{
std::string argsN = ", "; std::string argsN = ", ";
for (auto& arg : ev.args) { for (auto& arg : ev.args) {
if (arg.newType)
continue;
argsN += arg.name + ", "; argsN += arg.name + ", ";
} }
@ -642,6 +734,7 @@ void {}::{}({}) {{
evid++; evid++;
} }
}
// wayland interfaces and stuff // wayland interfaces and stuff
@ -687,6 +780,7 @@ void {}::{}({}) {{
const auto MESSAGE_NAME_EVENTS = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_events"); const auto MESSAGE_NAME_EVENTS = camelize(std::string{"_"} + "C_" + IFACE_NAME + "_events");
// message // message
if (!noInterfaces) {
if (iface.requests.size() > 0) { if (iface.requests.size() > 0) {
SOURCE += std::format(R"#( SOURCE += std::format(R"#(
static const wl_message {}[] = {{ static const wl_message {}[] = {{
@ -725,10 +819,12 @@ const wl_interface {} = {{
{}, {}, {}, {},
}}; }};
)#", )#",
IFACE_WL_NAME, iface.name, iface.version, iface.requests.size(), (iface.requests.size() > 0 ? MESSAGE_NAME_REQUESTS : "nullptr"), iface.events.size(), IFACE_WL_NAME, iface.name, iface.version, iface.requests.size(), (iface.requests.size() > 0 ? MESSAGE_NAME_REQUESTS : "nullptr"),
(iface.events.size() > 0 ? MESSAGE_NAME_EVENTS : "nullptr")); iface.events.size(), (iface.events.size() > 0 ? MESSAGE_NAME_EVENTS : "nullptr"));
}
// protocol body // protocol body
if (!clientCode) {
SOURCE += std::format(R"#( SOURCE += std::format(R"#(
{}::{}(wl_client* client, uint32_t version, uint32_t id) {{ {}::{}(wl_client* client, uint32_t version, uint32_t id) {{
pResource = wl_resource_create(client, &{}, version, id); pResource = wl_resource_create(client, &{}, version, id);
@ -772,8 +868,26 @@ void {}::onDestroyCalled() {{
)#", )#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_NAME + "_interface", IFACE_CLASS_NAME_CAMEL, IFACE_VTABLE_NAME, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_NAME + "_interface", IFACE_CLASS_NAME_CAMEL, IFACE_VTABLE_NAME, IFACE_CLASS_NAME_CAMEL,
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL); IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
} else {
SOURCE += std::format(R"#(
{}::{}(wl_resource* resource) {{
pResource = resource;
for (auto& rq : iface.requests) { if (!pResource)
return;
wl_proxy_set_user_data(pResource, this);
wl_proxy_add_listener(pResource, (void (**)(void))&{}, this);
}}
{}::~{}() {{
;
}}
)#",
IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL, IFACE_VTABLE_NAME, IFACE_CLASS_NAME_CAMEL, IFACE_CLASS_NAME_CAMEL);
}
for (auto& rq : (clientCode ? iface.events : iface.requests)) {
std::string args = ", "; std::string args = ", ";
for (auto& arg : rq.args) { for (auto& arg : rq.args) {
args += WPTypeToCType(arg, false) + ", "; args += WPTypeToCType(arg, false) + ", ";
@ -808,6 +922,16 @@ int main(int argc, char** argv, char** envp) {
return 0; return 0;
} }
if (curarg == "-c" || curarg == "--client") {
clientCode = true;
continue;
}
if (curarg == "--no-interfaces") {
noInterfaces = true;
continue;
}
if (curarg == "--wayland-enums") { if (curarg == "--wayland-enums") {
waylandEnums = true; waylandEnums = true;
continue; continue;