blob: bc751782724870b0ef1ce42a4a1eb622ee8358d7 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TOOLS_FIDL_FIDLC_INCLUDE_FIDL_FLAT_TYPES_H_
#define TOOLS_FIDL_FIDLC_INCLUDE_FIDL_FLAT_TYPES_H_
#include "name.h"
#include "object.h"
#include "values.h"
namespace fidl {
namespace flat {
struct CreateInvocation;
struct TypeDecl;
class LibraryMediator;
struct LayoutInvocation;
struct TypeConstraints;
struct Resource;
class TypeTemplate;
struct Type : public Object {
virtual ~Type() {}
enum struct Kind {
kArray,
kVector,
kString,
kHandle,
kRequestHandle,
kPrimitive,
kIdentifier,
};
explicit Type(const Name& name, Kind kind, types::Nullability nullability)
: name(name), kind(kind), nullability(nullability) {}
const Name name;
const Kind kind;
const types::Nullability nullability;
// Returns the nominal resourceness of the type per the FTP-057 definition.
// For IdentifierType, can only be called after the Decl has been compiled.
types::Resourceness Resourceness() const;
// Comparison helper object.
class Comparison {
public:
Comparison() = default;
template <class T>
Comparison Compare(const T& a, const T& b) const {
if (result_ != 0)
return Comparison(result_);
if (a < b)
return Comparison(-1);
if (b < a)
return Comparison(1);
return Comparison(0);
}
bool IsLessThan() const { return result_ < 0; }
private:
Comparison(int result) : result_(result) {}
const int result_ = 0;
};
bool operator<(const Type& other) const {
if (kind != other.kind)
return kind < other.kind;
return Compare(other).IsLessThan();
}
// Compare this object against 'other'.
// It's guaranteed that this->kind == other.kind.
// Return <0 if *this < other, ==0 if *this == other, and >0 if *this > other.
// Derived types should override this, but also call this implementation.
virtual Comparison Compare(const Type& other) const {
assert(kind == other.kind);
return Comparison().Compare(nullability, other.nullability);
}
// The old syntax's CreateInvocation contains both what would considered to be
// layout arguments and constraints in the new syntax. These are applied to
// the current type to produce a new type - this is the old syntax equivalent
// of ApplyConstraints
virtual bool ApplySomeLayoutParametersAndConstraints(const flat::LibraryMediator& lib,
const CreateInvocation& create_invocation,
const flat::TypeTemplate* layout,
std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const = 0;
// Apply the provided constraints to this type, returning the newly constrained
// Type and recording the invocation inside resolved_args.
// For types in the new syntax, we receive the unresolved TypeConstraints.
// TODO(fxbug.dev/74193): We currently require a pointer to the calling TypeTemplate
// for error reporting purposes, since all of the constraint related errors are
// still tied to TypeTemplates. As we fully separate out the constraints and
// layout parameter (TypeTemplate::Create) code, we'll be able to remove this
// extraneous parameter.
virtual bool ApplyConstraints(const flat::LibraryMediator& lib,
const TypeConstraints& constraints,
const flat::TypeTemplate* layout, std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const = 0;
};
struct ArrayType final : public Type {
ArrayType(const Name& name, const Type* element_type, const Size* element_count)
: Type(name, Kind::kArray, types::Nullability::kNonnullable),
element_type(element_type),
element_count(element_count) {}
const Type* element_type;
const Size* element_count;
std::any AcceptAny(VisitorAny* visitor) const override;
Comparison Compare(const Type& other) const override {
const auto& o = static_cast<const ArrayType&>(other);
return Type::Compare(o)
.Compare(element_count->value, o.element_count->value)
.Compare(*element_type, *o.element_type);
}
bool ApplySomeLayoutParametersAndConstraints(const flat::LibraryMediator& lib,
const CreateInvocation& create_invocation,
const flat::TypeTemplate* layout,
std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
bool ApplyConstraints(const flat::LibraryMediator& lib, const TypeConstraints& constraints,
const flat::TypeTemplate* layout, std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
};
struct VectorBaseType {
// "vector based" types share common code for determining the size and nullability.
// This method provides the resolved size and nullability, so that specific implementations
// only need to worry about setting the element type on out_args.
// We can't abstract away only the element type resolution process, because not
// all vector based type templates return a VectorType (the exception being StringTypeTemplate).
static bool ResolveSizeAndNullability(const LibraryMediator& lib,
const TypeConstraints& constraints,
const TypeTemplate* layout, LayoutInvocation* out_params);
const static Size kMaxSize;
};
struct VectorType final : public Type, public VectorBaseType {
VectorType(const Name& name, const Type* element_type)
: Type(name, Kind::kVector, types::Nullability::kNonnullable),
element_type(element_type),
element_count(&kMaxSize) {}
VectorType(const Name& name, const Type* element_type, const Size* element_count,
types::Nullability nullability)
: Type(name, Kind::kVector, nullability),
element_type(element_type),
element_count(element_count) {}
const Type* element_type;
const Size* element_count;
std::any AcceptAny(VisitorAny* visitor) const override;
Comparison Compare(const Type& other) const override {
const auto& o = static_cast<const VectorType&>(other);
return Type::Compare(o)
.Compare(element_count->value, o.element_count->value)
.Compare(*element_type, *o.element_type);
}
bool ApplySomeLayoutParametersAndConstraints(const flat::LibraryMediator& lib,
const CreateInvocation& create_invocation,
const flat::TypeTemplate* layout,
std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
bool ApplyConstraints(const flat::LibraryMediator& lib, const TypeConstraints& constraints,
const flat::TypeTemplate* layout, std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
};
struct StringType final : public Type, public VectorBaseType {
explicit StringType(const Name& name)
: Type(name, Kind::kString, types::Nullability::kNonnullable), max_size(&kMaxSize) {}
StringType(const Name& name, const Size* max_size, types::Nullability nullability)
: Type(name, Kind::kString, nullability), max_size(max_size) {}
const Size* max_size;
std::any AcceptAny(VisitorAny* visitor) const override;
Comparison Compare(const Type& other) const override {
const auto& o = static_cast<const StringType&>(other);
return Type::Compare(o).Compare(max_size->value, o.max_size->value);
}
bool ApplySomeLayoutParametersAndConstraints(const flat::LibraryMediator& lib,
const CreateInvocation& create_invocation,
const flat::TypeTemplate* layout,
std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
bool ApplyConstraints(const flat::LibraryMediator& lib, const TypeConstraints& constraints,
const flat::TypeTemplate* layout, std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
};
struct HandleType final : public Type {
HandleType(const Name& name, Resource* resource_decl)
: Type(name, Kind::kHandle, types::Nullability::kNonnullable),
resource_decl(resource_decl),
// TODO(fxbug.dev/64629): When we are ready to create handle types, we
// should have an object type (and/or subtype) determined and not require
// these hardcoded defaults.
// We need to allow setting a default obj_type in resource_definition
// declarations rather than hard-coding.
obj_type(static_cast<uint32_t>(types::HandleSubtype::kHandle)),
subtype(types::HandleSubtype::kHandle),
rights(&kSameRights) {}
HandleType(const Name& name, Resource* resource_decl, uint32_t obj_type,
types::HandleSubtype subtype, const HandleRights* rights,
types::Nullability nullability)
: Type(name, Kind::kHandle, nullability),
resource_decl(resource_decl),
obj_type(obj_type),
subtype(subtype),
rights(rights) {}
Resource* resource_decl;
const uint32_t obj_type;
const types::HandleSubtype subtype;
const HandleRights* rights;
std::any AcceptAny(VisitorAny* visitor) const override;
Comparison Compare(const Type& other) const override {
const auto& other_handle_type = *static_cast<const HandleType*>(&other);
auto rights_val =
static_cast<const flat::NumericConstantValue<types::RightsWrappedType>*>(rights);
auto other_rights_val =
static_cast<const flat::NumericConstantValue<types::RightsWrappedType>*>(
other_handle_type.rights);
return Type::Compare(other_handle_type)
.Compare(subtype, other_handle_type.subtype)
.Compare(*rights_val, *other_rights_val);
}
bool ApplySomeLayoutParametersAndConstraints(const flat::LibraryMediator& lib,
const CreateInvocation& create_invocation,
const flat::TypeTemplate* layout,
std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
bool ApplyConstraints(const flat::LibraryMediator& lib, const TypeConstraints& constraints,
const flat::TypeTemplate* layout, std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
const static HandleRights kSameRights;
};
struct PrimitiveType final : public Type {
explicit PrimitiveType(const Name& name, types::PrimitiveSubtype subtype)
: Type(name, Kind::kPrimitive, types::Nullability::kNonnullable), subtype(subtype) {}
types::PrimitiveSubtype subtype;
std::any AcceptAny(VisitorAny* visitor) const override;
Comparison Compare(const Type& other) const override {
const auto& o = static_cast<const PrimitiveType&>(other);
return Type::Compare(o).Compare(subtype, o.subtype);
}
bool ApplySomeLayoutParametersAndConstraints(const flat::LibraryMediator& lib,
const CreateInvocation& create_invocation,
const flat::TypeTemplate* layout,
std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
bool ApplyConstraints(const flat::LibraryMediator& lib, const TypeConstraints& constraints,
const flat::TypeTemplate* layout, std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
private:
static uint32_t SubtypeSize(types::PrimitiveSubtype subtype);
};
struct IdentifierType final : public Type {
IdentifierType(const Name& name, const TypeDecl* type_decl)
: IdentifierType(name, type_decl, types::Nullability::kNonnullable) {}
IdentifierType(const Name& name, const TypeDecl* type_decl, types::Nullability nullability)
: Type(name, Kind::kIdentifier, nullability), type_decl(type_decl) {}
const TypeDecl* type_decl;
std::any AcceptAny(VisitorAny* visitor) const override;
Comparison Compare(const Type& other) const override {
const auto& o = static_cast<const IdentifierType&>(other);
return Type::Compare(o).Compare(name, o.name);
}
bool ApplySomeLayoutParametersAndConstraints(const flat::LibraryMediator& lib,
const CreateInvocation& create_invocation,
const flat::TypeTemplate* layout,
std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
bool ApplyConstraints(const flat::LibraryMediator& lib, const TypeConstraints& constraints,
const flat::TypeTemplate* layout, std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
};
// TODO(fxbug.dev/43803) Add required and optional rights.
struct RequestHandleType final : public Type {
RequestHandleType(const Name& name, const IdentifierType* protocol_type)
: RequestHandleType(name, protocol_type, types::Nullability::kNonnullable) {}
RequestHandleType(const Name& name, const IdentifierType* protocol_type,
types::Nullability nullability)
: Type(name, Kind::kRequestHandle, nullability), protocol_type(protocol_type) {}
const IdentifierType* protocol_type;
std::any AcceptAny(VisitorAny* visitor) const override;
Comparison Compare(const Type& other) const override {
const auto& o = static_cast<const RequestHandleType&>(other);
return Type::Compare(o).Compare(*protocol_type, *o.protocol_type);
}
bool ApplySomeLayoutParametersAndConstraints(const flat::LibraryMediator& lib,
const CreateInvocation& create_invocation,
const flat::TypeTemplate* layout,
std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
bool ApplyConstraints(const flat::LibraryMediator& lib, const TypeConstraints& constraints,
const flat::TypeTemplate* layout, std::unique_ptr<Type>* out_type,
LayoutInvocation* out_params) const override;
};
} // namespace flat
} // namespace fidl
#endif // TOOLS_FIDL_FIDLC_INCLUDE_FIDL_FLAT_TYPES_H_