blob: 900afc0a5cc8f2d847384208da23135789d47d98 [file] [log] [blame]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "rs_bindings_from_cc/ir.h"
#include <stdint.h>
#include <optional>
#include <ostream>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include "base/integral_types.h"
#include "rs_bindings_from_cc/bazel_types.h"
#include "third_party/absl/strings/string_view.h"
#include "third_party/json/src/json.hpp"
#include "util/intops/strong_int.h"
namespace rs_bindings_from_cc {
template <class T>
static std::vector<nlohmann::json> VectorToJson(const std::vector<T>& v) {
std::vector<nlohmann::json> result;
result.reserve(v.size());
for (const T& t : v) {
result.push_back(t.ToJson());
}
return result;
}
nlohmann::json HeaderName::ToJson() const {
nlohmann::json result;
result["name"] = name_;
return result;
}
nlohmann::json Lifetime::ToJson() const {
nlohmann::json result;
result["name"] = name;
result["id"] = id.value();
return result;
}
nlohmann::json RsType::ToJson() const {
nlohmann::json result;
if (decl_id.has_value()) {
result["decl_id"] = decl_id->value();
} else {
result["name"] = name;
}
std::vector<nlohmann::json> json_lifetime_args;
json_lifetime_args.reserve(lifetime_args.size());
for (const LifetimeId& lifetime_id : lifetime_args) {
json_lifetime_args.push_back(lifetime_id.value());
}
result["lifetime_args"] = json_lifetime_args;
result["type_args"] = VectorToJson(type_args);
return result;
}
nlohmann::json CcType::ToJson() const {
nlohmann::json result;
if (decl_id.has_value()) {
result["decl_id"] = decl_id->value();
} else {
result["name"] = name;
}
result["is_const"] = is_const;
result["type_args"] = VectorToJson(type_args);
return result;
}
MappedType MappedType::PointerTo(MappedType pointee_type,
std::optional<LifetimeId> lifetime,
bool nullable) {
absl::string_view rs_name;
bool has_lifetime = lifetime.has_value();
if (has_lifetime) {
rs_name = pointee_type.cc_type.is_const ? internal::kRustRefConst
: internal::kRustRefMut;
} else {
rs_name = pointee_type.cc_type.is_const ? internal::kRustPtrConst
: internal::kRustPtrMut;
}
auto pointer_type =
Simple(std::string(rs_name), std::string(internal::kCcPtr));
if (has_lifetime) {
pointer_type.rs_type.lifetime_args.push_back(*std::move(lifetime));
}
pointer_type.rs_type.type_args.push_back(std::move(pointee_type.rs_type));
if (has_lifetime && nullable) {
pointer_type.rs_type =
RsType{.name = "Option", .type_args = {pointer_type.rs_type}};
}
pointer_type.cc_type.type_args.push_back(std::move(pointee_type.cc_type));
return pointer_type;
}
MappedType MappedType::LValueReferenceTo(MappedType pointee_type,
std::optional<LifetimeId> lifetime) {
absl::string_view rs_name;
if (lifetime.has_value()) {
rs_name = pointee_type.cc_type.is_const ? internal::kRustRefConst
: internal::kRustRefMut;
} else {
rs_name = pointee_type.cc_type.is_const ? internal::kRustPtrConst
: internal::kRustPtrMut;
}
auto reference_type =
Simple(std::string(rs_name), std::string(internal::kCcLValueRef));
if (lifetime.has_value()) {
reference_type.rs_type.lifetime_args.push_back(*std::move(lifetime));
}
reference_type.rs_type.type_args.push_back(std::move(pointee_type.rs_type));
reference_type.cc_type.type_args.push_back(std::move(pointee_type.cc_type));
return reference_type;
}
MappedType MappedType::FuncPtr(absl::string_view cc_call_conv,
absl::string_view rs_abi,
std::optional<LifetimeId> lifetime,
MappedType return_type,
std::vector<MappedType> param_types) {
std::vector<MappedType> type_args = std::move(param_types);
type_args.push_back(std::move(return_type));
std::vector<CcType> cc_type_args;
std::vector<RsType> rs_type_args;
cc_type_args.reserve(type_args.size());
rs_type_args.reserve(type_args.size());
for (MappedType& type_arg : type_args) {
cc_type_args.push_back(std::move(type_arg.cc_type));
rs_type_args.push_back(std::move(type_arg.rs_type));
}
CcType cc_func_value_type = CcType{
.name = absl::StrCat(internal::kCcFuncValue, " ", cc_call_conv),
.type_args = std::move(cc_type_args),
};
CcType cc_func_ptr_type = CcType{.name = std::string(internal::kCcPtr),
.type_args = {cc_func_value_type}};
// Rust cannot express a function *value* type, only function pointer types.
RsType rs_func_ptr_type = RsType{
.name = absl::StrCat(internal::kRustFuncPtr, " ", rs_abi),
.type_args = std::move(rs_type_args),
};
if (lifetime.has_value())
rs_func_ptr_type.lifetime_args.push_back(*std::move(lifetime));
// `fn() -> ()` is a *non-nullable* pointer in Rust. Since function pointers
// in C++ *can* be null, we need to wrap Rust's function pointer in
// `Option<...>`.
RsType rs_option_type =
RsType{.name = "Option", .type_args = {rs_func_ptr_type}};
return MappedType{
.rs_type = std::move(rs_option_type),
.cc_type = std::move(cc_func_ptr_type),
};
}
nlohmann::json MappedType::ToJson() const {
nlohmann::json result;
result["rs_type"] = rs_type.ToJson();
result["cc_type"] = cc_type.ToJson();
return result;
}
nlohmann::json Identifier::ToJson() const {
nlohmann::json result;
result["identifier"] = identifier_;
return result;
}
nlohmann::json IntegerConstant::ToJson() const {
nlohmann::json result;
result["is_negative"] = is_negative_;
result["wrapped_value"] = wrapped_value_;
return result;
}
nlohmann::json Operator::ToJson() const {
nlohmann::json result;
result["name"] = name_;
return result;
}
static std::string SpecialNameToString(SpecialName special_name) {
switch (special_name) {
case SpecialName::kDestructor:
return "Destructor";
case SpecialName::kConstructor:
return "Constructor";
}
}
nlohmann::json ToJson(const UnqualifiedIdentifier& unqualified_identifier) {
nlohmann::json result;
if (auto* id = std::get_if<Identifier>(&unqualified_identifier)) {
result["Identifier"] = id->ToJson();
} else if (auto* op = std::get_if<Operator>(&unqualified_identifier)) {
result["Operator"] = op->ToJson();
} else {
SpecialName special_name = std::get<SpecialName>(unqualified_identifier);
result[SpecialNameToString(special_name)] = nullptr;
}
return result;
}
nlohmann::json FuncParam::ToJson() const {
nlohmann::json result;
result["type"] = type.ToJson();
result["identifier"] = identifier.ToJson();
return result;
}
std::ostream& operator<<(std::ostream& o, const SpecialName& special_name) {
return o << SpecialNameToString(special_name);
}
nlohmann::json MemberFuncMetadata::ToJson() const {
nlohmann::json meta;
meta["record_id"] = record_id.value();
if (instance_method_metadata.has_value()) {
nlohmann::json instance;
absl::string_view reference;
switch (instance_method_metadata->reference) {
case MemberFuncMetadata::kLValue:
reference = "LValue";
break;
case MemberFuncMetadata::kRValue:
reference = "RValue";
break;
case MemberFuncMetadata::kUnqualified:
reference = "Unqualified";
break;
}
instance["reference"] = reference;
instance["is_const"] = instance_method_metadata->is_const;
instance["is_virtual"] = instance_method_metadata->is_virtual;
instance["is_explicit_ctor"] = instance_method_metadata->is_explicit_ctor;
meta["instance_method_metadata"] = std::move(instance);
}
return meta;
}
nlohmann::json Func::ToJson() const {
nlohmann::json func;
func["name"] = rs_bindings_from_cc::ToJson(name);
func["owning_target"] = owning_target.value();
if (doc_comment) {
func["doc_comment"] = *doc_comment;
}
func["mangled_name"] = mangled_name;
func["return_type"] = return_type.ToJson();
func["params"] = VectorToJson(params);
func["lifetime_params"] = VectorToJson(lifetime_params);
func["is_inline"] = is_inline;
if (member_func_metadata.has_value()) {
func["member_func_metadata"] = member_func_metadata->ToJson();
}
func["source_loc"] = source_loc.ToJson();
nlohmann::json item;
item["Func"] = std::move(func);
return item;
}
static std::string AccessToString(AccessSpecifier access) {
switch (access) {
case kPublic:
return "Public";
case kProtected:
return "Protected";
case kPrivate:
return "Private";
}
}
std::ostream& operator<<(std::ostream& o, const AccessSpecifier& access) {
return o << AccessToString(access);
}
nlohmann::json Field::ToJson() const {
nlohmann::json result;
result["identifier"] = identifier.ToJson();
if (doc_comment) {
result["doc_comment"] = *doc_comment;
}
result["type"] = type.ToJson();
result["access"] = AccessToString(access);
result["offset"] = offset;
result["is_no_unique_address"] = is_no_unique_address;
return result;
}
static std::string SpecialMemberDefinitionToString(
SpecialMemberFunc::Definition def) {
switch (def) {
case SpecialMemberFunc::Definition::kTrivial:
return "Trivial";
case SpecialMemberFunc::Definition::kNontrivialMembers:
return "NontrivialMembers";
case SpecialMemberFunc::Definition::kNontrivialUserDefined:
return "NontrivialUserDefined";
case SpecialMemberFunc::Definition::kDeleted:
return "Deleted";
}
}
std::ostream& operator<<(std::ostream& o,
const SpecialMemberFunc::Definition& definition) {
return o << SpecialMemberDefinitionToString(definition);
}
nlohmann::json SpecialMemberFunc::ToJson() const {
nlohmann::json result;
result["definition"] = SpecialMemberDefinitionToString(definition);
result["access"] = AccessToString(access);
return result;
}
nlohmann::json BaseClass::ToJson() const {
nlohmann::json base;
base["base_record_id"] = base_record_id.value();
if (offset.has_value()) {
base["offset"] = *offset;
}
return base;
}
nlohmann::json Record::ToJson() const {
nlohmann::json record;
record["identifier"] = identifier.ToJson();
record["id"] = id.value();
record["owning_target"] = owning_target.value();
if (doc_comment) {
record["doc_comment"] = *doc_comment;
}
record["unambiguous_public_bases"] = VectorToJson(unambiguous_public_bases);
record["fields"] = VectorToJson(fields);
record["lifetime_params"] = VectorToJson(lifetime_params);
record["size"] = size;
record["alignment"] = alignment;
if (base_size) {
record["base_size"] = *base_size;
}
record["override_alignment"] = override_alignment;
record["copy_constructor"] = copy_constructor.ToJson();
record["move_constructor"] = move_constructor.ToJson();
record["destructor"] = destructor.ToJson();
record["is_trivial_abi"] = is_trivial_abi;
record["is_final"] = is_final;
nlohmann::json item;
item["Record"] = std::move(record);
return item;
}
nlohmann::json Enumerator::ToJson() const {
nlohmann::json result;
result["identifier"] = identifier.ToJson();
result["value"] = value.ToJson();
return result;
}
nlohmann::json Enum::ToJson() const {
nlohmann::json enum_ir;
enum_ir["identifier"] = identifier.ToJson();
enum_ir["id"] = id.value();
enum_ir["owning_target"] = owning_target.value();
enum_ir["underlying_type"] = underlying_type.ToJson();
enum_ir["enumerators"] = VectorToJson(enumerators);
nlohmann::json item;
item["Enum"] = std::move(enum_ir);
return item;
}
nlohmann::json TypeAlias::ToJson() const {
nlohmann::json type_alias;
type_alias["identifier"] = identifier.ToJson();
type_alias["id"] = id.value();
type_alias["owning_target"] = owning_target.value();
type_alias["underlying_type"] = underlying_type.ToJson();
nlohmann::json item;
item["TypeAlias"] = std::move(type_alias);
return item;
}
nlohmann::json SourceLoc::ToJson() const {
nlohmann::json source_loc;
source_loc["filename"] = filename;
source_loc["line"] = line;
source_loc["column"] = column;
return source_loc;
}
nlohmann::json UnsupportedItem::ToJson() const {
nlohmann::json unsupported;
unsupported["name"] = name;
unsupported["message"] = message;
unsupported["source_loc"] = source_loc.ToJson();
nlohmann::json item;
item["UnsupportedItem"] = std::move(unsupported);
return item;
}
nlohmann::json Comment::ToJson() const {
nlohmann::json comment;
comment["text"] = text;
nlohmann::json item;
item["Comment"] = std::move(comment);
return item;
}
nlohmann::json IR::ToJson() const {
std::vector<nlohmann::json> json_items;
json_items.reserve(items.size());
for (const auto& item : items) {
std::visit([&](auto&& item) { json_items.push_back(item.ToJson()); }, item);
}
nlohmann::json result;
result["used_headers"] = VectorToJson(used_headers);
result["current_target"] = current_target.value();
result["items"] = std::move(json_items);
return result;
}
} // namespace rs_bindings_from_cc