blob: cc2aa130b6840e6f2585bc825df34929bf91f3dc [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import sys
import string
import json
blink_protocol_path = sys.argv[1]
browser_protocol_path = sys.argv[2]
output_cc_path = sys.argv[3]
output_h_path = sys.argv[4]
header = """\
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
// Generated by
// content/public/browser/devtools_protocol_handler_generator.py from
// third_party/WebKit/Source/devtools/protocol.json and
// content/browser/devtools/browser_protocol.json
"""
template_h = string.Template(header + """\
#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DISPATCHER_H_
#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DISPATCHER_H_
#include "content/browser/devtools/protocol/devtools_protocol_client.h"
namespace content {
class DevToolsProtocolDispatcher;
namespace devtools {
extern const char kProtocolVersion[];
bool IsSupportedProtocolVersion(const std::string& version);
template<typename T>
base::Value* CreateValue(const T& param) {
return new base::FundamentalValue(param);
}
template<class T>
base::Value* CreateValue(scoped_ptr<T>& param) {
return param.release();
}
template<class T>
base::Value* CreateValue(scoped_refptr<T> param) {
return param->ToValue().release();
}
template<typename T>
base::Value* CreateValue(const std::vector<T> param) {
base::ListValue* result = new base::ListValue();
for (auto& item : param) {
result->Append(CreateValue(item));
}
return result;
}
template<>
base::Value* CreateValue(const std::string& param);
${types}\
} // namespace devtools
class DevToolsProtocolDispatcher {
public:
using Notifier = DevToolsProtocolClient::RawMessageCallback;
using CommandHandler =
base::Callback<bool(int, scoped_ptr<base::DictionaryValue>)>;
explicit DevToolsProtocolDispatcher(const Notifier& notifier);
~DevToolsProtocolDispatcher();
CommandHandler FindCommandHandler(const std::string& method);
${setters}\
private:
using Response = DevToolsProtocolClient::Response;
using CommandHandlers = std::map<std::string, CommandHandler>;
${methods}\
Notifier notifier_;
DevToolsProtocolClient client_;
CommandHandlers command_handlers_;
${fields}\
};
} // namespace content
#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DISPATCHER_H_
""")
tmpl_typedef = string.Template("""\
namespace ${domain} {
typedef ${param_type} ${declared_name};
} // namespace ${domain}
""")
tmpl_struct = string.Template("""\
namespace ${domain} {
template<int MASK>
struct ${declared_name}Builder
: base::RefCounted<${declared_name}Builder<MASK>> {
public:
enum {
kAllSet = 0,
${fields_enum}\
};
${methods}\
static scoped_refptr<${declared_name}Builder<kNoneSet>> Create() {
return new ${declared_name}Builder<kNoneSet>();
}
scoped_ptr<base::DictionaryValue> ToValue() {
static_assert(MASK == kAllSet, "required properties missing");
return make_scoped_ptr(dict_->DeepCopy());
}
private:
friend struct ${declared_name}Builder<0>;
${declared_name}Builder() : dict_(new base::DictionaryValue()) {
}
template<class T> T* ThisAs() {
static_assert(sizeof(*this) == sizeof(T), "cannot cast");
return reinterpret_cast<T*>(this);
}
scoped_ptr<base::DictionaryValue> dict_;
};
typedef ${declared_name}Builder<0> ${declared_name};
} // namespace ${domain}
""")
tmpl_builder_setter_req = string.Template("""\
scoped_refptr<${declared_name}Builder<MASK & ~k${Param}>>
set_${param}(${pass_type} ${param}) {
static_assert(MASK & k${Param}, "already set");
dict_->Set("${proto_param}", CreateValue(${param}));
return ThisAs<${declared_name}Builder<MASK & ~k${Param}>>();
}
""")
tmpl_builder_setter_opt = string.Template("""\
scoped_refptr<${declared_name}Builder<MASK>>
set_${param}(${pass_type} ${param}) {
dict_->Set("${proto_param}", CreateValue(${param}));
return this;
}
""")
tmpl_builder_enum = string.Template("""\
k${Param} = 1 << ${ordinal},
""")
tmpl_builder_none_set = string.Template("""\
kNoneSet = ${all_fields}
""")
tmpl_named_enum = string.Template("""\
namespace ${domain} {
${values}\
} // namespace ${domain}
""")
tmpl_inline_enum = string.Template("""\
namespace ${domain} {
namespace ${subdomain} {
${values}\
} // namespace ${subdomain}
} // namespace ${domain}
""")
tmpl_enum_value = string.Template("""\
extern const char k${Enum}${Value}[];
""")
tmpl_enum_value_def = string.Template("""\
const char k${Enum}${Value}[] = "${value}";
""")
tmpl_handler = string.Template("""\
namespace ${domain} {
class ${Domain}Handler;
} // namespace domain
""")
tmpl_client = string.Template("""\
namespace ${domain} {
class Client : public DevToolsProtocolClient {
public:
explicit Client(const RawMessageCallback& raw_message_callback);
~Client() override;
${methods}\
};
} // namespace ${domain}
""")
tmpl_event = string.Template("""\
void ${Command}(
scoped_refptr<${Command}Params> params);
""")
tmpl_response = string.Template("""\
void Send${Command}Response(
DevToolsCommandId command_id,
scoped_refptr<${Command}Response> params);
""")
tmpl_setter = string.Template("""\
void Set${Domain}Handler(
devtools::${domain}::${Domain}Handler* ${domain}_handler);
""")
tmpl_callback = string.Template("""\
bool On${Domain}${Command}(
DevToolsCommandId command_id,
scoped_ptr<base::DictionaryValue> params);
""")
tmpl_field = string.Template("""\
devtools::${domain}::${Domain}Handler* ${domain}_handler_;
""")
template_cc = string.Template(header + """\
#include "content/browser/devtools/protocol/devtools_protocol_handler.h"
#include "base/bind.h"
#include "base/strings/string_number_conversions.h"
${includes}\
namespace content {
DevToolsProtocolDispatcher::DevToolsProtocolDispatcher(
const Notifier& notifier)
: notifier_(notifier),
client_(notifier),
${fields_init} {
}
DevToolsProtocolDispatcher::~DevToolsProtocolDispatcher() {
}
DevToolsProtocolDispatcher::CommandHandler
DevToolsProtocolDispatcher::FindCommandHandler(const std::string& method) {
CommandHandlers::iterator it = command_handlers_.find(method);
return it == command_handlers_.end() ? CommandHandler() : it->second;
}
${methods}\
namespace devtools {
const char kProtocolVersion[] = "${major}.${minor}";
bool IsSupportedProtocolVersion(const std::string& version) {
std::vector<std::string> tokens;
Tokenize(version, ".", &tokens);
int major, minor;
return tokens.size() == 2 &&
base::StringToInt(tokens[0], &major) && major == ${major} &&
base::StringToInt(tokens[1], &minor) && minor <= ${minor};
}
template<>
base::Value* CreateValue(const std::string& param) {
return new base::StringValue(param);
}
${types}\
} // namespace devtools
} // namespace content
""")
tmpl_include = string.Template("""\
#include "content/browser/devtools/protocol/${domain}_handler.h"
""")
tmpl_field_init = string.Template("${domain}_handler_(nullptr)")
tmpl_setter_impl = string.Template("""\
void DevToolsProtocolDispatcher::Set${Domain}Handler(
devtools::${domain}::${Domain}Handler* ${domain}_handler) {
DCHECK(!${domain}_handler_);
${domain}_handler_ = ${domain}_handler;
${initializations}\
}
""")
tmpl_register = string.Template("""\
command_handlers_["${Domain}.${command}"] =
base::Bind(
&DevToolsProtocolDispatcher::On${TargetDomain}${Command},
base::Unretained(this));
""")
tmpl_init_client = string.Template("""\
${domain}_handler_->SetClient(make_scoped_ptr(
new devtools::${domain}::Client(notifier_)));
""")
tmpl_callback_impl = string.Template("""\
bool DevToolsProtocolDispatcher::On${Domain}${Command}(
DevToolsCommandId command_id,
scoped_ptr<base::DictionaryValue> params) {
${prep}\
Response response = ${domain}_handler_->${Command}(${args});
scoped_ptr<base::DictionaryValue> protocol_response;
if (client_.SendError(command_id, response))
return true;
if (response.IsFallThrough())
return false;
scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
${wrap}\
client_.SendSuccess(command_id, result.Pass());
return true;
}
""")
tmpl_wrap = string.Template("""\
result->Set("${proto_param}", devtools::CreateValue(out_${param}));
""")
tmpl_callback_async_impl = string.Template("""\
bool DevToolsProtocolDispatcher::On${Domain}${Command}(
DevToolsCommandId command_id,
scoped_ptr<base::DictionaryValue> params) {
${prep}\
Response response = ${domain}_handler_->${Command}(${args});
if (client_.SendError(command_id, response))
return true;
return !response.IsFallThrough();
}
""")
tmpl_prep_req = string.Template("""\
${raw_type} in_${param}${init};
if (!params || !params->Get${Type}("${proto_param}", &in_${param})) {
client_.SendError(command_id, Response::InvalidParams("${proto_param}"));
return true;
}
""")
tmpl_prep_req_list = string.Template("""\
base::ListValue* list_${param} = nullptr;
if (!params || !params->GetList("${proto_param}", &list_${param})) {
client_.SendError(command_id, Response::InvalidParams("${proto_param}"));
return true;
}
std::vector<${item_type}> in_${param};
for (base::ListValue::const_iterator it =
list_${param}->begin(); it != list_${param}->end(); ++it) {
${item_raw_type} item;
if (!(*it)->GetAs${ItemType}(&item)) {
client_.SendError(command_id, Response::InvalidParams("${proto_param}"));
return true;
}
in_${param}.push_back(${item_pass});
}
""")
tmpl_prep_opt = string.Template("""\
${raw_type} in_${param}${init};
bool ${param}_found = params && params->Get${Type}(
"${proto_param}",
&in_${param});
""")
tmpl_prep_output = string.Template("""\
${param_type} out_${param}${init};
""")
tmpl_arg_name = string.Template("in_${param}")
tmpl_arg_req = string.Template("${param_pass}")
tmpl_arg_opt = string.Template(
"${param}_found ? ${param_pass} : nullptr")
tmpl_object_pass = string.Template(
"make_scoped_ptr<base::DictionaryValue>(${name}->DeepCopy())")
tmpl_client_impl = string.Template("""\
namespace ${domain} {
Client::Client(const RawMessageCallback& raw_message_callback)
: DevToolsProtocolClient(raw_message_callback) {
}
Client::~Client() {
}
${methods}\
} // namespace ${domain}
""")
tmpl_event_impl = string.Template("""\
void Client::${Command}(
scoped_refptr<${Command}Params> params) {
SendNotification("${Domain}.${command}",
params->ToValue().Pass());
}
""")
tmpl_response_impl = string.Template("""\
void Client::Send${Command}Response(
DevToolsCommandId command_id,
scoped_refptr<${Command}Response> params) {
SendSuccess(command_id, params->ToValue().Pass());
}
""")
tmpl_typename = string.Template("devtools::${domain}::${declared_name}")
def Capitalize(s):
return s[:1].upper() + s[1:]
def Uncamelcase(s):
result = ""
for i, c in enumerate(s):
if c.isupper():
if (i > 0) and ((i < len(s)-1) and s[i+1].islower() or s[i-1].islower()):
result += "_"
result += c.lower()
else:
result += c
return result
types = {}
blink_protocol = json.loads(open(blink_protocol_path, "r").read())
browser_protocol = json.loads(open(browser_protocol_path, "r").read())
type_decls = []
type_impls = []
handler_methods = []
handler_method_impls = []
domain_maps = []
redirects = {}
all_domains = blink_protocol["domains"] + browser_protocol["domains"]
for json_domain in all_domains:
if "types" in json_domain:
for json_type in json_domain["types"]:
types["%s.%s" % (json_domain["domain"], json_type["id"])] = json_type
def DeclareStruct(json_properties, mapping):
methods = []
fields_enum = []
enum_items = []
req_fields_num = 0
for json_prop in json_properties:
prop_map = mapping.copy()
prop_map["proto_param"] = json_prop["name"]
prop_map["param"] = Uncamelcase(json_prop["name"])
prop_map["Param"] = Capitalize(json_prop["name"])
prop_map["subdomain"] = Uncamelcase(prop_map["declared_name"])
del prop_map["declared_name"]
ResolveType(json_prop, prop_map)
prop_map["declared_name"] = mapping["declared_name"]
if json_prop.get("optional"):
methods.append(tmpl_builder_setter_opt.substitute(prop_map))
else:
methods.append(tmpl_builder_setter_req.substitute(prop_map))
enum_items.append("k%s" % prop_map["Param"]);
fields_enum.append(tmpl_builder_enum.substitute(prop_map,
ordinal = req_fields_num))
req_fields_num += 1
all_fields = "kAllSet"
if len(enum_items) > 0:
all_fields = " | ".join(enum_items)
fields_enum.append(tmpl_builder_none_set.substitute(mapping,
all_fields = all_fields))
type_decls.append(tmpl_struct.substitute(mapping,
methods = "\n".join(methods),
fields_enum = "".join(fields_enum)))
def DeclareEnum(json, mapping):
values = []
value_defs = []
tmpl_enum = tmpl_inline_enum
if "declared_name" in mapping:
mapping["Enum"] = mapping["declared_name"]
tmpl_enum = tmpl_named_enum
else:
mapping["Enum"] = Capitalize(mapping["proto_param"])
for enum_value in json["enum"]:
values.append(tmpl_enum_value.substitute(mapping,
Value = Capitalize(enum_value)))
value_defs.append(tmpl_enum_value_def.substitute(mapping,
value = enum_value,
Value = Capitalize(enum_value)))
type_decls.append(tmpl_enum.substitute(mapping,
values = "".join(values)))
type_impls.append(tmpl_enum.substitute(mapping,
values = "".join(value_defs)))
def ResolveRef(json, mapping):
dot_pos = json["$ref"].find(".")
if dot_pos == -1:
domain_name = mapping["Domain"]
type_name = json["$ref"]
else:
domain_name = json["$ref"][:dot_pos]
type_name = json["$ref"][dot_pos + 1:]
json_type = types["%s.%s" % (domain_name, type_name)]
mapping["declared_name"] = Capitalize(type_name)
mapping["Domain"] = domain_name
mapping["domain"] = Uncamelcase(domain_name)
mapping["param_type"] = tmpl_typename.substitute(mapping)
ResolveType(json_type, mapping)
if not "___type_declared" in json_type:
json_type["___type_declared"] = True;
if (json_type.get("type") == "object") and ("properties" in json_type):
DeclareStruct(json_type["properties"], mapping)
else:
if ("enum" in json_type):
DeclareEnum(json_type, mapping)
type_decls.append(tmpl_typedef.substitute(mapping))
def ResolveArray(json, mapping):
items_map = mapping.copy()
ResolveType(json["items"], items_map)
if items_map["Type"] == "List":
# TODO(dgozman) Implement this.
raise Exception("Nested arrays are not implemented")
mapping["param_type"] = "std::vector<%s>" % items_map["param_type"]
mapping["Type"] = "List"
mapping["pass_type"] = "const %s&" % mapping["param_type"]
mapping["storage_type"] = "std::vector<%s>" % items_map["storage_type"]
mapping["raw_type"] = mapping["storage_type"]
mapping["prep_req"] = tmpl_prep_req_list.substitute(mapping,
item_type = items_map["storage_type"],
item_init = items_map["init"],
item_raw_type = items_map["raw_type"],
item_pass = items_map["pass_template"].substitute(name="item", opt=""),
ItemType = items_map["Type"])
mapping["arg_out"] = "&out_%s" % mapping["param"]
def ResolveObject(json, mapping):
mapping["Type"] = "Dictionary"
mapping["storage_type"] = "scoped_ptr<base::DictionaryValue>"
mapping["raw_type"] = "base::DictionaryValue*"
mapping["pass_template"] = tmpl_object_pass
if "properties" in json:
if not "declared_name" in mapping:
mapping["declared_name"] = ("%s%s" %
(mapping["Command"], Capitalize(mapping["proto_param"])))
mapping["param_type"] = ("scoped_refptr<%s>" %
tmpl_typename.substitute(mapping))
DeclareStruct(json["properties"], mapping)
else:
mapping["param_type"] = ("scoped_refptr<%s>" %
tmpl_typename.substitute(mapping))
mapping["pass_type"] = mapping["param_type"]
mapping["arg_out"] = "&out_%s" % mapping["param"]
else:
mapping["param_type"] = "base::DictionaryValue"
mapping["pass_type"] = "scoped_ptr<base::DictionaryValue>"
mapping["arg_out"] = "out_%s.get()" % mapping["param"]
mapping["prep_req"] = tmpl_prep_req.substitute(mapping)
def ResolvePrimitive(json, mapping):
jsonrpc_type = json["type"]
if jsonrpc_type == "boolean":
mapping["param_type"] = "bool"
mapping["Type"] = "Boolean"
mapping["init"] = " = false"
elif jsonrpc_type == "integer":
mapping["param_type"] = "int"
mapping["Type"] = "Integer"
mapping["init"] = " = 0"
elif jsonrpc_type == "number":
mapping["param_type"] = "double"
mapping["Type"] = "Double"
mapping["init"] = " = 0.0"
elif jsonrpc_type == "string":
mapping["param_type"] = "std::string"
mapping["pass_type"] = "const std::string&"
mapping["Type"] = "String"
if "enum" in json and not "declared_name" in mapping:
if not "subdomain" in mapping:
mapping["subdomain"] = Uncamelcase(mapping["command"])
DeclareEnum(json, mapping)
else:
raise Exception("Unknown type: %s" % json_type)
mapping["storage_type"] = mapping["param_type"]
mapping["raw_type"] = mapping["param_type"]
mapping["prep_req"] = tmpl_prep_req.substitute(mapping)
if jsonrpc_type != "string":
mapping["pass_type"] = mapping["param_type"]
mapping["arg_out"] = "&out_%s" % mapping["param"]
def ResolveType(json, mapping):
mapping["init"] = ""
mapping["pass_template"] = string.Template("${opt}${name}")
if "$ref" in json:
ResolveRef(json, mapping)
elif "type" in json:
jsonrpc_type = json["type"]
if jsonrpc_type == "array":
ResolveArray(json, mapping)
elif jsonrpc_type == "object":
ResolveObject(json, mapping)
else:
ResolvePrimitive(json, mapping)
else:
raise Exception("Unknown type at %s.%s %s" %
(mapping["Domain"], mapping["command"], mapping["proto_param"]))
setters = []
fields = []
includes = []
fields_init = []
for json_domain in all_domains:
domain_map = {}
domain_map["Domain"] = json_domain["domain"]
domain_map["domain"] = Uncamelcase(json_domain["domain"])
initializations = []
client_methods = []
client_method_impls = []
domain_empty = True
domain_needs_client = False
if "commands" in json_domain:
for json_command in json_domain["commands"]:
if (not ("handlers" in json_command) or
not ("browser" in json_command["handlers"])):
continue
domain_empty = False
command_map = domain_map.copy()
command_map["command"] = json_command["name"]
command_map["Command"] = Capitalize(json_command["name"])
if "redirect" in json_command:
redirect_domain = json_command["redirect"]
if not (redirect_domain in redirects):
redirects[redirect_domain] = []
command_map["TargetDomain"] = redirect_domain
redirects[redirect_domain].append(tmpl_register.substitute(command_map))
continue
command_map["TargetDomain"] = command_map["Domain"]
prep = []
args = []
if "parameters" in json_command:
for json_param in json_command["parameters"]:
param_map = command_map.copy()
param_map["proto_param"] = json_param["name"]
param_map["param"] = Uncamelcase(json_param["name"])
ResolveType(json_param, param_map)
if json_param.get("optional"):
if param_map["Type"] in ["List"]:
# TODO(vkuzkokov) Implement transformation of base::ListValue
# to std::vector and base::DictonaryValue to struct.
raise Exception(
"Optional array parameters are not implemented")
prep.append(tmpl_prep_opt.substitute(param_map))
param_pass = param_map["pass_template"].substitute(
name=tmpl_arg_name.substitute(param_map),
opt="&")
args.append(
tmpl_arg_opt.substitute(param_map, param_pass=param_pass))
else:
prep.append(param_map["prep_req"])
param_pass = param_map["pass_template"].substitute(
name=tmpl_arg_name.substitute(param_map),
opt="")
args.append(
tmpl_arg_req.substitute(param_map, param_pass=param_pass))
if json_command.get("async"):
domain_needs_client = True
json_returns = []
if "returns" in json_command:
json_returns = json_command["returns"]
command_map["declared_name"] = "%sResponse" % command_map["Command"]
DeclareStruct(json_returns, command_map)
# TODO(vkuzkokov) Pass async callback instance similar to how
# InspectorBackendDispatcher does it. This, however, can work
# only if Blink and Chrome are in the same repo.
args.insert(0, "command_id")
handler_method_impls.append(
tmpl_callback_async_impl.substitute(command_map,
prep = "".join(prep),
args = "\n " + ",\n ".join(args)))
client_methods.append(tmpl_response.substitute(command_map))
client_method_impls.append(tmpl_response_impl.substitute(command_map))
else:
wrap = []
if "returns" in json_command:
for json_param in json_command["returns"]:
param_map = command_map.copy()
param_map["proto_param"] = json_param["name"]
param_map["param"] = Uncamelcase(json_param["name"])
if json_param.get("optional"):
# TODO(vkuzkokov) Implement Optional<T> for value types.
raise Exception("Optional return values are not implemented")
ResolveType(json_param, param_map)
prep.append(tmpl_prep_output.substitute(param_map))
args.append(param_map["arg_out"])
wrap.append(tmpl_wrap.substitute(param_map))
args_str = ""
if len(args) > 0:
args_str = "\n " + ",\n ".join(args)
handler_method_impls.append(tmpl_callback_impl.substitute(command_map,
prep = "".join(prep),
args = args_str,
wrap = "".join(wrap)))
initializations.append(tmpl_register.substitute(command_map))
handler_methods.append(tmpl_callback.substitute(command_map))
if "events" in json_domain:
for json_event in json_domain["events"]:
if (not ("handlers" in json_event) or
not ("browser" in json_event["handlers"])):
continue
domain_empty = False
domain_needs_client = True
event_map = domain_map.copy()
event_map["command"] = json_event["name"]
event_map["Command"] = Capitalize(json_event["name"])
json_parameters = []
if "parameters" in json_event:
json_parameters = json_event["parameters"]
event_map["declared_name"] = "%sParams" % event_map["Command"]
DeclareStruct(json_parameters, event_map);
client_methods.append(tmpl_event.substitute(event_map))
client_method_impls.append(tmpl_event_impl.substitute(event_map))
if domain_empty:
continue
type_decls.append(tmpl_handler.substitute(domain_map))
setters.append(tmpl_setter.substitute(domain_map))
fields.append(tmpl_field.substitute(domain_map))
includes.append(tmpl_include.substitute(domain_map))
fields_init.append(tmpl_field_init.substitute(domain_map))
if domain_needs_client:
type_decls.append(tmpl_client.substitute(domain_map,
methods = "".join(client_methods)))
initializations.append(tmpl_init_client.substitute(domain_map))
type_impls.append(tmpl_client_impl.substitute(domain_map,
methods = "\n".join(client_method_impls)))
domain_map["initializations"] = "".join(initializations)
domain_maps.append(domain_map)
for domain_map in domain_maps:
domain = domain_map["Domain"]
if domain in redirects:
domain_map["initializations"] += "".join(redirects[domain])
handler_method_impls.append(tmpl_setter_impl.substitute(domain_map))
output_h_file = open(output_h_path, "w")
output_cc_file = open(output_cc_path, "w")
output_h_file.write(template_h.substitute({},
types = "\n".join(type_decls),
setters = "".join(setters),
methods = "".join(handler_methods),
fields = "".join(fields)))
output_h_file.close()
output_cc_file.write(template_cc.substitute({},
major = blink_protocol["version"]["major"],
minor = blink_protocol["version"]["minor"],
includes = "".join(sorted(includes)),
fields_init = ",\n ".join(fields_init),
methods = "\n".join(handler_method_impls),
types = "\n".join(type_impls)))
output_cc_file.close()