github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/docs/apis/lang.ArrayWithTypeTemplate.md (about) 1 # `lang.ArrayWithTypeTemplate()` (template API) 2 3 > Unmarshals a data type into a Go struct and returns the results as an array with data type included 4 5 ## Description 6 7 This is a template API you can use for your custom data types to wrap around an 8 existing Go marshaller and return a Murex array which is consistent with 9 other structures such as nested JSON or YAML documents. 10 11 It should only be called from `ReadArrayWithType()` functions. 12 13 Because `lang.ArrayTemplateWithType()` relies on a marshaller, it means any types that 14 rely on this API are not going to be stream-able. 15 16 17 18 ## Examples 19 20 Example calling `lang.ArrayTemplate()` function: 21 22 ```go 23 package json 24 25 import ( 26 "context" 27 28 "github.com/lmorg/murex/lang" 29 "github.com/lmorg/murex/lang/stdio" 30 "github.com/lmorg/murex/utils/json" 31 ) 32 33 func readArray(ctx context.Context, read stdio.Io, callback func([]byte)) error { 34 // Create a marshaller function to pass to ArrayTemplate 35 marshaller := func(v interface{}) ([]byte, error) { 36 return json.Marshal(v, read.IsTTY()) 37 } 38 39 return lang.ArrayTemplate(ctx, marshaller, json.Unmarshal, read, callback) 40 } 41 ``` 42 43 ## Detail 44 45 ### API Source: 46 47 ```go 48 package lang 49 50 import ( 51 "context" 52 "fmt" 53 54 "github.com/lmorg/murex/lang/stdio" 55 "github.com/lmorg/murex/lang/types" 56 "github.com/lmorg/murex/utils" 57 "github.com/lmorg/murex/utils/consts" 58 ) 59 60 // ArrayWithTypeTemplate is a template function for reading arrays from marshalled data 61 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 { 62 b, err := read.ReadAll() 63 if err != nil { 64 return err 65 } 66 67 if len(utils.CrLfTrim(b)) == 0 { 68 return nil 69 } 70 71 var v interface{} 72 err = unmarshal(b, &v) 73 74 if err != nil { 75 return err 76 } 77 78 switch v := v.(type) { 79 case []interface{}: 80 return readArrayWithTypeBySliceInterface(ctx, dataType, marshal, v, callback) 81 82 case []string: 83 return readArrayWithTypeBySliceString(ctx, v, callback) 84 85 case []float64: 86 return readArrayWithTypeBySliceFloat(ctx, v, callback) 87 88 case []int: 89 return readArrayWithTypeBySliceInt(ctx, v, callback) 90 91 case []bool: 92 return readArrayWithTypeBySliceBool(ctx, v, callback) 93 94 case string: 95 return readArrayWithTypeByString(v, callback) 96 97 case []byte: 98 return readArrayWithTypeByString(string(v), callback) 99 100 case []rune: 101 return readArrayWithTypeByString(string(v), callback) 102 103 case map[string]string: 104 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 105 106 case map[string]interface{}: 107 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 108 109 case map[interface{}]string: 110 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 111 112 case map[interface{}]interface{}: 113 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 114 115 case map[int]string: 116 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 117 118 case map[int]interface{}: 119 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 120 121 case map[float64]string: 122 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 123 124 case map[float64]interface{}: 125 return readArrayWithTypeByMap(ctx, dataType, marshal, v, callback) 126 127 default: 128 return fmt.Errorf("cannot turn %T into an array\n%s", v, consts.IssueTrackerURL) 129 } 130 } 131 132 func readArrayWithTypeByString(v string, callback func(interface{}, string)) error { 133 callback(v, types.String) 134 135 return nil 136 } 137 138 func readArrayWithTypeBySliceInt(ctx context.Context, v []int, callback func(interface{}, string)) error { 139 for i := range v { 140 select { 141 case <-ctx.Done(): 142 return nil 143 144 default: 145 callback(v[i], types.Integer) 146 } 147 } 148 149 return nil 150 } 151 152 func readArrayWithTypeBySliceFloat(ctx context.Context, v []float64, callback func(interface{}, string)) error { 153 for i := range v { 154 select { 155 case <-ctx.Done(): 156 return nil 157 158 default: 159 callback(v[i], types.Number) 160 } 161 } 162 163 return nil 164 } 165 166 func readArrayWithTypeBySliceBool(ctx context.Context, v []bool, callback func(interface{}, string)) error { 167 for i := range v { 168 select { 169 case <-ctx.Done(): 170 return nil 171 172 default: 173 callback(v[i], types.Boolean) 174 175 } 176 } 177 178 return nil 179 } 180 181 func readArrayWithTypeBySliceString(ctx context.Context, v []string, callback func(interface{}, string)) error { 182 for i := range v { 183 select { 184 case <-ctx.Done(): 185 return nil 186 187 default: 188 callback(v[i], types.String) 189 } 190 } 191 192 return nil 193 } 194 195 func readArrayWithTypeBySliceInterface(ctx context.Context, dataType string, marshal func(interface{}) ([]byte, error), v []interface{}, callback func(interface{}, string)) error { 196 if len(v) == 0 { 197 return nil 198 } 199 200 for i := range v { 201 select { 202 case <-ctx.Done(): 203 return nil 204 205 default: 206 switch v[i].(type) { 207 208 case string: 209 callback((v[i].(string)), types.String) 210 211 case float64: 212 callback(v[i].(float64), types.Number) 213 214 case int: 215 callback(v[i].(int), types.Integer) 216 217 case bool: 218 if v[i].(bool) { 219 callback(true, types.Boolean) 220 } else { 221 callback(false, types.Boolean) 222 } 223 224 case []byte: 225 callback(string(v[i].([]byte)), types.String) 226 227 case []rune: 228 callback(string(v[i].([]rune)), types.String) 229 230 case nil: 231 callback(nil, types.Null) 232 233 default: 234 jBytes, err := marshal(v[i]) 235 if err != nil { 236 return err 237 } 238 callback(jBytes, dataType) 239 } 240 } 241 } 242 243 return nil 244 } 245 246 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 { 247 for key, val := range v { 248 select { 249 case <-ctx.Done(): 250 return nil 251 default: 252 m := map[K]any{key: val} 253 b, err := marshal(m) 254 if err != nil { 255 return err 256 } 257 callback(string(b), dataType) 258 } 259 } 260 261 return nil 262 } 263 ``` 264 265 ## Parameters 266 267 1. `func(interface{}) ([]byte, error)`: data type's marshaller 268 2. `func([]byte, interface{}) error`: data type's unmarshaller 269 3. `stdio.Io`: stream to read from (eg STDIN) 270 4. `func(interface{}, string)`: callback function to write each array element, with data type 271 272 ## See Also 273 274 * [apis/`ReadArray()` (type)](../apis/ReadArray.md): 275 Read from a data type one array element at a time 276 * [apis/`ReadArrayWithType()` (type)](../apis/ReadArrayWithType.md): 277 Read from a data type one array element at a time and return the elements contents and data type 278 * [apis/`ReadIndex()` (type)](../apis/ReadIndex.md): 279 Data type handler for the index, `[`, builtin 280 * [apis/`ReadMap()` (type)](../apis/ReadMap.md): 281 Treat data type as a key/value structure and read its contents 282 * [apis/`ReadNotIndex()` (type)](../apis/ReadNotIndex.md): 283 Data type handler for the bang-prefixed index, `: 285 Write a data type, one array element at a time 286 * [apis/`lang.IndexTemplateObject()` (template API)](../apis/lang.IndexTemplateObject.md): 287 Returns element(s) from a data structure 288 * [apis/`lang.IndexTemplateTable()` (template API)](../apis/lang.IndexTemplateTable.md): 289 Returns element(s) from a table 290 291 <hr/> 292 293 This document was generated from [lang/stdio/interface_doc.yaml](https://github.com/lmorg/murex/blob/master/lang/stdio/interface_doc.yaml).