github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/define_array_type.go (about) 1 package lang 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/lmorg/murex/lang/stdio" 8 "github.com/lmorg/murex/lang/types" 9 "github.com/lmorg/murex/utils" 10 "github.com/lmorg/murex/utils/consts" 11 ) 12 13 // ArrayWithTypeTemplate is a template function for reading arrays from marshalled data 14 func ArrayWithTypeTemplate(ctx context.Context, dataType string, marshal func(interface{}) ([]byte, error), unmarshal func([]byte, interface{}) error, read stdio.Io, callback func(interface{}, string)) error { 15 b, err := read.ReadAll() 16 if err != nil { 17 return err 18 } 19 20 if len(utils.CrLfTrim(b)) == 0 { 21 return nil 22 } 23 24 var v interface{} 25 err = unmarshal(b, &v) 26 27 if err != nil { 28 return err 29 } 30 31 switch v := v.(type) { 32 case []interface{}: 33 return readArrayWithTypeBySliceInterface(ctx, dataType, marshal, v, callback) 34 35 case []string: 36 return readArrayWithTypeBySliceString(ctx, v, callback) 37 38 case []float64: 39 return readArrayWithTypeBySliceFloat(ctx, v, callback) 40 41 case []int: 42 return readArrayWithTypeBySliceInt(ctx, v, callback) 43 44 case []bool: 45 return readArrayWithTypeBySliceBool(ctx, v, callback) 46 47 case string: 48 return readArrayWithTypeByString(v, callback) 49 50 case []byte: 51 return readArrayWithTypeByString(string(v), callback) 52 53 case []rune: 54 return readArrayWithTypeByString(string(v), callback) 55 56 case map[string]string: 57 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 58 59 case map[string]interface{}: 60 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 61 62 case map[interface{}]string: 63 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 64 65 case map[interface{}]interface{}: 66 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 67 68 case map[int]string: 69 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 70 71 case map[int]interface{}: 72 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 73 74 case map[float64]string: 75 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 76 77 case map[float64]interface{}: 78 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 79 80 default: 81 return fmt.Errorf("cannot turn %T into an array\n%s", v, consts.IssueTrackerURL) 82 } 83 } 84 85 func readArrayWithTypeByString(v string, callback func(interface{}, string)) error { 86 callback(v, types.String) 87 88 return nil 89 } 90 91 func readArrayWithTypeBySliceInt(ctx context.Context, v []int, callback func(interface{}, string)) error { 92 for i := range v { 93 select { 94 case <-ctx.Done(): 95 return nil 96 97 default: 98 callback(v[i], types.Integer) 99 } 100 } 101 102 return nil 103 } 104 105 func readArrayWithTypeBySliceFloat(ctx context.Context, v []float64, callback func(interface{}, string)) error { 106 for i := range v { 107 select { 108 case <-ctx.Done(): 109 return nil 110 111 default: 112 callback(v[i], types.Number) 113 } 114 } 115 116 return nil 117 } 118 119 func readArrayWithTypeBySliceBool(ctx context.Context, v []bool, callback func(interface{}, string)) error { 120 for i := range v { 121 select { 122 case <-ctx.Done(): 123 return nil 124 125 default: 126 callback(v[i], types.Boolean) 127 128 } 129 } 130 131 return nil 132 } 133 134 func readArrayWithTypeBySliceString(ctx context.Context, v []string, callback func(interface{}, string)) error { 135 for i := range v { 136 select { 137 case <-ctx.Done(): 138 return nil 139 140 default: 141 callback(v[i], types.String) 142 } 143 } 144 145 return nil 146 } 147 148 func readArrayWithTypeBySliceInterface(ctx context.Context, dataType string, marshal func(interface{}) ([]byte, error), v []interface{}, callback func(interface{}, string)) error { 149 if len(v) == 0 { 150 return nil 151 } 152 153 for i := range v { 154 select { 155 case <-ctx.Done(): 156 return nil 157 158 default: 159 switch v[i].(type) { 160 161 case string: 162 callback((v[i].(string)), types.String) 163 164 case float64: 165 callback(v[i].(float64), types.Number) 166 167 case int: 168 callback(v[i].(int), types.Integer) 169 170 case bool: 171 if v[i].(bool) { 172 callback(true, types.Boolean) 173 } else { 174 callback(false, types.Boolean) 175 } 176 177 case []byte: 178 callback(string(v[i].([]byte)), types.String) 179 180 case []rune: 181 callback(string(v[i].([]rune)), types.String) 182 183 case nil: 184 callback(nil, types.Null) 185 186 default: 187 jBytes, err := marshal(v[i]) 188 if err != nil { 189 return err 190 } 191 callback(jBytes, dataType) 192 } 193 } 194 } 195 196 return nil 197 } 198 199 func readArrayWithTypeByMap[K comparable, V any](ctx context.Context, dataType string, marshal func(interface{}) ([]byte, error), v map[K]V, callback func(interface{}, string)) error { 200 for key, val := range v { 201 select { 202 case <-ctx.Done(): 203 return nil 204 default: 205 m := map[K]any{key: val} 206 b, err := marshal(m) 207 if err != nil { 208 return err 209 } 210 callback(string(b), dataType) 211 } 212 } 213 214 return nil 215 }