go-ml.dev/pkg/base@v0.0.0-20200610162856-60c38abac71b/tables/enum.go (about) 1 package tables 2 3 import ( 4 "fmt" 5 "go-ml.dev/pkg/base/fu" 6 "golang.org/x/xerrors" 7 "reflect" 8 "sync" 9 ) 10 11 var enumType = reflect.TypeOf(Enum{}) 12 13 /* 14 Enum encapsulate enumeration abstraction in relation to tables 15 */ 16 type Enum struct { 17 Text string 18 Value int 19 } 20 21 // Text return enum string representation 22 func (e Enum) String() string { 23 return e.Text 24 } 25 26 // Enum defines enumerated meta-column with the Enum tipe 27 func (e Enumset) Enum() Meta { 28 return Enumerator{e, &sync.Mutex{}, len(e) != 0} 29 } 30 31 // Enum defines enumerated meta-column with the string type 32 func (e Enumset) Text() Meta { 33 return TextEnumerator{Enumerator{e, &sync.Mutex{}, len(e) != 0}} 34 } 35 36 // Enum defines enumerated meta-column with the int type 37 func (e Enumset) Integer() Meta { 38 return IntegerEnumerator{ 39 Enumerator{e, &sync.Mutex{}, len(e) != 0}, 40 fu.KeysOf((map[string]int)(e)).([]string), 41 } 42 } 43 44 // Enum defines enumerated meta-column with the float32 type 45 func (e Enumset) Float32() Meta { 46 return Float32Enumerator{ 47 IntegerEnumerator{ 48 Enumerator{e, &sync.Mutex{}, len(e) != 0}, 49 fu.KeysOf((map[string]int)(e)).([]string), 50 }} 51 } 52 53 // Enumset is a set of values belongs to one enumeration 54 type Enumset map[string]int 55 56 // Len returns length of enumset aka count of enum values 57 func (m Enumset) Len() int { 58 return len(m) 59 } 60 61 // Enumerator the object enumerates enums in data stream 62 type Enumerator struct { 63 m Enumset 64 mu *sync.Mutex 65 ro bool 66 } 67 68 func (ce Enumerator) enumerate(v string) (e int, ok bool) { 69 ce.mu.Lock() 70 if e, ok = ce.m[v]; !ok { 71 if ce.ro { 72 panic(xerrors.Errorf("readonly enumset does not have value `%v`" + v)) 73 } 74 ce.m[v] = len(ce.m) 75 } 76 ce.mu.Unlock() 77 return 78 } 79 80 // Type returns the type of column 81 func (ce Enumerator) Type() reflect.Type { 82 return enumType // it's the Enum meta-column 83 } 84 func (ce Enumerator) Convert(v string, value *reflect.Value, _, _ int) (na bool, err error) { 85 if v == "" { 86 *value = reflect.ValueOf("") 87 return true, nil 88 } 89 e, _ := ce.enumerate(v) 90 *value = reflect.ValueOf(Enum{v, e}) 91 return 92 } 93 func (ce Enumerator) Format(x reflect.Value, na bool) string { 94 if na { 95 return "" 96 } 97 if x.Type() == enumType { 98 text := x.Interface().(Enum).Text 99 if _, ok := ce.m[text]; ok { 100 return text 101 } 102 } 103 panic(xerrors.Errorf("`%v` is not an enumeration value", x)) 104 } 105 106 type IntegerEnumerator struct { 107 Enumerator 108 rev []string 109 } 110 111 func (ce IntegerEnumerator) Type() reflect.Type { 112 return fu.Int 113 } 114 115 func (ce IntegerEnumerator) Convert(v string, value *reflect.Value, _, _ int) (bool, error) { 116 if v == "" { 117 *value = reflect.ValueOf("") 118 return true, nil 119 } 120 e, ok := ce.enumerate(v) 121 if !ok { 122 ce.mu.Lock() 123 ce.rev = append(ce.rev, v) 124 ce.mu.Unlock() 125 } 126 *value = reflect.ValueOf(e) 127 return false, nil 128 } 129 130 func (ce IntegerEnumerator) Format(x reflect.Value, na bool) string { 131 if na { 132 return "" 133 } 134 if x.Kind() == reflect.String { 135 text := x.String() 136 if e, ok := ce.m[text]; ok { 137 return fmt.Sprint(e) 138 } 139 } 140 panic(xerrors.Errorf("`%v` is not an enumeration value", x)) 141 } 142 143 type Float32Enumerator struct{ IntegerEnumerator } 144 145 func (ce Float32Enumerator) Type() reflect.Type { 146 return fu.Float32 147 } 148 149 func (ce Float32Enumerator) Convert(v string, value *reflect.Value, _, _ int) (na bool, err error) { 150 val := reflect.Value{} 151 if na, err = ce.IntegerEnumerator.Convert(v, &val, 0, 0); err == nil { 152 *value = reflect.ValueOf(float32(val.Int())) 153 } 154 return 155 } 156 157 type TextEnumerator struct{ Enumerator } 158 159 func (ce TextEnumerator) Type() reflect.Type { 160 return fu.String 161 } 162 163 func (ce TextEnumerator) Convert(v string, value *reflect.Value, _, _ int) (bool, error) { 164 if v == "" { 165 *value = reflect.ValueOf("") 166 return true, nil 167 } 168 ce.enumerate(v) 169 *value = reflect.ValueOf(v) 170 return false, nil 171 }