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  }