blob: 8eea3006745b8678a0ee703f7545122f962a0c7e [file] [log] [blame]
// Copyright 2021 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.
package fidlgen_cpp
import (
"sort"
"strings"
"go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgen"
)
// These correspond to templated classes forward-declared in
// //src/lib/fidl/include/lib/fidl/cpp/internal/natural_types.h
var (
DesignatedInitializationProxy = internalNs.member("DesignatedInitializationProxy")
TypeTraits = internalNs.member("TypeTraits")
)
type Struct struct {
Attributes
fidlgen.Resourceness
nameVariants
AnonymousChildren []ScopedLayout
CodingTableType string
Members []StructMember
BackingBufferTypeV1 string
BackingBufferTypeV2 string
Result *Result
// Full decls needed to check if a type is memcpy compatible.
// Only set if it may be possible for a type to be memcpy compatible,
// e.g. has no padding.
// See the struct template for usage.
FullDeclMemcpyCompatibleDeps []string
TypeShapeV1 TypeShape
TypeShapeV2 TypeShape
// DesignatedInitializationProxy is the name of the internal aggregate
// type associated with this struct in natural domain objects,
// to support designated initialization.
DesignatedInitializationProxy name
// TypeTraits contains information about a natural domain object.
TypeTraits name
isEmptyStruct bool
isRequestOrResponse bool
}
func (*Struct) Kind() declKind {
return Kinds.Struct
}
// IsRequestOrResponse indicates whether this struct is used as a method
// request/response.
func (s *Struct) IsRequestOrResponse() bool {
return s.isRequestOrResponse
}
var _ Kinded = (*Struct)(nil)
var _ namespaced = (*Struct)(nil)
type StructMember struct {
Attributes
nameVariants
Type Type
DefaultValue ConstantValue
OffsetV1 int
OffsetV2 int
HandleInformation *HandleInformation
}
func (m StructMember) AsParameter() Parameter {
return Parameter{
nameVariants: m.nameVariants,
Type: m.Type,
OffsetV1: m.OffsetV1,
OffsetV2: m.OffsetV2,
HandleInformation: m.HandleInformation,
}
}
func (sm StructMember) NameAndType() (string, Type) {
return sm.Name(), sm.Type
}
var _ Member = (*StructMember)(nil)
func (c *compiler) compileStructMember(val fidlgen.StructMember) StructMember {
t := c.compileType(val.Type)
defaultValue := ConstantValue{}
if val.MaybeDefaultValue != nil {
defaultValue = c.compileConstant(*val.MaybeDefaultValue, &t, val.Type)
}
return StructMember{
Attributes: Attributes{val.Attributes},
nameVariants: structMemberContext.transform(val.Name),
Type: t,
DefaultValue: defaultValue,
OffsetV1: val.FieldShapeV1.Offset,
OffsetV2: val.FieldShapeV2.Offset,
HandleInformation: c.fieldHandleInformation(&val.Type),
}
}
func (c *compiler) compileStruct(val fidlgen.Struct) *Struct {
name := c.compileNameVariants(val.Name)
codingTableType := c.compileCodingTableType(val.Name)
r := Struct{
Attributes: Attributes{val.Attributes},
AnonymousChildren: c.getAnonymousChildren(val.Layout),
TypeShapeV1: TypeShape{val.TypeShapeV1},
TypeShapeV2: TypeShape{val.TypeShapeV2},
Resourceness: val.Resourceness,
nameVariants: name,
CodingTableType: codingTableType,
Members: []StructMember{},
BackingBufferTypeV1: computeAllocation(
TypeShape{val.TypeShapeV1}.MaxTotalSize(), boundednessBounded).
BackingBufferType(),
BackingBufferTypeV2: computeAllocation(
TypeShape{val.TypeShapeV2}.MaxTotalSize(), boundednessBounded).
BackingBufferType(),
DesignatedInitializationProxy: DesignatedInitializationProxy.template(name.Unified),
TypeTraits: TypeTraits.template(name.Unified),
isRequestOrResponse: val.IsRequestOrResponse,
}
for _, v := range val.Members {
r.Members = append(r.Members, c.compileStructMember(v))
}
if len(r.Members) == 0 {
r.isEmptyStruct = true
r.Members = []StructMember{
c.compileStructMember(fidlgen.EmptyStructMember("__reserved")),
}
}
// Construct a deduped list of decls for IsMemcpyCompatible template definitions.
memcpyCompatibleDepMap := make(map[string]struct{})
for _, member := range r.Members {
// The dangerous identifiers test package contains identifiers that won't compile.
// e.g. ::fidl::test::dangerous::struct::types::camel::Interface gives an
// "expected unqualified-id" error because of "struct".
// There isn't an easily accessible dangerous identifiers list to replace identifiers.
if strings.Contains(member.Type.HLCPP.String(), "::fidl::test::dangerous::") {
memcpyCompatibleDepMap = nil
break
}
memcpyCompatibleDepMap[member.Type.HLCPP.String()] = struct{}{}
}
for decl := range memcpyCompatibleDepMap {
r.FullDeclMemcpyCompatibleDeps = append(r.FullDeclMemcpyCompatibleDeps, decl)
}
sort.Strings(r.FullDeclMemcpyCompatibleDeps)
return &r
}