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  }