| // Copyright 2019 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 ir |
| |
| import ( |
| "reflect" |
| |
| "go.fuchsia.dev/fuchsia/tools/fidl/gidl/config" |
| ) |
| |
| func Merge(input []All) All { |
| var output All |
| for _, elem := range input { |
| for _, encodeSuccess := range elem.EncodeSuccess { |
| output.EncodeSuccess = append(output.EncodeSuccess, encodeSuccess) |
| } |
| for _, decodeSuccess := range elem.DecodeSuccess { |
| output.DecodeSuccess = append(output.DecodeSuccess, decodeSuccess) |
| } |
| for _, encodeFailure := range elem.EncodeFailure { |
| output.EncodeFailure = append(output.EncodeFailure, encodeFailure) |
| } |
| for _, decodeFailure := range elem.DecodeFailure { |
| output.DecodeFailure = append(output.DecodeFailure, decodeFailure) |
| } |
| for _, benchmark := range elem.Benchmark { |
| output.Benchmark = append(output.Benchmark, benchmark) |
| } |
| } |
| return output |
| } |
| |
| func FilterByBinding(input All, binding string) All { |
| shouldKeep := func(binding string, allowlist *LanguageList, denylist *LanguageList) bool { |
| if denylist != nil && denylist.Includes(binding) { |
| return false |
| } |
| if allowlist != nil { |
| return allowlist.Includes(binding) |
| } |
| if LanguageList(config.DefaultBindingsDenylist).Includes(binding) { |
| return false |
| } |
| return true |
| } |
| var output All |
| for _, def := range input.EncodeSuccess { |
| if shouldKeep(binding, def.BindingsAllowlist, def.BindingsDenylist) { |
| output.EncodeSuccess = append(output.EncodeSuccess, def) |
| } |
| } |
| for _, def := range input.DecodeSuccess { |
| if shouldKeep(binding, def.BindingsAllowlist, def.BindingsDenylist) { |
| output.DecodeSuccess = append(output.DecodeSuccess, def) |
| } |
| } |
| for _, def := range input.EncodeFailure { |
| if shouldKeep(binding, def.BindingsAllowlist, def.BindingsDenylist) { |
| output.EncodeFailure = append(output.EncodeFailure, def) |
| } |
| } |
| for _, def := range input.DecodeFailure { |
| if shouldKeep(binding, def.BindingsAllowlist, def.BindingsDenylist) { |
| output.DecodeFailure = append(output.DecodeFailure, def) |
| } |
| } |
| for _, def := range input.Benchmark { |
| if shouldKeep(binding, def.BindingsAllowlist, def.BindingsDenylist) { |
| output.Benchmark = append(output.Benchmark, def) |
| } |
| } |
| return output |
| } |
| |
| func ValidateAllType(input All, generatorType string) { |
| forbid := func(fields ...interface{}) { |
| for _, field := range fields { |
| if reflect.ValueOf(field).Len() > 0 { |
| panic("illegal field specified") |
| } |
| } |
| } |
| switch generatorType { |
| case "conformance": |
| forbid(input.Benchmark) |
| case "benchmark": |
| forbid(input.EncodeSuccess, input.DecodeSuccess, input.EncodeFailure, input.DecodeFailure) |
| default: |
| panic("unknown case: expected 'conformance' or 'benchmark'") |
| } |
| } |
| |
| // ContainsUnknownField returns if the value or any subvalue contains an unknown |
| // field. |
| // Intended to allow bindings that don't support unknown fields to skip test |
| // cases that contain them. |
| func ContainsUnknownField(value Value) bool { |
| switch value := value.(type) { |
| case Record: |
| for _, f := range value.Fields { |
| if f.Key.IsUnknown() { |
| return true |
| } |
| if ContainsUnknownField(f.Value) { |
| return true |
| } |
| } |
| return false |
| case []Value: |
| for _, v := range value { |
| if ContainsUnknownField(v) { |
| return true |
| } |
| } |
| return false |
| default: |
| return false |
| } |
| } |
| |
| func TypeFromValue(value Value) string { |
| record, ok := value.(Record) |
| if !ok { |
| panic("only can extract type name from struct value") |
| } |
| return record.Name |
| } |
| |
| func GetHandlesFromHandleDispositions(handleDispositions []HandleDisposition) []Handle { |
| var handles []Handle |
| for _, handleDisposition := range handleDispositions { |
| handles = append(handles, handleDisposition.Handle) |
| } |
| return handles |
| } |
| |
| // GetUnusedHandles returns the list of handles from the input slice that do not |
| // appear in the provided Value |
| func GetUnusedHandles(value Value, handles []Handle) []Handle { |
| usedHandles := make(map[Handle]struct{}) |
| populateUsedHandles(value, usedHandles) |
| |
| var unused []Handle |
| for _, handle := range handles { |
| if _, ok := usedHandles[handle]; !ok { |
| unused = append(unused, handle) |
| } |
| } |
| return unused |
| } |
| |
| func populateUsedHandles(value Value, seen map[Handle]struct{}) { |
| switch value := value.(type) { |
| case Handle: |
| seen[value] = struct{}{} |
| case Record: |
| for _, field := range value.Fields { |
| populateUsedHandles(field.Value, seen) |
| } |
| case UnknownData: |
| for _, handle := range value.Handles { |
| seen[handle] = struct{}{} |
| } |
| case []Value: |
| for _, item := range value { |
| populateUsedHandles(item, seen) |
| } |
| } |
| } |