// Mgmt // Copyright (C) 2013-2024+ James Shubin and the project contributors // Written by James Shubin and the project contributors // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // Additional permission under GNU GPL version 3 section 7 // // If you modify this program, or any covered work, by linking or combining it // with embedded mcl code and modules (and that the embedded mcl code and // modules which link with this program, contain a copy of their source code in // the authoritative form) containing parts covered by the terms of any other // license, the licensors of this program grant you additional permission to // convey the resulting work. Furthermore, the licensors of this program grant // the original author, James Shubin, additional permission to update this // additional permission if he deems it necessary to achieve the goals of this // additional permission. package types import ( "fmt" "reflect" ) // nextPowerOfTwo gets the lowest number higher than v that is a power of two. func nextPowerOfTwo(v uint) uint { v-- v |= v >> 1 v |= v >> 2 v |= v >> 4 v |= v >> 8 v |= v >> 16 v |= v >> 32 v++ return v } // TypeStructTagToFieldName returns a mapping from recommended alias to actual // field name. It returns an error if it finds a collision. It uses the `lang` // tags. It must be passed a reflect.Type representation of a struct or it will // error. // TODO: This is a copy of engineUtil.StructTagToFieldName taking a reflect.Type func TypeStructTagToFieldName(st reflect.Type) (map[string]string, error) { if k := st.Kind(); k != reflect.Struct { // this should be a struct now return nil, fmt.Errorf("input doesn't point to a struct, got: %+v", k) } result := make(map[string]string) // `lang` field tag -> field name for i := 0; i < st.NumField(); i++ { field := st.Field(i) name := field.Name // if !ok, then nothing is found if alias, ok := field.Tag.Lookup(StructTag); ok { // golang 1.7+ if val, exists := result[alias]; exists { return nil, fmt.Errorf("field `%s` uses the same key `%s` as field `%s`", name, alias, val) } // empty string ("") is a valid value if alias != "" { result[alias] = name } } } return result, nil } // Iter applies a function to each type in the top-level type. It stops if that // function errors, and returns that error to the top-level caller. It panics if // it encounters an invalid or partial type struct. This version starts at the // top and works its way deeper. func Iter(typ *Type, fn func(*Type) error) error { if err := fn(typ); err != nil { return err } switch typ.Kind { case KindBool: case KindStr: case KindInt: case KindFloat: case KindList: if typ.Val == nil { panic("malformed list type") } if err := Iter(typ.Val, fn); err != nil { return err } case KindMap: if typ.Key == nil || typ.Val == nil { panic("malformed map type") } if err := Iter(typ.Key, fn); err != nil { return err } if err := Iter(typ.Val, fn); err != nil { return err } case KindStruct: // {a bool; b int} if typ.Map == nil { panic("malformed struct type") } if len(typ.Map) != len(typ.Ord) { panic("malformed struct length") } for _, k := range typ.Ord { t, ok := typ.Map[k] if !ok { panic("malformed struct order") } if t == nil { panic("malformed struct field") } if err := Iter(t, fn); err != nil { return err } } case KindFunc: if typ.Map == nil { panic("malformed func type") } if len(typ.Map) != len(typ.Ord) { panic("malformed func length") } for _, k := range typ.Ord { t, ok := typ.Map[k] if !ok { panic("malformed func order") } if t == nil { panic("malformed func field") } if err := Iter(t, fn); err != nil { return err } } //if typ.Out != nil { if err := Iter(typ.Out, fn); err != nil { return err } //} case KindVariant: if err := Iter(typ.Var, fn); err != nil { return err } case KindUnification: if typ.Uni == nil { panic("malformed unification variable") } // nothing to do default: panic("malformed type") } return nil }