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 }