github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/builtins/types/querystring/marshal.go (about) 1 package string 2 3 import ( 4 "errors" 5 "fmt" 6 "net/url" 7 "strconv" 8 9 "github.com/lmorg/murex/lang" 10 "github.com/lmorg/murex/lang/types" 11 ) 12 13 func marshal(_ *lang.Process, iface interface{}) (b []byte, err error) { 14 qs := make(url.Values) 15 16 switch v := iface.(type) { 17 case []string: 18 for i := range v { 19 qs.Add(strconv.Itoa(i), v[i]) 20 } 21 b = []byte(qs.Encode()) 22 23 case []interface{}: 24 for i := range v { 25 t, err := types.ConvertGoType(v[i], types.String) 26 if err != nil { 27 t = fmt.Sprint(v[i]) 28 } 29 qs.Add(strconv.Itoa(i), t.(string)) 30 } 31 b = []byte(qs.Encode()) 32 33 case map[string]string: 34 for s := range v { 35 qs.Add(s, v[s]) 36 } 37 b = []byte(qs.Encode()) 38 39 case map[string]interface{}: 40 for s := range v { 41 t, err := types.ConvertGoType(v[s], types.String) 42 if err != nil { 43 t = fmt.Sprint(v[s]) 44 } 45 qs.Add(s, t.(string)) 46 } 47 b = []byte(qs.Encode()) 48 49 case map[interface{}]interface{}: 50 for s := range v { 51 t1, err := types.ConvertGoType(s, types.String) 52 if err != nil { 53 t1 = fmt.Sprint(s) 54 } 55 t2, err := types.ConvertGoType(v[s], types.String) 56 if err != nil { 57 t1 = fmt.Sprint(v[s]) 58 } 59 qs.Add(t1.(string), t2.(string)) 60 } 61 b = []byte(qs.Encode()) 62 63 case map[interface{}]string: 64 for s := range v { 65 t, err := types.ConvertGoType(s, types.String) 66 if err != nil { 67 t = fmt.Sprint(s) 68 } 69 qs.Add(t.(string), v[s]) 70 } 71 b = []byte(qs.Encode()) 72 73 case interface{}: 74 qs.Add(fmt.Sprint(v), "") 75 76 default: 77 err = errors.New("I don't know how to marshal that data into a `" + dataType + "`. Data possibly too complex?") 78 } 79 80 return 81 } 82 83 func unmarshal(p *lang.Process) (interface{}, error) { 84 b, err := p.Stdin.ReadAll() 85 if err != nil { 86 return nil, err 87 } 88 89 if len(b) == 0 { 90 return nil, nil 91 } 92 93 if b[0] == '?' { 94 if len(b) == 1 { 95 return nil, nil 96 } 97 b = b[1:] 98 } 99 100 values, err := url.ParseQuery(string(b)) 101 if err != nil { 102 return nil, err 103 } 104 105 qs := make(map[string]interface{}) 106 for s := range values { 107 if len(values[s]) == 1 { 108 float, tnErr := toNumber(values[s][0]) 109 if tnErr != nil { 110 qs[s] = values[s][0] 111 continue 112 } 113 qs[s] = float 114 115 } else { 116 qs[s] = values[s] 117 } 118 } 119 120 return qs, nil 121 } 122 123 func toNumber(s string) (f float64, err error) { 124 f, err = strconv.ParseFloat(s, 64) 125 if err != nil { 126 return 127 } 128 129 if s != strconv.FormatFloat(f, 'f', -1, 64) { 130 err = errors.New("Input doesn't match converted output. Possibly due to padding?") 131 } 132 133 return 134 }