1
0
mirror of https://github.com/ggicci/httpin.git synced 2025-11-06 08:59:26 +02:00
Files
httpin/core/directiveruntime.go

96 lines
2.8 KiB
Go

package core
import (
"context"
"fmt"
"net/http"
"reflect"
"github.com/ggicci/owl"
)
type contextKey int
const (
// CtxRequest is the key to get the HTTP request value (of *http.Request)
// from DirectiveRuntime.Context. The HTTP request value is injected by
// httpin to the context of DirectiveRuntime before executing the directive.
// See Core.Decode() for more details.
CtxRequest contextKey = iota
CtxRequestBuilder
// CtxCustomCoder is the key to get the custom decoder for a field from
// Resolver.Context. Which is specified by the "decoder" directive.
// During resolver building phase, the "decoder" directive will be removed
// from the resolver, and the targeted decoder by name will be put into
// Resolver.Context with this key. e.g.
//
// type GreetInput struct {
// Message string `httpin:"decoder=custom"`
// }
// For the above example, the decoder named "custom" will be put into the
// resolver of Message field with this key.
CtxCustomCoder
// CtxFieldSet is used by executors to tell whether a field has been set. When
// multiple executors were applied to a field, if the field value were set
// by a former executor, the latter executors MAY skip running by consulting
// this context value.
CtxFieldSet
)
// DirectiveRuntime is the runtime of a directive execution. It wraps owl.DirectiveRuntime,
// providing some additional helper methods particular to httpin.
//
// See owl.DirectiveRuntime for more details.
type DirectiveRuntime owl.DirectiveRuntime
func (rtm *DirectiveRuntime) GetRequest() *http.Request {
if req := rtm.Context.Value(CtxRequest); req != nil {
return req.(*http.Request)
}
return nil
}
func (rtm *DirectiveRuntime) GetRequestBuilder() *RequestBuilder {
if rb := rtm.Context.Value(CtxRequestBuilder); rb != nil {
return rb.(*RequestBuilder)
}
return nil
}
func (rtm *DirectiveRuntime) GetCustomCoder() *NamedAnyStringableAdaptor {
if info := rtm.Resolver.Context.Value(CtxCustomCoder); info != nil {
return info.(*NamedAnyStringableAdaptor)
} else {
return nil
}
}
func (rtm *DirectiveRuntime) IsFieldSet() bool {
return rtm.Context.Value(CtxFieldSet) == true
}
func (rtm *DirectiveRuntime) MarkFieldSet(value bool) {
rtm.Context = context.WithValue(rtm.Context, CtxFieldSet, value)
}
func (rtm *DirectiveRuntime) SetValue(value any) error {
if value == nil {
// NOTE: should we wipe the value here? i.e. set the value to nil if necessary.
// No case found yet, at least for now.
return nil
}
newValue := reflect.ValueOf(value)
targetType := rtm.Value.Type().Elem()
if !newValue.Type().AssignableTo(targetType) {
return fmt.Errorf("%w: value of type %q is not assignable to type %q",
ErrTypeMismatch, reflect.TypeOf(value), targetType)
}
rtm.Value.Elem().Set(newValue)
return nil
}