-
Notifications
You must be signed in to change notification settings - Fork 0
/
genplusser.go
107 lines (87 loc) · 1.93 KB
/
genplusser.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// +build ignore
package main
// Rationale
// https://stackoverflow.com/questions/34408808/golang-embed-an-interface-with-additional-hidden-methods
// https://github.com/golang/go/issues/18997
import (
"bytes"
"fmt"
"go/format"
"io"
"io/ioutil"
"os"
"text/template"
)
var all = []string{
"http.CloseNotifier",
"http.Flusher",
"http.Hijacker",
"io.ReaderFrom",
"http.Pusher",
}
var tmp = template.Must(template.New("plusser").Parse(`package web
import (
"io"
"net/http"
)
// AUTO GENERATED. DO NOT EDIT
// Usually, implementations of http.ResponseWriter contain extra methods, so we
// auto generate all combinations of those to keep the functionality
{{ range . }}
type plusser{{.Bits}} interface { {{range .Interfaces }}
{{if .Off}}// {{end}}{{.Interface}} {{end}}
}
type responseWriter{{.Bits}} struct {
http.ResponseWriter
plusser{{.Bits}}
}
{{end}}
func newPlusser(wr, pl http.ResponseWriter) http.ResponseWriter {
switch x := pl.(type) { {{range .}}
case plusser{{.Bits}}:
return &responseWriter{{.Bits}}{wr, x} {{end}}
}
return wr
}
`))
type Interfaces struct {
Bit int
Interfaces []Interface
}
func (ifs Interfaces) Bits() string {
return fmt.Sprintf("%0*b", len(all), ifs.Bit)
}
type Interface struct {
Bit int
Interface string
}
func (ifs Interface) Off() bool {
return ifs.Bit == 0
}
func main() {
combo := compileAll(all)
var buf bytes.Buffer
err := tmp.Execute(&buf, combo)
if err != nil {
panic(err)
}
out, err := format.Source(buf.Bytes())
if err != nil {
io.Copy(os.Stdout, &buf)
panic(err)
}
ioutil.WriteFile("plusser.go", out, 0666)
}
func compileAll(ifs []string) []Interfaces {
all := make([]Interfaces, 1<<uint(len(ifs)))
for i := range all {
b := len(all) - i - 1
all[i].Bit = b
all[i].Interfaces = make([]Interface, len(ifs))
for j := range ifs {
all[i].Interfaces[j].Bit = b & (1 << uint(len(ifs)-j-1))
all[i].Interfaces[j].Interface = ifs[j]
}
}
return all
}