github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/mm/spec.go (about) 1 package mm 2 3 import ( 4 "bytes" 5 "fmt" 6 "go/format" 7 "os" 8 "text/template" 9 "unsafe" 10 ) 11 12 type Allocator interface { 13 Alignment() int 14 Alloc(size int) unsafe.Pointer 15 } 16 17 type Reallocator interface { 18 Realloc(p *unsafe.Pointer, size int) bool 19 } 20 21 type Deallocator interface { 22 Dealloc(p unsafe.Pointer) bool 23 } 24 25 type Owner interface { 26 Owns(p unsafe.Pointer) bool 27 } 28 29 type Emptyer interface { 30 Empty() bool 31 } 32 33 type Spec struct { 34 Type string 35 Alignment int 36 Dealloc bool 37 Owns bool 38 Empty bool 39 } 40 41 func SpecFor(v Allocator) *Spec { 42 _, dealloc := v.(Deallocator) 43 _, owns := v.(Owner) 44 _, empty := v.(Emptyer) 45 return &Spec{ 46 Type: fmt.Sprintf("%+T", v), 47 Alignment: v.Alignment(), 48 Dealloc: dealloc, 49 Owns: owns, 50 Empty: empty, 51 } 52 } 53 54 var funcs = template.FuncMap{ 55 "min": func(a, b int) int { 56 if a < b { 57 return a 58 } 59 return b 60 }, 61 "max": func(a, b int) int { 62 if a > b { 63 return a 64 } 65 return b 66 }, 67 } 68 69 type Error struct { 70 Message error 71 Generated []byte 72 } 73 74 func (err *Error) Error() string { 75 if err.Generated == nil { 76 return err.Message.Error() 77 } 78 return fmt.Sprintf("%v\n\n%v", string(err.Generated), err.Message) 79 } 80 81 func Generate(def string, specs map[string]*Spec) ([]byte, error) { 82 t := template.Must(template.New("").Funcs(funcs).Parse(def)) 83 84 var buf bytes.Buffer 85 err := t.Execute(&buf, specs) 86 if err != nil { 87 return nil, &Error{err, nil} 88 } 89 90 data, err := format.Source(buf.Bytes()) 91 if err != nil { 92 os.Stdout.Write(buf.Bytes()) 93 return nil, &Error{err, nil} 94 } 95 96 return data, nil 97 }