in src/tool/abi/type_banners.h [117:262]
inline void write_type_banner(writer& w, class_type const& type)
{
using namespace std::literals;
using namespace xlang::meta::reader;
using namespace xlang::text;
w.write(R"^-^(/*
*
* Class %
)^-^", type.clr_full_name());
write_type_banner_version_info(w, type.type());
for_each_attribute(type.type(), metadata_namespace, "ActivatableAttribute"sv, [&](bool first, CustomAttribute const& attr)
{
if (first)
{
w.write(" *\n * RuntimeClass can be activated.\n");
}
// There are 6 constructors for the ActivatableAttribute; we only care about the two that give us contracts
auto sig = attr.Value();
auto const& fixedArgs = sig.FixedArgs();
if (fixedArgs.size() == 2)
{
auto const& elem0 = std::get<ElemSig>(fixedArgs[0].value);
auto const& elem1 = std::get<ElemSig>(fixedArgs[1].value);
if (!std::holds_alternative<std::uint32_t>(elem0.value) ||
!std::holds_alternative<std::string_view>(elem1.value))
{
return;
}
w.write(" * Type can be activated via RoActivateInstance starting with version % of the % API contract\n",
bind<write_contract_version>(std::get<std::uint32_t>(elem0.value)),
std::get<std::string_view>(elem1.value));
}
else if (fixedArgs.size() == 3)
{
auto const& elem0 = std::get<ElemSig>(fixedArgs[0].value);
auto const& elem1 = std::get<ElemSig>(fixedArgs[1].value);
auto const& elem2 = std::get<ElemSig>(fixedArgs[2].value);
if (!std::holds_alternative<ElemSig::SystemType>(elem0.value) ||
!std::holds_alternative<std::uint32_t>(elem1.value) ||
!std::holds_alternative<std::string_view>(elem2.value))
{
return;
}
w.write(" * Type can be activated via the % interface starting with version % of the % API contract\n",
std::get<ElemSig::SystemType>(elem0.value).name,
bind<write_contract_version>(std::get<std::uint32_t>(elem1.value)),
std::get<std::string_view>(elem2.value));
}
});
for_each_attribute(type.type(), metadata_namespace, "StaticAttribute"sv, [&](bool first, CustomAttribute const& attr)
{
if (first)
{
w.write(" *\n * RuntimeClass contains static methods.\n");
}
// There are 3 constructors for the ActivatableAttribute; we only care about one
auto sig = attr.Value();
auto const& fixedArgs = sig.FixedArgs();
if (fixedArgs.size() != 3)
{
return;
}
auto const& contractElem = std::get<ElemSig>(fixedArgs[2].value);
if (!std::holds_alternative<std::string_view>(contractElem.value))
{
return;
}
w.write(" * Static Methods exist on the % interface starting with version % of the % API contract\n",
std::get<ElemSig::SystemType>(std::get<ElemSig>(fixedArgs[0].value).value).name,
bind<write_contract_version>(std::get<std::uint32_t>(std::get<ElemSig>(fixedArgs[1].value).value)),
std::get<std::string_view>(contractElem.value));
});
if (!type.required_interfaces.empty())
{
w.write(R"^-^( *
* Class implements the following interfaces:
)^-^");
for (auto iface : type.required_interfaces)
{
auto suffix = iface == type.default_interface ? " ** Default Interface **" : ""sv;
w.write(" * %%\n", iface->clr_full_name(), suffix);
}
}
if (auto attr = get_attribute(type.type(), metadata_namespace, "ThreadingAttribute"sv))
{
// There's only one constructor for ThreadingAttribute
auto sig = attr.Value();
auto const& fixedArgs = sig.FixedArgs();
XLANG_ASSERT(fixedArgs.size() == 1);
auto const& enumValue = std::get<ElemSig::EnumValue>(std::get<ElemSig>(fixedArgs[0].value).value);
std::string_view msg = "";
switch (std::get<std::int32_t>(enumValue.value))
{
case 1: msg = "Single Threaded Apartment"sv; break;
case 2: msg = "Multi Threaded Apartment"sv; break;
case 3: msg = "Both Single and Multi Threaded Apartment"sv; break;
}
if (!msg.empty())
{
w.write(" *\n * Class Threading Model: %\n", msg);
}
}
if (auto attr = get_attribute(type.type(), metadata_namespace, "MarshalingBehaviorAttribute"sv))
{
// There's only one constructor for ThreadingAttribute
auto sig = attr.Value();
auto const& fixedArgs = sig.FixedArgs();
XLANG_ASSERT(fixedArgs.size() == 1);
auto const& enumValue = std::get<ElemSig::EnumValue>(std::get<ElemSig>(fixedArgs[0].value).value);
std::string_view msg = "";
switch (std::get<std::int32_t>(enumValue.value))
{
case 1: msg = "None - Class cannot be marshaled"sv; break;
case 2: msg = "Agile - Class is agile"sv; break;
case 3: msg = "Standard - Class marshals using the standard marshaler"sv; break;
}
if (!msg.empty())
{
w.write(" *\n * Class Marshaling Behavior: %\n", msg);
}
}
w.write(R"^-^( *
*/
)^-^");
}