blob: 1589bafb7233c36633e5f053c17248efcaba94d6 [file] [log] [blame]
// Copyright 2022 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 rust_syscall
import (
"embed"
"fmt"
"path/filepath"
"sort"
"strings"
"text/template"
"go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgen"
"go.fuchsia.dev/fuchsia/zircon/tools/zither"
"go.fuchsia.dev/fuchsia/zircon/tools/zither/backends/rust"
)
//go:embed templates/*
var templates embed.FS
type Generator struct {
fidlgen.Generator
}
func NewGenerator(formatter fidlgen.Formatter) *Generator {
gen := fidlgen.NewGenerator("RustSyscallTemplates", templates, formatter, template.FuncMap{
"LowerCaseWithUnderscores": rust.LowerCaseWithUnderscores,
"ParameterType": parameterType,
"ReturnType": returnType,
"LastParameterIndex": func(syscall zither.Syscall) int { return len(syscall.Parameters) - 1 },
})
return &Generator{*gen}
}
func (gen Generator) DeclOrder() zither.DeclOrder { return zither.SourceDeclOrder }
func (gen Generator) DeclCallback(zither.Decl) {}
func (gen *Generator) Generate(summary zither.LibrarySummary, outputDir string) ([]string, error) {
var syscalls []zither.Syscall
for _, summary := range summary.Files {
for _, decl := range summary.Decls {
if !decl.IsSyscallFamily() {
continue
}
for _, syscall := range decl.AsSyscallFamily().Syscalls {
if syscall.IsInternal() {
continue
}
syscalls = append(syscalls, syscall)
}
}
}
sort.Slice(syscalls, func(i, j int) bool {
return strings.Compare(syscalls[i].Name, syscalls[j].Name) < 0
})
outputDir = filepath.Join(outputDir, strings.Join(summary.Library.Parts(), "-"), "src")
definitions := filepath.Join(outputDir, "definitions.rs")
if err := gen.GenerateFile(definitions, "GenerateDefinitions", syscalls); err != nil {
return nil, err
}
return []string{definitions}, nil
}
func typeName(desc zither.TypeDescriptor) string {
return rust.DescribeType(desc, rust.CaseStyleSyscall)
}
//
// Template functions.
//
func parameterType(param zither.SyscallParameter) string {
// Structs and non-inputs should be passed as pointers.
kind := param.Type.Kind
if !kind.IsPointerLike() && (!param.IsStrictInput() || kind == zither.TypeKindStruct) {
elementType := param.Type
elementType.Mutable = !param.IsStrictInput()
return typeName(zither.TypeDescriptor{
Kind: zither.TypeKindPointer,
ElementType: &elementType,
})
}
return typeName(param.Type)
}
func returnType(syscall zither.Syscall) string {
if syscall.ReturnType == nil {
panic(fmt.Sprintf("%s does not have a return type", syscall.Name))
}
return typeName(*syscall.ReturnType)
}