Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/blueprint/proptools/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 6 kB image not shown  

Quelle  repack.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2024 Google Inc. All rights reserved.
//
// 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.

package proptools

import (
 "fmt"
 "reflect"
 "slices"

 "github.com/google/blueprint/parser"
)

func RepackProperties(props []interface{}) (*parser.Map, error) {

 var dereferencedProps []reflect.Value
 for _, rawProp := range props {
  propStruct := reflect.ValueOf(rawProp)
  if !isStructPtr(propStruct.Type()) {
   return nil, fmt.Errorf("properties must be *struct, got %s",
    propStruct.Type())
  }
  propStruct = propStruct.Elem()
  dereferencedProps = append(dereferencedProps, propStruct)
 }

 return repackStructs(dereferencedProps)
}

func repackStructs(props []reflect.Value) (*parser.Map, error) {
 var allFieldNames []string
 for _, prop := range props {
  propType := prop.Type()
  for i := 0; i < propType.NumField(); i++ {
   field := propType.Field(i)
   if !slices.Contains(allFieldNames, field.Name) {
    allFieldNames = append(allFieldNames, field.Name)
   }
  }
 }

 result := &parser.Map{}

 for _, fieldName := range allFieldNames {
  var fields []reflect.Value
  for _, prop := range props {
   field := prop.FieldByName(fieldName)
   if field.IsValid() {
    fields = append(fields, field)
   }
  }
  if err := assertFieldsEquivalent(fields); err != nil {
   return nil, err
  }

  var expr parser.Expression
  var field reflect.Value
  for _, f := range fields {
   if !isPropEmpty(f) {
    field = f
    break
   }
  }
  if !field.IsValid() {
   continue
  }
  if isStruct(field.Type()) && !isConfigurable(field.Type()) {
   x, err := repackStructs(fields)
   if err != nil {
    return nil, err
   }
   if x != nil {
    expr = x
   }
  } else {
   x, err := fieldToExpr(field)
   if err != nil {
    return nil, err
   }
   if x != nil {
    expr = *x
   }
  }

  if expr != nil {
   result.Properties = append(result.Properties, &parser.Property{
    Name:  PropertyNameForField(fieldName),
    Value: expr,
   })
  }
 }

 return result, nil
}

func fieldToExpr(field reflect.Value) (*parser.Expression, error) {
 if IsConfigurable(field.Type()) {
  return field.Interface().(configurableReflection).toExpression()
 }
 if field.Kind() == reflect.Pointer {
  if field.IsNil() {
   return nil, nil
  }
  field = field.Elem()
 }
 switch field.Kind() {
 case reflect.String:
  var result parser.Expression = &parser.String{Value: field.String()}
  return &result, nil
 case reflect.Bool:
  var result parser.Expression = &parser.Bool{Value: field.Bool()}
  return &result, nil
 case reflect.Int, reflect.Int64:
  var result parser.Expression = &parser.Int64{Value: field.Int()}
  return &result, nil
 case reflect.Slice:
  var contents []parser.Expression
  for i := 0; i < field.Len(); i++ {
   inner, err := fieldToExpr(field.Index(i))
   if err != nil {
    return nil, err
   }
   contents = append(contents, *inner)
  }
  var result parser.Expression = &parser.List{Values: contents}
  return &result, nil
 case reflect.Struct:
  var properties []*parser.Property
  typ := field.Type()
  for i := 0; i < typ.NumField(); i++ {
   inner, err := fieldToExpr(field.Field(i))
   if err != nil {
    return nil, err
   }
   properties = append(properties, &parser.Property{
    Name:  typ.Field(i).Name,
    Value: *inner,
   })
  }
  var result parser.Expression = &parser.Map{Properties: properties}
  return &result, nil
 default:
  return nil, fmt.Errorf("Unhandled type: %s", field.Kind().String())
 }
}

func isPropEmpty(value reflect.Value) bool {
 switch value.Kind() {
 case reflect.Pointer:
  if value.IsNil() {
   return true
  }
  return isPropEmpty(value.Elem())
 case reflect.Struct:
  if isConfigurable(value.Type()) {
   return value.Interface().(configurableReflection).isEmpty()
  }
  for i := 0; i < value.NumField(); i++ {
   if !isPropEmpty(value.Field(i)) {
    return false
   }
  }
  return true
 default:
  return false
 }
}

func assertFieldsEquivalent(fields []reflect.Value) error {
 var firstNonEmpty reflect.Value
 var firstIndex int
 for i, f := range fields {
  if !isPropEmpty(f) {
   firstNonEmpty = f
   firstIndex = i
   break
  }
 }
 if !firstNonEmpty.IsValid() {
  return nil
 }
 for i, f := range fields {
  if i != firstIndex && !isPropEmpty(f) {
   if err := assertTwoNonEmptyFieldsEquivalent(firstNonEmpty, f); err != nil {
    return err
   }
  }
 }
 return nil
}

func assertTwoNonEmptyFieldsEquivalent(a, b reflect.Value) error {
 aType := a.Type()
 bType := b.Type()

 if aType != bType {
  return fmt.Errorf("fields must have the same type")
 }

 switch aType.Kind() {
 case reflect.Pointer:
  return assertTwoNonEmptyFieldsEquivalent(a.Elem(), b.Elem())
 case reflect.String:
  if a.String() != b.String() {
   return fmt.Errorf("Conflicting fields in property structs had values %q and %q", a.String(), b.String())
  }
 case reflect.Bool:
  if a.Bool() != b.Bool() {
   return fmt.Errorf("Conflicting fields in property structs had values %t and %t", a.Bool(), b.Bool())
  }
 case reflect.Slice:
  if a.Len() != b.Len() {
   return fmt.Errorf("Conflicting fields in property structs had lengths %d and %d", a.Len(), b.Len())
  }
  for i := 0; i < a.Len(); i++ {
   if err := assertTwoNonEmptyFieldsEquivalent(a.Index(i), b.Index(i)); err != nil {
    return err
   }
  }
 case reflect.Int:
  if a.Int() != b.Int() {
   return fmt.Errorf("Conflicting fields in property structs had values %d and %d", a.Int(), b.Int())
  }
 case reflect.Struct:
  if isConfigurable(a.Type()) {
   // We could properly check that two configurables are equivalent, but that's a lot more
   // work for a case that I don't think should show up in practice.
   return fmt.Errorf("Cannot handle two property structs with nonempty configurable properties")
  }
  // We don't care about checking if structs are equivalent, we'll check their individual
  // fields when we recurse down.
 default:
  return fmt.Errorf("Unhandled kind: %s", aType.Kind().String())
 }

 return nil
}

[Dauer der Verarbeitung: 0.21 Sekunden, vorverarbeitet 2026-06-28]