blob: 9078b362c4bb7df560ce7cc278d2c060380ebce3 [file] [log] [blame]
// Copyright 2018 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 codegen
import (
"bytes"
"embed"
"fmt"
"text/template"
cpp "go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgen_cpp"
)
type Generator struct {
*cpp.Generator
}
type TypedArgument struct {
ArgumentName string
ArgumentValue string
ArgumentType cpp.Type
Pointer bool
Nullable bool
Access bool
MutableAccess bool
}
func closeHandles(argumentName string, argumentValue string, argumentType cpp.Type, pointer bool, nullable bool, access bool, mutableAccess bool) string {
if !argumentType.IsResource {
return ""
}
name := argumentName
value := argumentValue
if access {
name = fmt.Sprintf("%s()", name)
value = name
} else if mutableAccess {
name = fmt.Sprintf("mutable_%s()", name)
value = name
}
switch argumentType.Kind {
case cpp.TypeKinds.Handle, cpp.TypeKinds.Request, cpp.TypeKinds.Protocol:
if pointer {
if nullable {
return fmt.Sprintf("if (%s != nullptr) { %s->reset(); }", name, name)
}
return fmt.Sprintf("%s->reset();", name)
} else {
return fmt.Sprintf("%s.reset();", name)
}
case cpp.TypeKinds.Array:
element_name := argumentName + "_element"
element_type := argumentType.ElementType
var buf bytes.Buffer
buf.WriteString("{\n")
buf.WriteString(fmt.Sprintf("%s* %s = %s.data();\n", element_type, element_name, value))
buf.WriteString(fmt.Sprintf("for (size_t i = 0; i < %s.size(); ++i, ++%s) {\n", value, element_name))
buf.WriteString(closeHandles(element_name, fmt.Sprintf("(*%s)", element_name), *element_type, true, false, false, false))
buf.WriteString("\n}\n}\n")
return buf.String()
case cpp.TypeKinds.Vector:
element_name := argumentName + "_element"
element_type := argumentType.ElementType
var buf bytes.Buffer
buf.WriteString("{\n")
buf.WriteString(fmt.Sprintf("%s* %s = %s.mutable_data();\n", element_type, element_name, value))
buf.WriteString(fmt.Sprintf("for (uint64_t i = 0; i < %s.count(); ++i, ++%s) {\n", value, element_name))
buf.WriteString(closeHandles(element_name, fmt.Sprintf("(*%s)", element_name), *element_type, true, false, false, false))
buf.WriteString("\n}\n}\n")
return buf.String()
default:
if pointer {
if nullable {
return fmt.Sprintf("if (%s != nullptr) { %s->_CloseHandles(); }", name, name)
}
return fmt.Sprintf("%s->_CloseHandles();", name)
} else {
return fmt.Sprintf("%s._CloseHandles();", name)
}
}
}
// These are the helper functions we inject for use by the templates.
var utilityFuncs = template.FuncMap{
"SyncCallTotalStackSizeV1": func(m cpp.Method) int {
totalSize := 0
if m.Request.ClientAllocationV1.IsStack {
totalSize += m.Request.ClientAllocationV1.Size
}
if m.Response.ClientAllocationV1.IsStack {
totalSize += m.Response.ClientAllocationV1.Size
}
return totalSize
},
"SyncCallTotalStackSizeV2": func(m cpp.Method) int {
totalSize := 0
if m.Request.ClientAllocationV2.IsStack {
totalSize += m.Request.ClientAllocationV2.Size
}
if m.Response.ClientAllocationV2.IsStack {
totalSize += m.Response.ClientAllocationV2.Size
}
return totalSize
},
"CloseHandles": func(member cpp.Member,
access bool,
mutableAccess bool) string {
n, t := member.NameAndType()
return closeHandles(n, n, t, t.WirePointer, t.WirePointer, access, mutableAccess)
},
}
//go:embed *.tmpl
var templates embed.FS
func NewGenerator(flags *cpp.CmdlineFlags) *cpp.Generator {
return cpp.NewGenerator(flags, templates, utilityFuncs)
}