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 }