| // Copyright (C) 2015 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| //go:generate embed |
| |
| // Package generate contains the rpc code generation functionality. |
| package generate |
| |
| import ( |
| "bytes" |
| "fmt" |
| "io" |
| "path/filepath" |
| "strings" |
| |
| "android.googlesource.com/platform/tools/gpu/api/apic/template" |
| "android.googlesource.com/platform/tools/gpu/api/semantic" |
| binary "android.googlesource.com/platform/tools/gpu/binary/generate" |
| ) |
| |
| func loader(filename string) ([]byte, error) { |
| s, ok := embedded[filename] |
| if !ok { |
| return nil, fmt.Errorf("Unknown embedded filename %s", filename) |
| } |
| return []byte(s), nil |
| } |
| |
| func fromType(from semantic.Type) *binary.Type { |
| native := "" |
| switch from { |
| case semantic.BoolType: |
| native = "Bool" |
| case semantic.IntType: |
| native = "Int" |
| case semantic.UintType: |
| native = "Uint" |
| case semantic.Int8Type: |
| native = "Int8" |
| case semantic.Uint8Type: |
| native = "Uint8" |
| case semantic.Int16Type: |
| native = "Int16" |
| case semantic.Uint16Type: |
| native = "Uint16" |
| case semantic.Int32Type: |
| native = "Int32" |
| case semantic.Uint32Type: |
| native = "Uint32" |
| case semantic.Float32Type: |
| native = "Float32" |
| case semantic.Float64Type: |
| native = "Float64" |
| case semantic.Int64Type: |
| native = "Int64" |
| case semantic.Uint64Type: |
| native = "Uint64" |
| case semantic.StringType: |
| native = "String" |
| } |
| if native != "" { |
| return &binary.Type{ |
| Name: strings.ToLower(native), |
| Kind: binary.Native, |
| Method: native, |
| } |
| } |
| switch from := from.(type) { |
| case *semantic.Enum: |
| return &binary.Type{ |
| Name: from.Typename(), |
| Kind: binary.Remap, |
| Method: "Int32", |
| Native: "int32", |
| } |
| case *semantic.Pointer: |
| t := &binary.Type{ |
| Kind: binary.Pointer, |
| SubType: fromType(from.To), |
| } |
| if t.SubType.Kind != binary.Interface { |
| t.Name = fmt.Sprintf("*%s", t.SubType.Name) |
| } else { |
| t.Name = t.SubType.Name |
| } |
| return t |
| case *semantic.Array: |
| t := &binary.Type{ |
| Kind: binary.Array, |
| SubType: fromType(from.ValueType), |
| } |
| name := t.SubType.Name |
| switch t.SubType.Kind { |
| case binary.Pointer: |
| name = t.SubType.SubType.Name |
| case binary.Native: |
| name = t.SubType.Method |
| switch name { |
| case "Uint8": |
| name = "U8" |
| case "Int8": |
| name = "S8" |
| case "Uint16": |
| name = "U16" |
| case "Int16": |
| name = "S16" |
| case "Uint32": |
| name = "U32" |
| case "Int32": |
| name = "S32" |
| case "Uint64": |
| name = "U64" |
| case "Int64": |
| name = "S64" |
| case "Float32": |
| name = "F32" |
| case "Float64": |
| name = "F64" |
| } |
| } |
| t.Name = fmt.Sprintf("%sArray", name) |
| return t |
| case *semantic.Class: |
| if from.GetAnnotation("Interface") != nil { |
| return &binary.Type{ |
| Name: from.Typename(), |
| Kind: binary.Interface, |
| } |
| } |
| return &binary.Type{ |
| Name: from.Typename(), |
| Kind: binary.Codeable, |
| } |
| default: |
| return &binary.Type{ |
| Name: from.Typename(), |
| Kind: binary.Codeable, |
| } |
| } |
| } |
| |
| func addFields(s *binary.Struct, c *semantic.Class) { |
| for _, e := range c.Extends { |
| addFields(s, e) |
| } |
| for _, decl := range c.Fields { |
| f := binary.Field{ |
| Name: decl.Name, |
| Type: fromType(decl.Type), |
| } |
| s.Fields = append(s.Fields, f) |
| } |
| } |
| |
| func converter(pkgName string) func(api *semantic.API) *binary.File { |
| return func(api *semantic.API) *binary.File { |
| result := &binary.File{ |
| Package: pkgName, |
| Generated: "rpcapi", |
| } |
| for _, cmd := range api.Functions { |
| params := &binary.Struct{ |
| Name: fmt.Sprintf("call%s", cmd.Name), |
| Package: pkgName, |
| } |
| for _, decl := range cmd.CallParameters() { |
| f := binary.Field{ |
| Name: decl.Name, |
| Type: fromType(decl.Type), |
| } |
| params.Fields = append(params.Fields, f) |
| } |
| params.UpdateID() |
| result.Structs = append(result.Structs, params) |
| ret := &binary.Struct{ |
| Name: fmt.Sprintf("result%s", cmd.Name), |
| Package: pkgName, |
| } |
| for _, decl := range cmd.Outputs { |
| f := binary.Field{ |
| Name: decl.Name, |
| Type: fromType(cmd.Return.Type), |
| } |
| // TODO: remove naming hack |
| if decl == cmd.Return { |
| f.Name = "value" |
| } |
| ret.Fields = append(ret.Fields, f) |
| } |
| ret.UpdateID() |
| result.Structs = append(result.Structs, ret) |
| } |
| for _, c := range api.Classes { |
| if c.GetAnnotation("Interface") != nil { |
| continue |
| } |
| s := &binary.Struct{Name: c.Name, Package: pkgName} |
| addFields(s, c) |
| s.UpdateID() |
| result.Structs = append(result.Structs, s) |
| } |
| binary.Sort(result.Structs) |
| return result |
| } |
| } |
| |
| func wrapStructWriter(f func(io.Writer, *binary.Struct) error) func(s *binary.Struct) string { |
| return func(s *binary.Struct) string { |
| b := &bytes.Buffer{} |
| f(b, s) |
| return b.String() |
| } |
| } |
| |
| func wrapFileWriter(f func(*binary.File) ([]byte, error)) func(s *binary.File) string { |
| return func(s *binary.File) string { |
| result, _ := f(s) |
| return string(result) |
| } |
| } |
| |
| // Init prepares a new template processor that layers the apic one with |
| // the functions from the binary codec generate package. |
| func Init(apiFile string, api *semantic.API) *template.Functions { |
| apiFile, _ = filepath.Abs(apiFile) |
| pkg := filepath.Base(filepath.Dir(apiFile)) |
| return template.NewFunctions(apiFile, api, loader, map[string]interface{}{ |
| "ConvertAPI": converter(pkg), |
| "GoRegister": wrapStructWriter(binary.GoRegister), |
| "GoEncoder": wrapStructWriter(binary.GoEncoder), |
| "GoDecoder": wrapStructWriter(binary.GoDecoder), |
| "GoFile": wrapFileWriter(binary.GoFile), |
| "JavaFile": wrapFileWriter(binary.JavaFile), |
| }) |
| } |
| |
| // Go invokes the main go code generation template. |
| func Go(f *template.Functions) error { |
| return f.Include(rpc_go_tmpl_file) |
| } |
| |
| // Java invokes the main go code generation template. |
| func Java(f *template.Functions) error { |
| return f.Include(rpc_java_tmpl_file) |
| } |