github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/fields/.gistsnip (about) 1 { 2 "Description": "", 3 "Snippets": { 4 "00_typeswitch/field#interface.go": { 5 "GistID": "55ca3e70d6d4b5ca78a7dc76a16bce14", 6 "GistURL": "https://gist.github.com/55ca3e70d6d4b5ca78a7dc76a16bce14", 7 "Line": 3, 8 "File": "00_typeswitch/field.go", 9 "Path": "00_typeswitch/field#interface.go", 10 "Name": "interface", 11 "Content": "type Field interface {\n\tName() string\n}\n\ntype Uint struct {\n\tID string\n\tValue uint64\n}\n\nfunc (a *Uint) Name() string { return a.ID }\nfunc (a *Uint) Add(b *Uint) *Uint { return \u0026Uint{Value: a.Value + b.Value} }\nfunc (a *Uint) Sub(b *Uint) *Uint { return \u0026Uint{Value: a.Value - b.Value} }\n\ntype Float struct {\n\tID string\n\tValue float64\n}\n\nfunc (a *Float) Name() string { return a.ID }\nfunc (a *Float) Add(b *Float) *Float { return \u0026Float{Value: a.Value + b.Value} }\nfunc (a *Float) Sub(b *Float) *Float { return \u0026Float{Value: a.Value - b.Value} }" 12 }, 13 "00_typeswitch/main#main.go": { 14 "GistID": "5cff51a1b5f2d50966876129554897a2", 15 "GistURL": "https://gist.github.com/5cff51a1b5f2d50966876129554897a2", 16 "Line": 12, 17 "File": "00_typeswitch/main.go", 18 "Path": "00_typeswitch/main#main.go", 19 "Name": "main", 20 "Content": "fields, err := ParseFields(strings.NewReader(testdata.Basic))\nif err != nil {\n\tlog.Fatal(err)\n}\n\nfmt.Printf(\"%#+v\\n\", Add(fields[\"Alpha\"], fields[\"Beta\"]))\nfmt.Printf(\"%#+v\\n\", Add(fields[\"Alpha\"], fields[\"Gamma\"]))" 21 }, 22 "00_typeswitch/ops#ops.go": { 23 "GistID": "cb203f996d6c50487c632e30b5d649d6", 24 "GistURL": "https://gist.github.com/cb203f996d6c50487c632e30b5d649d6", 25 "Line": 3, 26 "File": "00_typeswitch/ops.go", 27 "Path": "00_typeswitch/ops#ops.go", 28 "Name": "ops", 29 "Content": "func Add(a, b Field) Field {\n\tif aerr, ok := a.(*Error); ok {\n\t\treturn aerr\n\t}\n\tif berr, ok := b.(*Error); ok {\n\t\treturn berr\n\t}\n\n\tswitch x := a.(type) {\n\tcase *Float:\n\t\tif y, ok := b.(*Float); ok {\n\t\t\treturn x.Add(y)\n\t\t} else {\n\t\t\treturn \u0026Error{\"add type-mismatch\"}\n\t\t}\n\tcase *Uint:\n\t\tif y, ok := b.(*Uint); ok {\n\t\t\treturn x.Add(y)\n\t\t} else {\n\t\t\treturn \u0026Error{\"add type-mismatch\"}\n\t\t}\n\tdefault:\n\t\treturn \u0026Error{\"unhandled types\"}\n\t}\n}" 30 }, 31 "00_typeswitch/parse#parse.go": { 32 "GistID": "cf3f718ea7e1a9a6ad18ab80aa1d9b07", 33 "GistURL": "https://gist.github.com/cf3f718ea7e1a9a6ad18ab80aa1d9b07", 34 "Line": 9, 35 "File": "00_typeswitch/parse.go", 36 "Path": "00_typeswitch/parse#parse.go", 37 "Name": "parse", 38 "Content": "func ParseFields(r io.Reader) (map[string]Field, error) {\n\tvar config struct {\n\t\tFields []struct {\n\t\t\tName string\n\t\t\tType string\n\t\t\tVal interface{}\n\t\t\tMultiplier interface{}\n\t\t}\n\t}\n\n\terr := json.NewDecoder(r).Decode(\u0026config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfields := map[string]Field{}\n\n\tfor _, jsonField := range config.Fields {\n\t\tval, valok := jsonField.Val.(float64)\n\t\tif !valok {\n\t\t\treturn nil, errors.New(\"unsupported type \" + jsonField.Type)\n\t\t}\n\n\t\tvar field Field\n\t\tswitch jsonField.Type {\n\t\tcase \"uint\":\n\t\t\tfield = \u0026Uint{\n\t\t\t\tID: jsonField.Name,\n\t\t\t\tValue: uint64(val),\n\t\t\t}\n\t\tcase \"float\":\n\t\t\tfield = \u0026Float{\n\t\t\t\tID: jsonField.Name,\n\t\t\t\tValue: float64(val),\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, errors.New(\"unsupported type \" + jsonField.Type)\n\t\t}\n\n\t\tfields[field.Name()] = field\n\t}\n\n\treturn fields, nil\n}" 39 }, 40 "01_typemap/main#main.go": { 41 "GistID": "b2c0efddfdc7269a3349e044a0788edc", 42 "GistURL": "https://gist.github.com/b2c0efddfdc7269a3349e044a0788edc", 43 "Line": 12, 44 "File": "01_typemap/main.go", 45 "Path": "01_typemap/main#main.go", 46 "Name": "main", 47 "Content": "fields, err := ParseFields(strings.NewReader(testdata.Basic))\nif err != nil {\n\tlog.Fatal(err)\n}\n\nfmt.Printf(\"%#+v\\n\", Add(fields[\"Alpha\"], fields[\"Beta\"]))\nfmt.Printf(\"%#+v\\n\", Add(fields[\"Alpha\"], fields[\"Gamma\"]))" 48 }, 49 "01_typemap/ops#ops.go": { 50 "GistID": "f768c7099d81db7202aa783e5b858554", 51 "GistURL": "https://gist.github.com/f768c7099d81db7202aa783e5b858554", 52 "Line": 5, 53 "File": "01_typemap/ops.go", 54 "Path": "01_typemap/ops#ops.go", 55 "Name": "ops", 56 "Content": "type Op struct {\n\tName string\n\tLeft reflect.Type\n\tRight reflect.Type\n}\n\nvar Ops = map[Op]func(a, b Field) Field{}\n\nfunc init() {\n\ttUint := reflect.TypeOf(\u0026Uint{})\n\ttFloat := reflect.TypeOf(\u0026Float{})\n\n\tOps[Op{\"Add\", tUint, tUint}] = func(a, b Field) Field { return a.(*Uint).Add(b.(*Uint)) }\n\tOps[Op{\"Sub\", tUint, tUint}] = func(a, b Field) Field { return a.(*Uint).Sub(b.(*Uint)) }\n\n\tOps[Op{\"Add\", tFloat, tFloat}] = func(a, b Field) Field { return a.(*Float).Add(b.(*Float)) }\n\tOps[Op{\"Sub\", tFloat, tFloat}] = func(a, b Field) Field { return a.(*Float).Sub(b.(*Float)) }\n}\n\nfunc Call(name string, a, b Field) Field {\n\tif aerr, ok := a.(*Error); ok {\n\t\treturn aerr\n\t}\n\tif berr, ok := b.(*Error); ok {\n\t\treturn berr\n\t}\n\n\tta, tb := reflect.TypeOf(a), reflect.TypeOf(b)\n\tcall, found := Ops[Op{\"Add\", ta, tb}]\n\tif !found {\n\t\treturn \u0026Error{\"unhandled op\"}\n\t}\n\treturn call(a, b)\n}\n\nfunc Add(a, b Field) Field { return Call(\"Add\", a, b) }\nfunc Sub(a, b Field) Field { return Call(\"Sub\", a, b) }" 57 }, 58 "02_reflect/main#main.go": { 59 "GistID": "ad6d16f06731554fb74c056338780c4a", 60 "GistURL": "https://gist.github.com/ad6d16f06731554fb74c056338780c4a", 61 "Line": 12, 62 "File": "02_reflect/main.go", 63 "Path": "02_reflect/main#main.go", 64 "Name": "main", 65 "Content": "var example struct {\n\tAlpha float64\n\tGamma float64\n\tBeta uint\n}\nerr := Unmarshal(strings.NewReader(testdata.Basic), \u0026example)\nif err != nil {\n\tlog.Fatal(err)\n}\n\nfmt.Println(example.Alpha + example.Gamma)" 66 }, 67 "02_reflect/scan#assignfield.go": { 68 "GistID": "da954a2e761d8eb0a65e1bece1efd03f", 69 "GistURL": "https://gist.github.com/da954a2e761d8eb0a65e1bece1efd03f", 70 "Line": 78, 71 "File": "02_reflect/scan.go", 72 "Path": "02_reflect/scan#assignfield.go", 73 "Name": "assignfield", 74 "Content": "func (config *jsonConfig) assignField(field *jsonField, p interface{}) error {\n\t// p is a pointer to struct field\n\tswitch p := p.(type) {\n\tcase *uint:\n\t\tuv, ok := field.Val.(float64)\n\t\tif !ok || field.Type != \"uint\" {\n\t\t\treturn fmt.Errorf(\"expected uint, got %T and %v\", field.Val, field.Type)\n\t\t}\n\t\t*p = uint(uv)\n\tcase *float64:\n\t\tuv, ok := field.Val.(float64)\n\t\tif !ok || field.Type != \"float\" {\n\t\t\treturn fmt.Errorf(\"expected float, got %T and %v\", field.Val, field.Type)\n\t\t}\n\t\t*p = uv\n\tdefault:\n\t\treturn fmt.Errorf(\"unhandled field type %T\", p)\n\t}\n\treturn nil\n}" 75 }, 76 "02_reflect/scan#scan.go": { 77 "GistID": "160e39000c0518d6df7c4c27ccfbc86f", 78 "GistURL": "https://gist.github.com/160e39000c0518d6df7c4c27ccfbc86f", 79 "Line": 35, 80 "File": "02_reflect/scan.go", 81 "Path": "02_reflect/scan#scan.go", 82 "Name": "scan", 83 "Content": "func (config *jsonConfig) Scan(r interface{}) error {\n\t// check that r is a pointer to some struct\n\trv := reflect.ValueOf(r)\n\tif rv.Kind() != reflect.Ptr || rv.Elem().Kind() != reflect.Struct {\n\t\treturn fmt.Errorf(\"expected pointer to a struct, got %T\", r)\n\t}\n\n\ts := rv.Elem()\n\tt := s.Type()\n\n\t// iterate over all struct fields\n\tfor i, n := 0, s.NumField(); i \u003c n; i++ {\n\t\tresultField := s.Field(i)\n\n\t\t// find the corresponding field from config\n\t\tfield, err := config.findField(t.Field(i).Name)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// assign field value to the struct field\n\t\terr = config.assignField(field, resultField.Addr().Interface())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}" 84 }, 85 "02_reflect/scan#unmarshal.go": { 86 "GistID": "55a2bf2da8961f29ab9a22c5a4a775dc", 87 "GistURL": "https://gist.github.com/55a2bf2da8961f29ab9a22c5a4a775dc", 88 "Line": 11, 89 "File": "02_reflect/scan.go", 90 "Path": "02_reflect/scan#unmarshal.go", 91 "Name": "unmarshal", 92 "Content": "func Unmarshal(rd io.Reader, data interface{}) error {\n\tvar config jsonConfig\n\terr := json.NewDecoder(rd).Decode(\u0026config)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn config.Scan(data)\n}\n\ntype jsonConfig struct {\n\tFields []jsonField\n}\n\ntype jsonField struct {\n\tName string\n\tType string\n\tVal interface{}\n\tMultiplier interface{}\n}" 93 }, 94 "03_compose/fields#field.go": { 95 "GistID": "8e16073941df6a9514d62f779fa5e017", 96 "GistURL": "https://gist.github.com/8e16073941df6a9514d62f779fa5e017", 97 "Line": 6, 98 "File": "03_compose/fields.go", 99 "Path": "03_compose/fields#field.go", 100 "Name": "field", 101 "Content": "type Field interface {\n\tName() string\n\tAssign(typ string, value interface{}) error\n}\n\ntype Float struct {\n\tFieldName string\n\tValue *float64\n}\n\nfunc (s Float) Name() string { return s.FieldName }\nfunc (s Float) Assign(typ string, val interface{}) error {\n\tuv, ok := val.(float64)\n\tif !ok || typ != \"float\" {\n\t\treturn fmt.Errorf(\"expected float, got %T and %v\", val, typ)\n\t}\n\t*s.Value = uv\n\treturn nil\n}" 102 }, 103 "03_compose/main#main.go": { 104 "GistID": "2da839012c19ece1af8e9ae9038cfad7", 105 "GistURL": "https://gist.github.com/2da839012c19ece1af8e9ae9038cfad7", 106 "Line": 15, 107 "File": "03_compose/main.go", 108 "Path": "03_compose/main#main.go", 109 "Name": "main", 110 "Content": "config := \u0026jsonConfig{}\nerr = json.NewDecoder(strings.NewReader(testdata.Basic)).Decode(config)\nif err != nil {\n\tlog.Fatal(err)\n}\n\nvar (\n\talpha float64\n\tgamma float64\n\tbeta uint\n)\n\nerr = config.Scan(\n\tFloat{\"Alpha\", \u0026alpha},\n\tFloat{\"Gamma\", \u0026gamma},\n\tUint{\"Beta\", \u0026beta},\n)\nif err != nil {\n\tlog.Fatal(err)\n}\n\nfmt.Println(alpha + gamma)" 111 }, 112 "03_compose/scan#scan.go": { 113 "GistID": "7c67a02167834e7ef19b325e3609b46c", 114 "GistURL": "https://gist.github.com/7c67a02167834e7ef19b325e3609b46c", 115 "Line": 19, 116 "File": "03_compose/scan.go", 117 "Path": "03_compose/scan#scan.go", 118 "Name": "scan", 119 "Content": "func (config *jsonConfig) Scan(fields ...Field) error {\n\tfor _, dst := range fields {\n\t\tname := dst.Name()\n\t\tsrc, err := config.findField(name)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\terr = dst.Assign(src.Type, src.Val)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}" 120 }, 121 "testdata/basic#data.go": { 122 "GistID": "9bb4702ad4cff0def933916cfdb00c20", 123 "GistURL": "https://gist.github.com/9bb4702ad4cff0def933916cfdb00c20", 124 "Line": 3, 125 "File": "testdata/basic.go", 126 "Path": "testdata/basic#data.go", 127 "Name": "data", 128 "Content": "const Basic = `{\n\t\"Fields\": [\n\t\t{ \"Name\": \"Alpha\", \"Type\": \"float\", \"Val\": 15, \"Multiplier\": 0.5 },\n\t\t{ \"Name\": \"Beta\", \"Type\": \"uint\", \"Val\": 10, \"Multiplier\": 10 },\n\t\t{ \"Name\": \"Gamma\", \"Type\": \"float\", \"Val\": 10, \"Multiplier\": 0.5 }\n\t]\n}`" 129 } 130 } 131 }