1
0
mirror of https://github.com/golang/go synced 2024-11-21 21:54:40 -07:00

net/http/httptrace: compose ClientTrace without reflect

This is to enable use of package httptrace on TinyGo, which does not
have an implementation of reflect.MakeFunc.
This commit is contained in:
Randy Reddig 2024-08-30 09:11:03 -07:00
parent fc9f02c7ae
commit 87c83bf442
No known key found for this signature in database

View File

@ -12,7 +12,6 @@ import (
"internal/nettrace" "internal/nettrace"
"net" "net"
"net/textproto" "net/textproto"
"reflect"
"time" "time"
) )
@ -176,34 +175,86 @@ func (t *ClientTrace) compose(old *ClientTrace) {
if old == nil { if old == nil {
return return
} }
tv := reflect.ValueOf(t).Elem() t.GetConn = compose1to0(t.GetConn, old.GetConn)
ov := reflect.ValueOf(old).Elem() t.GotConn = compose1to0(t.GotConn, old.GotConn)
structType := tv.Type() t.PutIdleConn = compose1to0(t.PutIdleConn, old.PutIdleConn)
for i := 0; i < structType.NumField(); i++ { t.GotFirstResponseByte = compose0to0(t.GotFirstResponseByte, old.GotFirstResponseByte)
tf := tv.Field(i) t.Got100Continue = compose0to0(t.Got100Continue, old.Got100Continue)
hookType := tf.Type() t.Got1xxResponse = compose2to1(t.Got1xxResponse, old.Got1xxResponse)
if hookType.Kind() != reflect.Func { t.DNSStart = compose1to0(t.DNSStart, old.DNSStart)
continue t.DNSDone = compose1to0(t.DNSDone, old.DNSDone)
} t.ConnectStart = compose2to0(t.ConnectStart, old.ConnectStart)
of := ov.Field(i) t.ConnectDone = compose3to0(t.ConnectDone, old.ConnectDone)
if of.IsNil() { t.TLSHandshakeStart = compose0to0(t.TLSHandshakeStart, old.TLSHandshakeStart)
continue t.TLSHandshakeDone = compose2to0(t.TLSHandshakeDone, old.TLSHandshakeDone)
} t.WroteHeaderField = compose2to0(t.WroteHeaderField, old.WroteHeaderField)
if tf.IsNil() { t.WroteHeaders = compose0to0(t.WroteHeaders, old.WroteHeaders)
tf.Set(of) t.Wait100Continue = compose0to0(t.Wait100Continue, old.Wait100Continue)
continue t.WroteRequest = compose1to0(t.WroteRequest, old.WroteRequest)
} }
// Make a copy of tf for tf to call. (Otherwise it func compose0to0[F func()](f1, f2 F) F {
// creates a recursive call cycle and stack overflows) if f1 == nil {
tfCopy := reflect.ValueOf(tf.Interface()) return f2
}
if f2 == nil {
return f1
}
return func() {
f1()
f2()
}
}
// We need to call both tf and of in some order. func compose1to0[F func(A), A any](f1, f2 F) F {
newFunc := reflect.MakeFunc(hookType, func(args []reflect.Value) []reflect.Value { if f1 == nil {
tfCopy.Call(args) return f2
return of.Call(args) }
}) if f2 == nil {
tv.Field(i).Set(newFunc) return f1
}
return func(a A) {
f1(a)
f2(a)
}
}
func compose2to0[F func(A, B), A, B any](f1, f2 F) F {
if f1 == nil {
return f2
}
if f2 == nil {
return f1
}
return func(a A, b B) {
f1(a, b)
f2(a, b)
}
}
func compose2to1[F func(A, B) R, A, B, R any](f1, f2 F) F {
if f1 == nil {
return f2
}
if f2 == nil {
return f1
}
return func(a A, b B) R {
f1(a, b)
return f2(a, b)
}
}
func compose3to0[F func(A, B, C), A, B, C any](f1, f2 F) F {
if f1 == nil {
return f2
}
if f2 == nil {
return f1
}
return func(a A, b B, c C) {
f1(a, b, c)
f2(a, b, c)
} }
} }