sync from project
This commit is contained in:
@ -11,6 +11,8 @@ import (
|
||||
var (
|
||||
extractors = make(map[reflect.Type]func(*http.Request) (any, error))
|
||||
|
||||
extractorsTakeBody = make(map[reflect.Type]bool)
|
||||
|
||||
extractorsTakesResponseWriter = make(map[reflect.Type]func(http.ResponseWriter, *http.Request) (any, error))
|
||||
)
|
||||
|
||||
@ -18,6 +20,12 @@ type FromRequest interface {
|
||||
FromRequest(*http.Request) error
|
||||
}
|
||||
|
||||
// Marker interface
|
||||
type TakeRequestBody interface {
|
||||
TakeRequestBody()
|
||||
}
|
||||
|
||||
// Marker interface
|
||||
type TakeResponseWriter interface {
|
||||
TakeResponseWriter(http.ResponseWriter)
|
||||
}
|
||||
@ -43,6 +51,42 @@ func RegisterExtractorGeneric[T any](extractor func(*http.Request) (any, error))
|
||||
RegisterExtractor(reflect.TypeOf(pointerToT).Elem(), extractor)
|
||||
}
|
||||
|
||||
func RegisterExtractorThatTakesBody(o any, extractor func(*http.Request) (any, error)) {
|
||||
if t, ok := o.(reflect.Type); ok {
|
||||
slog.With("type", t.String()).Debug("extractor type registered with reflect.Type")
|
||||
extractors[t] = extractor
|
||||
extractorsTakeBody[t] = true
|
||||
} else if v, ok := o.(reflect.Value); ok {
|
||||
slog.With("type", v.Type().String(), "value", v.Interface()).Debug("extractor type registered with reflect.Value")
|
||||
|
||||
extractors[v.Type()] = extractor
|
||||
extractorsTakeBody[v.Type()] = true
|
||||
} else {
|
||||
t := reflect.TypeOf(o)
|
||||
slog.With("type", t.String(), "value", o).Debug("extractor type registered with object")
|
||||
|
||||
extractors[t] = extractor
|
||||
extractorsTakeBody[t] = true
|
||||
}
|
||||
}
|
||||
|
||||
func RegisterExtractorThatTakesBodyGeneric[T any](extractor func(*http.Request) (any, error)) {
|
||||
var pointerToT *T
|
||||
RegisterExtractorThatTakesBody(reflect.TypeOf(pointerToT).Elem(), extractor)
|
||||
}
|
||||
|
||||
func IsTakeBody(t reflect.Type) bool {
|
||||
if isTakeBody := extractorsTakeBody[t]; isTakeBody {
|
||||
return isTakeBody
|
||||
}
|
||||
|
||||
if _, ok := util.Implements[TakeRequestBody](t); ok {
|
||||
return ok
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func RegisterExtractorThatTakesResponseWriter(o any, extractor func(http.ResponseWriter, *http.Request) (any, error)) {
|
||||
if t, ok := o.(reflect.Type); ok {
|
||||
slog.With("type", t.String()).Debug("extractor type registered with reflect.Type")
|
||||
@ -70,62 +114,57 @@ func GetExtractor(t reflect.Type) (func(http.ResponseWriter, *http.Request) (any
|
||||
_, ptrIsTakeResponseWriter := util.Implements[TakeResponseWriter](t.Elem())
|
||||
isTakeResponseWriter = isTakeResponseWriter || ptrIsTakeResponseWriter
|
||||
}
|
||||
if _, ok := util.Implements[FromRequest](t); ok {
|
||||
if t.Kind() == reflect.Pointer {
|
||||
// T.Implement(FromRequest) and T is Pointer
|
||||
// create new actual T and call T.FromRequest on it
|
||||
// if error happens, no error is returned. just return nil
|
||||
return func(w http.ResponseWriter, r *http.Request) (any, error) {
|
||||
// var t T
|
||||
// return t, t.FromRequest(r)
|
||||
z := reflect.New(t.Elem())
|
||||
|
||||
if isTakeResponseWriter {
|
||||
z.MethodByName("TakeResponseWriter").Call([]reflect.Value{reflect.ValueOf(w)})
|
||||
fromRequestType := reflect.TypeOf((*FromRequest)(nil)).Elem()
|
||||
if t.Implements(fromRequestType) {
|
||||
return func(w http.ResponseWriter, r *http.Request) (any, error) {
|
||||
val := reflect.New(t).Elem()
|
||||
if t.Kind() == reflect.Pointer {
|
||||
val = reflect.New(t.Elem())
|
||||
}
|
||||
|
||||
if isTakeResponseWriter {
|
||||
if taker, ok := val.Addr().Interface().(TakeResponseWriter); ok {
|
||||
taker.TakeResponseWriter(w)
|
||||
}
|
||||
}
|
||||
|
||||
results := z.MethodByName("FromRequest").Call([]reflect.Value{reflect.ValueOf(r)})
|
||||
if err, ok := results[0].Interface().(error); ok && err != nil {
|
||||
if errResponse, ok := err.(ErrorResponse); ok {
|
||||
return reflect.Zero(t).Interface(), errResponse
|
||||
if fromR, ok := val.Interface().(FromRequest); ok {
|
||||
if err := fromR.FromRequest(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if val.CanAddr() {
|
||||
if fromR, ok := val.Addr().Interface().(FromRequest); ok {
|
||||
if err := fromR.FromRequest(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reflect.Zero(t).Interface(), nil
|
||||
}
|
||||
return z.Interface(), nil
|
||||
}, isTakeResponseWriter
|
||||
}
|
||||
// T.Implement(FromRequest) and T is not Pointer
|
||||
// create zero T and call T.FromRequest directly on it
|
||||
return func(w http.ResponseWriter, r *http.Request) (any, error) {
|
||||
// var t T
|
||||
// return t, t.FromRequest(r)
|
||||
z := reflect.Zero(t)
|
||||
|
||||
if isTakeResponseWriter {
|
||||
z.MethodByName("TakeResponseWriter").Call([]reflect.Value{reflect.ValueOf(w)})
|
||||
}
|
||||
if t.Kind() == reflect.Pointer {
|
||||
|
||||
results := z.MethodByName("FromRequest").Call([]reflect.Value{reflect.ValueOf(r)})
|
||||
if err, ok := results[0].Interface().(error); ok {
|
||||
return z.Interface(), err
|
||||
return val.Interface(), nil
|
||||
}
|
||||
return z.Interface(), nil
|
||||
return val.Addr().Interface(), nil
|
||||
}, isTakeResponseWriter
|
||||
} else if v, ok := util.PointerImplements[FromRequest](t); ok {
|
||||
}
|
||||
|
||||
if reflect.PointerTo(t).Implements(fromRequestType) {
|
||||
return func(w http.ResponseWriter, r *http.Request) (any, error) {
|
||||
// var t T
|
||||
// return t, t.FromRequest(r)
|
||||
z := reflect.New(v.Type().Elem())
|
||||
val := reflect.New(t)
|
||||
|
||||
if isTakeResponseWriter {
|
||||
z.MethodByName("TakeResponseWriter").Call([]reflect.Value{reflect.ValueOf(w)})
|
||||
if taker, ok := val.Interface().(TakeResponseWriter); ok {
|
||||
taker.TakeResponseWriter(w)
|
||||
}
|
||||
}
|
||||
|
||||
results := z.MethodByName("FromRequest").Call([]reflect.Value{reflect.ValueOf(r)})
|
||||
if err := results[0].Interface(); err == nil {
|
||||
return z.Elem().Interface(), nil
|
||||
if fromR, ok := val.Interface().(FromRequest); ok {
|
||||
if err := fromR.FromRequest(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return z.Elem().Interface(), results[0].Interface().(error)
|
||||
|
||||
return val.Elem().Interface(), nil
|
||||
}, isTakeResponseWriter
|
||||
}
|
||||
|
||||
@ -142,7 +181,10 @@ func GetExtractor(t reflect.Type) (func(http.ResponseWriter, *http.Request) (any
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
// Create a pointer to the value
|
||||
vp := reflect.New(reflect.TypeOf(v))
|
||||
vp.Elem().Set(reflect.ValueOf(v))
|
||||
return vp.Interface(), nil
|
||||
}, false
|
||||
}
|
||||
}
|
||||
@ -160,7 +202,10 @@ func GetExtractor(t reflect.Type) (func(http.ResponseWriter, *http.Request) (any
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
// Create a pointer to the value
|
||||
vp := reflect.New(reflect.TypeOf(v))
|
||||
vp.Elem().Set(reflect.ValueOf(v))
|
||||
return vp.Interface(), nil
|
||||
}, true
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user