github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/builtins/types/generic/marshal.go (about)

     1  package generic
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"strings"
     8  	"text/tabwriter"
     9  
    10  	"github.com/lmorg/murex/lang"
    11  	"github.com/lmorg/murex/lang/types"
    12  	"github.com/lmorg/murex/utils"
    13  )
    14  
    15  func marshal(_ *lang.Process, iface interface{}) (b []byte, err error) {
    16  	switch v := iface.(type) {
    17  	case string:
    18  		b = []byte(v)
    19  		return
    20  
    21  	case []string:
    22  		for i := range v {
    23  			b = append(b, []byte(v[i]+utils.NewLineString)...)
    24  		}
    25  		return
    26  
    27  	case [][]string:
    28  		return tabWriter(iface.([][]string))
    29  		/*for i := range v {
    30  			b = append(b, []byte(strings.Join(v[i], "\t")+utils.NewLineString)...)
    31  		}
    32  		return*/
    33  
    34  	case []interface{}:
    35  		for i := range v {
    36  			b = append(b, iface2str(&v[i])...)
    37  		}
    38  		return
    39  
    40  	case map[string]string:
    41  		return mapToArray(v)
    42  	case map[string]float64:
    43  		return mapToArray(v)
    44  	case map[string]int:
    45  		return mapToArray(v)
    46  	case map[string]bool:
    47  		return mapToArray(v)
    48  	case map[string]interface{}:
    49  		return mapToArray(v)
    50  
    51  	case map[interface{}]interface{}:
    52  		for s := range v {
    53  			b = append(b, []byte(fmt.Sprintf("%s\t%s%s", fmt.Sprint(s), fmt.Sprint(v[s]), utils.NewLineString))...)
    54  		}
    55  		return
    56  
    57  	case map[interface{}]string:
    58  		for s := range v {
    59  			b = append(b, []byte(fmt.Sprintf("%s\t%s%s", fmt.Sprint(s), v[s], utils.NewLineString))...)
    60  		}
    61  		return
    62  
    63  	/*case interface{}:
    64  	return []byte(fmt.Sprintln(iface)), nil*/
    65  
    66  	default:
    67  		err = fmt.Errorf("I don't know how to marshal %T into a `%s`. Data possibly too complex?", v, types.Generic)
    68  		return
    69  	}
    70  }
    71  
    72  func iface2str(iface *interface{}) (b []byte) {
    73  	switch v := (*iface).(type) {
    74  	case []interface{}:
    75  		if len(v) == 0 {
    76  			return
    77  		}
    78  
    79  		for i := 0; i < len(v)-2; i++ {
    80  			b = append(b, []byte(fmt.Sprintf("%v\t", v[i]))...)
    81  		}
    82  		return append(b, []byte(fmt.Sprintf("%v%s", v[len(v)-1], utils.NewLineString))...)
    83  
    84  	case string:
    85  		return []byte(v + utils.NewLineString)
    86  
    87  	case interface{}:
    88  		return []byte(fmt.Sprintf("%v%s", v, utils.NewLineString))
    89  
    90  		//default:
    91  		//	return []byte(fmt.Sprintf("%v%s", v, utils.NewLineString))
    92  	default:
    93  		panic(fmt.Sprintf("cannot marshal %T", v))
    94  	}
    95  }
    96  
    97  func mapToArray[K comparable, V string | float64 | int | bool | any](m map[K]V) ([]byte, error) {
    98  	var a [][]string
    99  	for k, v := range m {
   100  		a = append(a, []string{fmt.Sprint(k), fmt.Sprint(v)})
   101  	}
   102  	return tabWriter(a)
   103  }
   104  
   105  func tabWriter(v [][]string) ([]byte, error) {
   106  	var (
   107  		b   []byte
   108  		err error
   109  	)
   110  
   111  	buf := bytes.NewBuffer(b)
   112  	w := tabwriter.NewWriter(buf, twMinWidth, twTabWidth, twPadding, twPadChar, twFlags)
   113  
   114  	for i := range v {
   115  		_, err = fmt.Fprintln(w, strings.Join(v[i], "\t"))
   116  		if err != nil {
   117  			return nil, err
   118  		}
   119  	}
   120  
   121  	err = w.Flush()
   122  	return buf.Bytes(), err
   123  }
   124  
   125  func unmarshal(p *lang.Process) (interface{}, error) {
   126  	table := make([][]string, 1)
   127  
   128  	scanner := bufio.NewScanner(p.Stdin)
   129  	for scanner.Scan() {
   130  		table = append(table, rxWhitespace.Split(scanner.Text(), -1))
   131  	}
   132  
   133  	if len(table) > 1 {
   134  		table = table[1:]
   135  	}
   136  
   137  	err := scanner.Err()
   138  	if err != nil {
   139  		return table, fmt.Errorf("error while unmarshalling a %s array: %s", types.Generic, err.Error())
   140  	}
   141  	return table, err
   142  }