Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

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]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik