github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/commons/container/trees/element.go (about)

     1  /*
     2   * Copyright 2023 Wang Min Xiang
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   * 	http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   */
    17  
    18  package trees
    19  
    20  import (
    21  	"fmt"
    22  	"reflect"
    23  	"strings"
    24  )
    25  
    26  func NewElement[T any](v T) (element *Element[T], err error) {
    27  	rv := reflect.ValueOf(v)
    28  	ptr := rv.Type().Kind() == reflect.Ptr
    29  	if !ptr {
    30  		rv = reflect.ValueOf(&v)
    31  	}
    32  	ok := false
    33  	identFieldName := ""
    34  	parentFieldName := ""
    35  	childrenFieldName := ""
    36  	childPtr := false
    37  	rt := reflect.Indirect(rv).Type()
    38  	for i := 0; i < rt.NumField(); i++ {
    39  		field := rt.Field(i)
    40  		tag, has := field.Tag.Lookup(treeTag)
    41  		if !has {
    42  			continue
    43  		}
    44  		idx := strings.Index(tag, "+")
    45  		if idx < 1 || idx == len(tag)-1 {
    46  			err = fmt.Errorf("tree tag is invalid")
    47  			return
    48  		}
    49  		// parent
    50  		parentName := strings.TrimSpace(tag[0:idx])
    51  		parentField, hasParentField := rt.FieldByName(parentName)
    52  		if !hasParentField {
    53  			err = fmt.Errorf("parent field was not found")
    54  			return
    55  		}
    56  		if !parentField.IsExported() {
    57  			err = fmt.Errorf("parent field was not exported")
    58  			return
    59  		}
    60  		if parentField.Anonymous {
    61  			err = fmt.Errorf("parent field can not be anonymous")
    62  			return
    63  		}
    64  		if parentField.Type != field.Type {
    65  			err = fmt.Errorf("type of parent field does not match ident field type")
    66  			return
    67  		}
    68  		parentFieldName = parentName
    69  		// children
    70  		childrenName := strings.TrimSpace(tag[idx+1:])
    71  		childrenField, hasChildrenField := rt.FieldByName(childrenName)
    72  		if !hasChildrenField {
    73  			err = fmt.Errorf("children field was not found")
    74  			return
    75  		}
    76  		if !childrenField.IsExported() {
    77  			err = fmt.Errorf("children field was not exported")
    78  			return
    79  		}
    80  		if childrenField.Anonymous {
    81  			err = fmt.Errorf("children field can not be anonymous")
    82  			return
    83  		}
    84  		if childrenField.Type.Kind() != reflect.Slice {
    85  			err = fmt.Errorf("children field was not slice")
    86  			return
    87  		}
    88  		childrenElementType := childrenField.Type.Elem()
    89  		childPtr = childrenElementType.Kind() == reflect.Ptr
    90  		if childPtr {
    91  			childrenElementType = childrenElementType.Elem()
    92  		}
    93  		if childrenElementType.PkgPath() != rt.PkgPath() && childrenElementType.Name() != rt.Name() {
    94  			err = fmt.Errorf("element type of children field was not matched")
    95  			return
    96  		}
    97  		childrenFieldName = childrenName
    98  		// ident
    99  		identFieldName = field.Name
   100  		ok = true
   101  		break
   102  	}
   103  	if !ok {
   104  		err = fmt.Errorf("%s.%s is not tree struct", rt.PkgPath(), rt.Name())
   105  		return
   106  	}
   107  	element = &Element[T]{
   108  		ptr:           ptr,
   109  		childPtr:      childPtr,
   110  		value:         rv,
   111  		identField:    identFieldName,
   112  		parentField:   parentFieldName,
   113  		childrenField: childrenFieldName,
   114  		children:      make(Elements[T], 0, 1),
   115  		hasParent:     false,
   116  	}
   117  	return
   118  }
   119  
   120  type Element[T any] struct {
   121  	ptr           bool
   122  	childPtr      bool
   123  	value         reflect.Value
   124  	identField    string
   125  	parentField   string
   126  	childrenField string
   127  	children      Elements[T]
   128  	hasParent     bool
   129  }
   130  
   131  func (element *Element[T]) ident() reflect.Value {
   132  	return element.value.Elem().FieldByName(element.identField)
   133  }
   134  
   135  func (element *Element[T]) parent() reflect.Value {
   136  	return element.value.Elem().FieldByName(element.parentField)
   137  }
   138  
   139  func (element *Element[T]) Interface() (v T) {
   140  	children := reflect.MakeSlice(element.value.Elem().FieldByName(element.childrenField).Type(), 0, 1)
   141  	for _, child := range element.children {
   142  		cv := child.Interface()
   143  		if element.childPtr {
   144  			if element.ptr {
   145  				children = reflect.Append(children, reflect.ValueOf(cv))
   146  			} else {
   147  				children = reflect.Append(children, reflect.ValueOf(&cv))
   148  			}
   149  		} else {
   150  			if element.ptr {
   151  				children = reflect.Append(children, reflect.ValueOf(cv).Elem())
   152  			} else {
   153  				children = reflect.Append(children, reflect.ValueOf(cv))
   154  			}
   155  		}
   156  	}
   157  	if children.Len() > 0 {
   158  		element.value.Elem().FieldByName(element.childrenField).Set(children)
   159  	}
   160  
   161  	if element.ptr {
   162  		v = element.value.Interface().(T)
   163  		return
   164  	}
   165  	v = element.value.Elem().Interface().(T)
   166  	return
   167  }
   168  
   169  func (element *Element[T]) contains(child *Element[T]) (ok bool) {
   170  	for _, e := range element.children {
   171  		if e.value.Equal(child.value) {
   172  			ok = true
   173  			break
   174  		}
   175  	}
   176  	return
   177  }
   178  
   179  type Elements[T any] []*Element[T]
   180  
   181  func (elements Elements[T]) Len() int {
   182  	return len(elements)
   183  }
   184  
   185  func (elements Elements[T]) Less(i, j int) bool {
   186  	switch elements[i].ident().Type().Kind() {
   187  	case reflect.String:
   188  		return elements[i].ident().String() < elements[j].ident().String()
   189  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   190  		return elements[i].ident().Int() < elements[j].ident().Int()
   191  	case reflect.Float32, reflect.Float64:
   192  		return elements[i].ident().Float() < elements[j].ident().Float()
   193  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   194  		return elements[i].ident().Uint() < elements[j].ident().Uint()
   195  	case reflect.Uintptr:
   196  		return elements[i].ident().Interface().(uintptr) < elements[j].ident().Interface().(uintptr)
   197  	default:
   198  		return false
   199  	}
   200  }
   201  
   202  func (elements Elements[T]) Swap(i, j int) {
   203  	elements[i], elements[j] = elements[j], elements[i]
   204  }