TypeBuilder_cpp.template 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. // This file is generated by TypeBuilder_cpp.template.
  2. // Copyright (c) 2016 The Chromium Authors. All rights reserved.
  3. // Use of this source code is governed by a BSD-style license that can be
  4. // found in the LICENSE file.
  5. #include {{format_domain_include(config.protocol.package, domain.domain)}}
  6. #include {{format_include(config.protocol.package, "Protocol")}}
  7. #include "{{config.crdtp.dir}}/cbor.h"
  8. #include "{{config.crdtp.dir}}/find_by_first.h"
  9. #include "{{config.crdtp.dir}}/span.h"
  10. {% for namespace in config.protocol.namespace %}
  11. namespace {{namespace}} {
  12. {% endfor %}
  13. namespace {{domain.domain}} {
  14. using {{config.crdtp.namespace}}::DeserializerState;
  15. using {{config.crdtp.namespace}}::ProtocolTypeTraits;
  16. // ------------- Enum values from types.
  17. const char Metainfo::domainName[] = "{{domain.domain}}";
  18. const char Metainfo::commandPrefix[] = "{{domain.domain}}.";
  19. const char Metainfo::version[] = "{{domain.version}}";
  20. {% for type in domain.types %}
  21. {% if not protocol.generate_type(domain.domain, type.id) %}{% continue %} {% endif %}
  22. {% if "enum" in type %}
  23. namespace {{type.id}}Enum {
  24. {% for literal in type.enum %}
  25. const char {{ literal | dash_to_camelcase}}[] = "{{literal}}";
  26. {% endfor %}
  27. } // namespace {{type.id}}Enum
  28. {% if protocol.is_exported(domain.domain, type.id) %}
  29. namespace API {
  30. namespace {{type.id}}Enum {
  31. {% for literal in type.enum %}
  32. const char* {{ literal | dash_to_camelcase}} = "{{literal}}";
  33. {% endfor %}
  34. } // namespace {{type.id}}Enum
  35. } // namespace API
  36. {% endif %}
  37. {% endif %}
  38. {% for property in type.properties %}
  39. {% if "enum" in property %}
  40. {% for literal in property.enum %}
  41. const char* {{type.id}}::{{property.name | to_title_case}}Enum::{{literal | dash_to_camelcase}} = "{{literal}}";
  42. {% endfor %}
  43. {% endif %}
  44. {% endfor %}
  45. {% if not (type.type == "object") or not ("properties" in type) %}{% continue %}{% endif %}
  46. CRDTP_BEGIN_DESERIALIZER({{type.id}})
  47. {% for property in type.properties | sort(attribute = 'name', case_sensitive=True) %}
  48. {% if property.optional %}
  49. CRDTP_DESERIALIZE_FIELD_OPT("{{property.name}}", m_{{property.name}}),
  50. {% else %}
  51. CRDTP_DESERIALIZE_FIELD("{{property.name}}", m_{{property.name}}),
  52. {% endif %}
  53. {% endfor %}
  54. CRDTP_END_DESERIALIZER()
  55. CRDTP_BEGIN_SERIALIZER({{type.id}})
  56. {% for property in type.properties %}
  57. CRDTP_SERIALIZE_FIELD("{{property.name}}", m_{{property.name}});
  58. {% endfor %}
  59. CRDTP_END_SERIALIZER();
  60. {% if protocol.is_exported(domain.domain, type.id) %}
  61. // static
  62. std::unique_ptr<API::{{type.id}}> API::{{type.id}}::fromBinary(const uint8_t* data, size_t length)
  63. {
  64. return protocol::{{domain.domain}}::{{type.id}}::FromBinary(data, length);
  65. }
  66. {% endif %}
  67. {% endfor %}
  68. // ------------- Enum values from params.
  69. {% for command in join_arrays(domain, ["commands", "events"]) %}
  70. {% for param in join_arrays(command, ["parameters", "returns"]) %}
  71. {% if "enum" in param %}
  72. namespace {{command.name | to_title_case}} {
  73. namespace {{param.name | to_title_case}}Enum {
  74. {% for literal in param.enum %}
  75. const char* {{ literal | to_title_case}} = "{{literal}}";
  76. {% endfor %}
  77. } // namespace {{param.name | to_title_case}}Enum
  78. } // namespace {{command.name | to_title_case }}
  79. {% if protocol.is_exported(domain.domain, command.name + "." + param.name) %}
  80. namespace API {
  81. namespace {{command.name | to_title_case}} {
  82. namespace {{param.name | to_title_case}}Enum {
  83. {% for literal in param.enum %}
  84. const char* {{ literal | to_title_case}} = "{{literal}}";
  85. {% endfor %}
  86. } // namespace {{param.name | to_title_case}}Enum
  87. } // namespace {{command.name | to_title_case }}
  88. } // namespace API
  89. {% endif %}
  90. {% endif %}
  91. {% endfor %}
  92. {% endfor %}
  93. // ------------- Frontend notifications.
  94. {% for event in domain.events %}
  95. {% if not protocol.generate_event(domain.domain, event.name) %}{% continue %}{% endif %}
  96. void Frontend::{{event.name | to_method_case}}(
  97. {%- for parameter in event.parameters %}
  98. {% if "optional" in parameter -%}
  99. Maybe<{{protocol.resolve_type(parameter).raw_type}}>
  100. {%- else -%}
  101. {{protocol.resolve_type(parameter).pass_type}}
  102. {%- endif %} {{parameter.name}}{%- if not loop.last -%}, {% endif -%}
  103. {% endfor -%})
  104. {
  105. if (!frontend_channel_)
  106. return;
  107. {% if event.parameters %}
  108. {{config.crdtp.namespace}}::ObjectSerializer serializer;
  109. {% for parameter in event.parameters %}
  110. serializer.AddField({{config.crdtp.namespace}}::MakeSpan("{{parameter.name}}"), {{parameter.name}});
  111. {% endfor %}
  112. frontend_channel_->SendProtocolNotification({{config.crdtp.namespace}}::CreateNotification("{{domain.domain}}.{{event.name}}", serializer.Finish()));
  113. {% else %}
  114. frontend_channel_->SendProtocolNotification({{config.crdtp.namespace}}::CreateNotification("{{domain.domain}}.{{event.name}}"));
  115. {% endif %}
  116. }
  117. {% endfor %}
  118. void Frontend::flush()
  119. {
  120. frontend_channel_->FlushProtocolNotifications();
  121. }
  122. void Frontend::sendRawNotification(std::unique_ptr<Serializable> notification)
  123. {
  124. frontend_channel_->SendProtocolNotification(std::move(notification));
  125. }
  126. // --------------------- Dispatcher.
  127. class DomainDispatcherImpl : public protocol::DomainDispatcher {
  128. public:
  129. DomainDispatcherImpl(FrontendChannel* frontendChannel, Backend* backend)
  130. : DomainDispatcher(frontendChannel)
  131. , m_backend(backend) {}
  132. ~DomainDispatcherImpl() override { }
  133. using CallHandler = void (DomainDispatcherImpl::*)(const {{config.crdtp.namespace}}::Dispatchable& dispatchable);
  134. std::function<void(const {{config.crdtp.namespace}}::Dispatchable&)> Dispatch({{config.crdtp.namespace}}::span<uint8_t> command_name) override;
  135. {% for command in domain.commands %}
  136. {% if "redirect" in command %}{% continue %}{% endif %}
  137. {% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %}
  138. void {{command.name}}(const {{config.crdtp.namespace}}::Dispatchable& dispatchable);
  139. {% endfor %}
  140. protected:
  141. Backend* m_backend;
  142. };
  143. namespace {
  144. // This helper method with a static map of command methods (instance methods
  145. // of DomainDispatcherImpl declared just above) by their name is used immediately below,
  146. // in the DomainDispatcherImpl::Dispatch method.
  147. DomainDispatcherImpl::CallHandler CommandByName({{config.crdtp.namespace}}::span<uint8_t> command_name) {
  148. static auto* commands = [](){
  149. auto* commands = new std::vector<std::pair<{{config.crdtp.namespace}}::span<uint8_t>,
  150. DomainDispatcherImpl::CallHandler>>{
  151. {% for command in domain.commands|sort(attribute="name",case_sensitive=True) %}
  152. {% if "redirect" in command %}{% continue %}{% endif %}
  153. {% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %}
  154. {
  155. {{config.crdtp.namespace}}::SpanFrom("{{command.name}}"),
  156. &DomainDispatcherImpl::{{command.name}}
  157. },
  158. {% endfor %}
  159. };
  160. return commands;
  161. }();
  162. return {{config.crdtp.namespace}}::FindByFirst<DomainDispatcherImpl::CallHandler>(*commands, command_name, nullptr);
  163. }
  164. } // namespace
  165. std::function<void(const {{config.crdtp.namespace}}::Dispatchable&)> DomainDispatcherImpl::Dispatch({{config.crdtp.namespace}}::span<uint8_t> command_name) {
  166. CallHandler handler = CommandByName(command_name);
  167. if (!handler) return nullptr;
  168. return [this, handler](const {{config.crdtp.namespace}}::Dispatchable& dispatchable) {
  169. (this->*handler)(dispatchable);
  170. };
  171. }
  172. {% for command in domain.commands %}
  173. {% set command_name_title = command.name | to_title_case %}
  174. {% if "redirect" in command %}{% continue %}{% endif %}
  175. {% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %}
  176. {% if protocol.is_async_command(domain.domain, command.name) %}
  177. class {{command_name_title}}CallbackImpl : public Backend::{{command_name_title}}Callback, public DomainDispatcher::Callback {
  178. public:
  179. {{command_name_title}}CallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, int callId, {{config.crdtp.namespace}}::span<uint8_t> message)
  180. : DomainDispatcher::Callback(std::move(backendImpl), callId,
  181. {{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}.{{command.name}}"), message) { }
  182. void sendSuccess(
  183. {%- for parameter in command.returns -%}
  184. {%- if "optional" in parameter -%}
  185. Maybe<{{protocol.resolve_type(parameter).raw_type}}> {{parameter.name}}
  186. {%- else -%}
  187. {{protocol.resolve_type(parameter).pass_type}} {{parameter.name}}
  188. {%- endif -%}
  189. {%- if not loop.last -%}, {% endif -%}
  190. {%- endfor -%}) override
  191. {
  192. {{config.crdtp.namespace}}::ObjectSerializer serializer;
  193. {% for parameter in command.returns %}
  194. serializer.AddField({{config.crdtp.namespace}}::MakeSpan("{{parameter.name}}"), {{parameter.name}});
  195. {% endfor %}
  196. sendIfActive(serializer.Finish(), DispatchResponse::Success());
  197. }
  198. void fallThrough() override
  199. {
  200. fallThroughIfActive();
  201. }
  202. void sendFailure(const DispatchResponse& response) override
  203. {
  204. DCHECK(response.IsError());
  205. sendIfActive(nullptr, response);
  206. }
  207. };
  208. {% endif %}
  209. namespace {
  210. {% if "parameters" in command %}
  211. struct {{command.name}}Params : public {{config.crdtp.namespace}}::DeserializableProtocolObject<{{command.name}}Params> {
  212. {% for parameter in command.parameters %}
  213. {% set parameter_type = protocol.resolve_type(parameter) %}
  214. {% if parameter.optional %}
  215. Maybe<{{parameter_type.raw_type}}> {{parameter.name}};
  216. {% else %}
  217. {{parameter_type.type}} {{parameter.name}};
  218. {% endif %}
  219. {% endfor %}
  220. DECLARE_DESERIALIZATION_SUPPORT();
  221. };
  222. CRDTP_BEGIN_DESERIALIZER({{command.name}}Params)
  223. {% for parameter in command.parameters | sort(attribute = 'name', case_sensitive=True) %}
  224. {% if parameter.optional %}
  225. CRDTP_DESERIALIZE_FIELD_OPT("{{parameter.name}}", {{parameter.name}}),
  226. {% else %}
  227. CRDTP_DESERIALIZE_FIELD("{{parameter.name}}", {{parameter.name}}),
  228. {% endif %}
  229. {% endfor %}
  230. CRDTP_END_DESERIALIZER()
  231. {% endif %}
  232. } // namespace
  233. void DomainDispatcherImpl::{{command.name}}(const {{config.crdtp.namespace}}::Dispatchable& dispatchable)
  234. {
  235. // Prepare input parameters.
  236. {% if "parameters" in command %}
  237. auto deserializer = {{config.crdtp.namespace}}::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
  238. {{command.name}}Params params;
  239. if (!{{command.name}}Params::Deserialize(&deserializer, &params)) {
  240. ReportInvalidParams(dispatchable, deserializer);
  241. return;
  242. }
  243. {% endif -%}
  244. {% if "returns" in command and not protocol.is_async_command(domain.domain, command.name) %}
  245. // Declare output parameters.
  246. {% for parameter in command.returns %}
  247. {% if "optional" in parameter %}
  248. Maybe<{{protocol.resolve_type(parameter).raw_type}}> out_{{parameter.name}};
  249. {% else %}
  250. {{protocol.resolve_type(parameter).type}} out_{{parameter.name}};
  251. {% endif %}
  252. {% endfor %}
  253. {% endif %}
  254. {% if not protocol.is_async_command(domain.domain, command.name) %}
  255. std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
  256. DispatchResponse response = m_backend->{{command.name | to_method_case}}(
  257. {%- for parameter in command.parameters -%}
  258. {%- if not loop.first -%}, {% endif -%}
  259. {%- if "optional" in parameter -%}
  260. std::move(params.{{parameter.name}})
  261. {%- else -%}
  262. {{protocol.resolve_type(parameter).to_pass_type % ("params." + parameter.name)}}
  263. {%- endif -%}
  264. {%- endfor %}
  265. {%- if "returns" in command %}
  266. {%- for parameter in command.returns -%}
  267. {%- if not loop.first or command.parameters -%}, {% endif -%}
  268. &out_{{parameter.name}}
  269. {%- endfor %}
  270. {% endif %});
  271. if (response.IsFallThrough()) {
  272. channel()->FallThrough(dispatchable.CallId(), {{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}.{{command.name}}"), dispatchable.Serialized());
  273. return;
  274. }
  275. {% if "returns" in command %}
  276. if (weak->get()) {
  277. std::unique_ptr<{{config.crdtp.namespace}}::Serializable> result;
  278. if (response.IsSuccess()) {
  279. {{config.crdtp.namespace}}::ObjectSerializer serializer;
  280. {% for parameter in command.returns %}
  281. serializer.AddField({{config.crdtp.namespace}}::MakeSpan("{{parameter.name}}"), out_{{parameter.name}});
  282. {% endfor %}
  283. result = serializer.Finish();
  284. } else {
  285. result = Serializable::From({});
  286. }
  287. weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
  288. }
  289. {% else %}
  290. if (weak->get())
  291. weak->get()->sendResponse(dispatchable.CallId(), response);
  292. {% endif %}
  293. return;
  294. {% else %}
  295. m_backend->{{command.name | to_method_case}}(
  296. {%- for property in command.parameters -%}
  297. {%- if not loop.first -%}, {% endif -%}
  298. {%- if "optional" in property -%}
  299. std::move(params.{{property.name}})
  300. {%- else -%}
  301. {{protocol.resolve_type(property).to_pass_type % ("params." + property.name)}}
  302. {%- endif -%}
  303. {%- endfor -%}
  304. {%- if command.parameters -%}, {% endif -%}
  305. std::make_unique<{{command_name_title}}CallbackImpl>(weakPtr(), dispatchable.CallId(), dispatchable.Serialized()));
  306. {% endif %}
  307. }
  308. {% endfor %}
  309. namespace {
  310. // This helper method (with a static map of redirects) is used from Dispatcher::wire
  311. // immediately below.
  312. const std::vector<std::pair<{{config.crdtp.namespace}}::span<uint8_t>, {{config.crdtp.namespace}}::span<uint8_t>>>& SortedRedirects() {
  313. static auto* redirects = [](){
  314. auto* redirects = new std::vector<std::pair<{{config.crdtp.namespace}}::span<uint8_t>, {{config.crdtp.namespace}}::span<uint8_t>>>{
  315. {% for command in domain.commands|sort(attribute="name",case_sensitive=True) %}
  316. {% if "redirect" in command %}
  317. { {{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}.{{command.name}}"), {{config.crdtp.namespace}}::SpanFrom("{{command.redirect}}.{{command.name}}") },
  318. {% endif %}
  319. {% endfor %}
  320. };
  321. return redirects;
  322. }();
  323. return *redirects;
  324. }
  325. } // namespace
  326. // static
  327. void Dispatcher::wire(UberDispatcher* uber, Backend* backend)
  328. {
  329. auto dispatcher = std::make_unique<DomainDispatcherImpl>(uber->channel(), backend);
  330. uber->WireBackend({{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}"), SortedRedirects(), std::move(dispatcher));
  331. }
  332. } // {{domain.domain}}
  333. {% for namespace in config.protocol.namespace %}
  334. } // namespace {{namespace}}
  335. {% endfor %}