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  }