diff --git a/middleware/generate.go b/middleware/generate.go new file mode 100644 index 00000000..74e2d5eb --- /dev/null +++ b/middleware/generate.go @@ -0,0 +1,530 @@ +//go:build ignore +// +build ignore + +/* +Usage: execute from repository root: +$ go run middleware/generate.go && gofmt -w -s middleware/step_*.go +*/ + +/* +This file produces the discrete middleware steps used by generated Smithy +clients. Extreme care should be taken when editing the generation template. + +We are electing to generate these steps for performance reasons. A previous +implementation of each step delegated to an underlying pair of list/mapping of +IDs to middlewares. This enabled code reuse but was expensive at runtime, +accounting for roughly 10% of the overall allocations in an operation. + +The generated step here instead operates by directly decorating the phase +function in-place, which entirely removes that overhead and conveys a slight +runtime performance boost. + +Hand-writing the decorator code in terms of generics is not feasible due to the +excessive amount of adapter structures that need to be used. +*/ + +package main + +import ( + "fmt" + "os" + "strings" + "text/template" +) + +const stepTemplate = `// Code generated by smithy-go/middleware/generate.go DO NOT EDIT. +package middleware + +import ( + "context" + "fmt" +) + +{{ .InputDoc }} +type {{.Phase}}Input struct { +{{- range .Inputs }} + {{ .Name }} {{ .Type }} +{{- end }} +} + +// {{.Phase}}Output provides the result returned by the next {{.Phase}}Handler. +type {{.Phase}}Output struct { +{{- range .Outputs }} + {{ .Name }} {{ .Type }} +{{- end }} +} + +// {{.Phase}}Handler provides the interface for the next handler the +// {{.Phase}}Middleware will call in the middleware chain. +type {{.Phase}}Handler interface { + Handle{{.Phase}}(ctx context.Context, in {{.Phase}}Input) ( + out {{.Phase}}Output, metadata Metadata, err error, + ) +} + +// {{.Phase}}Middleware provides the interface for middleware specific to the +// {{.PhaseLowercase}} step. Delegates to the next {{.Phase}}Handler for further +// processing. +type {{.Phase}}Middleware interface { + // ID returns a unique ID for the middleware in the {{.Phase}}Step. The step does not + // allow duplicate IDs. + ID() string + + // Handle{{.Phase}} invokes the middleware behavior which must delegate to the next handler + // for the middleware chain to continue. The method must return a result or + // error to its caller. + Handle{{.Phase}}(ctx context.Context, in {{.Phase}}Input, next {{.Phase}}Handler) ( + out {{.Phase}}Output, metadata Metadata, err error, + ) +} + +// {{.Phase}}MiddlewareFunc returns a {{.Phase}}Middleware with the unique ID provided, +// and the func to be invoked. +func {{.Phase}}MiddlewareFunc(id string, fn func(context.Context, {{.Phase}}Input, {{.Phase}}Handler) ({{.Phase}}Output, Metadata, error)) {{.Phase}}Middleware { + return {{.PhaseLowercase}}MiddlewareFunc{ + id: id, + fn: fn, + } +} + +type {{.PhaseLowercase}}MiddlewareFunc struct { + // Unique ID for the middleware. + id string + + // Middleware function to be called. + fn func(context.Context, {{.Phase}}Input, {{.Phase}}Handler) ( + {{.Phase}}Output, Metadata, error, + ) +} + +// ID returns the unique ID for the middleware. +func (s {{.PhaseLowercase}}MiddlewareFunc) ID() string { return s.id } + +// Handle{{.Phase}} invokes the middleware Fn. +func (s {{.PhaseLowercase}}MiddlewareFunc) Handle{{.Phase}}(ctx context.Context, in {{.Phase}}Input, next {{.Phase}}Handler) ( + out {{.Phase}}Output, metadata Metadata, err error, +) { + return s.fn(ctx, in, next) +} + +var _ {{.Phase}}Middleware = ({{.PhaseLowercase}}MiddlewareFunc{}) + +// {{.Phase}}Step provides the ordered grouping of {{.Phase}}Middleware to be +// invoked on a handler. +type {{.Phase}}Step struct { + head *decorated{{.Phase}}Handler + tail *decorated{{.Phase}}Handler +{{- range .StepFields }} + {{ .Name }} {{ .Type }} +{{- end }} +} + +// New{{.Phase}}Step returns an {{.Phase}}Step ready to have middleware for +// {{.PhaseLowercase}} added to it. +func New{{.Phase}}Step({{ range .StepFields }} {{ .Name }} {{ .Type }}, {{ end }}) *{{.Phase}}Step { + return &{{.Phase}}Step{ +{{- range .StepFields }} + {{ .Name }}: {{ .Name }}, +{{- end }} + } +} + +var _ Middleware = (*{{.Phase}}Step)(nil) + +// ID returns the unique ID of the step as a middleware. +func (s *{{.Phase}}Step) ID() string { + return "{{.Phase}} stack step" +} + +// HandleMiddleware invokes the middleware by decorating the next handler +// provided. Returns the result of the middleware and handler being invoked. +// +// Implements Middleware interface. +func (s *{{.Phase}}Step) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( + out interface{}, metadata Metadata, err error, +) { + sIn := {{.Phase}}Input{ +{{- range .Inputs }} + {{ .Name }}: {{ .Binding }}, +{{- end }} + } + + wh := &{{.PhaseLowercase}}WrapHandler{next} + if s.head == nil { + res, metadata, err := wh.Handle{{.Phase}}(ctx, sIn) + return res.Result, metadata, err + } + + s.tail.Next = wh + res, metadata, err := s.head.Handle{{.Phase}}(ctx, sIn) + return res.Result, metadata, err +} + +// Get retrieves the middleware identified by id. If the middleware is not present, returns false. +func (s *{{.Phase}}Step) Get(id string) ({{.Phase}}Middleware, bool) { + for h := s.head; h != nil; { + if h.With.ID() == id { + return h.With, true + } + if h.Next == nil { + break + } + h = h.Next.(*decorated{{.Phase}}Handler) + } + return nil, false +} + +// Add injects the middleware to the relative position of the middleware group. +// +// Add never returns an error. It used to for duplicate phases but this +// behavior has since been removed as part of a performance optimization. The +// return value from Add can be ignored. +func (s *{{.Phase}}Step) Add(m {{.Phase}}Middleware, pos RelativePosition) error { + if s.head == nil { + s.head = &decorated{{.Phase}}Handler{nil, m} + s.tail = s.head + return nil + } + + if pos == Before { + s.head = &decorated{{.Phase}}Handler{s.head, m} + } else { + tail := &decorated{{.Phase}}Handler{nil, m} + s.tail.Next = tail + s.tail = tail + } + + return nil +} + +// Insert injects the middleware relative to an existing middleware ID. +// Returns error if the original middleware does not exist, or the middleware +// being added already exists. +func (s *{{.Phase}}Step) Insert(m {{.Phase}}Middleware, relativeTo string, pos RelativePosition) error { + var prev, found *decorated{{.Phase}}Handler + for h := s.head; h != nil; { + if h.With.ID() == relativeTo { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decorated{{.Phase}}Handler) + } + if found == nil { + return fmt.Errorf("not found: %s", m.ID()) + } + + if pos == Before { + if prev == nil { // at the front + s.head = &decorated{{.Phase}}Handler{s.head, m} + } else { // somewhere in the middle + prev.Next = &decorated{{.Phase}}Handler{found, m} + } + } else { + if found.Next == nil { // at the end + tail := &decorated{{.Phase}}Handler{nil, m} + s.tail.Next = tail + s.tail = tail + } else { // somewhere in the middle + found.Next = &decorated{{.Phase}}Handler{found.Next, m} + } + } + + return nil +} + +// Swap removes the middleware by id, replacing it with the new middleware. +// Returns the middleware removed, or error if the middleware to be removed +// doesn't exist. +func (s *{{.Phase}}Step) Swap(id string, m {{.Phase}}Middleware) ({{.Phase}}Middleware, error) { + for h := s.head; h != nil; { + if h.With.ID() == id { + swapped := h.With + h.With = m + return swapped, nil + } + if h.Next == nil { + break + } + h = h.Next.(*decorated{{.Phase}}Handler) + } + return nil, fmt.Errorf("not found: %s", m.ID()) +} + +// Remove removes the middleware by id. Returns error if the middleware +// doesn't exist. +func (s *{{.Phase}}Step) Remove(id string) ({{.Phase}}Middleware, error) { + var prev, found *decorated{{.Phase}}Handler + for h := s.head; h != nil; { + if h.With.ID() == id { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decorated{{.Phase}}Handler) + } + if found == nil { + return nil, fmt.Errorf("not found: %s", id) + } + + if s.head == s.tail { // it's the only one + s.head = nil + s.tail = nil + } else if found == s.head { // at the front + s.head = s.head.Next.(*decorated{{.Phase}}Handler) + } else if found == s.tail { // at the end + prev.Next = nil + s.tail = prev + } else { + prev.Next = found.Next // somewhere in the middle + } + + return found.With, nil +} + +// List returns a list of the middleware in the step. +func (s *{{.Phase}}Step) List() []string { + var ids []string + for h := s.head; h != nil; { + ids = append(ids, h.With.ID()) + if h.Next == nil { + break + } + + // once executed, tail.Next of the list will be set to an + // *{{.PhaseLowercase}}WrapHandler, make sure to check for that + if hnext, ok := h.Next.(*decorated{{.Phase}}Handler); ok { + h = hnext + } + } + return ids +} + +// Clear removes all middleware in the step. +func (s *{{.Phase}}Step) Clear() { + s.head = nil + s.tail = nil +} + +type {{.PhaseLowercase}}WrapHandler struct { + Next Handler +} + +var _ {{.Phase}}Handler = (*{{.PhaseLowercase}}WrapHandler)(nil) + +// Handle{{.Phase}} implements {{.Phase}}Handler, converts types and delegates to underlying +// generic handler. +func (w {{.PhaseLowercase}}WrapHandler) Handle{{.Phase}}(ctx context.Context, in {{.Phase}}Input) ( + out {{.Phase}}Output, metadata Metadata, err error, +) { + res, metadata, err := w.Next.Handle(ctx, {{ .NextInput }}) + return {{.Phase}}Output{ +{{- range .Outputs }} + {{ .Name }}: {{ .Binding }}, +{{- end }} + }, metadata, err +} + +type decorated{{.Phase}}Handler struct { + Next {{.Phase}}Handler + With {{.Phase}}Middleware +} + +var _ {{.Phase}}Handler = (*decorated{{.Phase}}Handler)(nil) + +func (h decorated{{.Phase}}Handler) Handle{{.Phase}}(ctx context.Context, in {{.Phase}}Input) ( + out {{.Phase}}Output, metadata Metadata, err error, +) { + return h.With.Handle{{.Phase}}(ctx, in, h.Next) +} + +// {{.Phase}}HandlerFunc provides a wrapper around a function to be used as {{.PhaseLowercase}}Middleware. +type {{.Phase}}HandlerFunc func(context.Context, {{.Phase}}Input) ({{.Phase}}Output, Metadata, error) + +// Handle{{.Phase}} calls the wrapped function with the provided arguments. +func (f {{.Phase}}HandlerFunc) Handle{{.Phase}}(ctx context.Context, in {{.Phase}}Input) ({{.Phase}}Output, Metadata, error) { + return f(ctx, in) +} + +var _ {{.Phase}}Handler = {{.Phase}}HandlerFunc(nil) +` + +// Step describes how to generate a middleware. +type Step struct { + Phase string + PhaseLowercase string // set automatically by generator + + // the input literal passed along to the phase that follows this one + // + // for the final phase that would just be the transport client call + // (so for HTTP, the request) + NextInput string + + // struct fields on the step itself + StepFields []FieldDecl + + InputDoc string + Inputs []InputFieldDecl + + Outputs []OutputFieldDecl +} + +type FieldDecl struct { + Name, Type string +} + +type InputFieldDecl struct { + FieldDecl + Binding string +} + +type OutputFieldDecl struct { + FieldDecl + Binding string +} + +func (s *Step) Filepath() string { + return fmt.Sprintf("middleware/step_%s.go", s.PhaseLowercase) +} + +func main() { + tmpl, err := template.New("Step").Parse(stepTemplate) + if err != nil { + panic(err) + } + + for _, step := range []Step{ + { + Phase: "Initialize", + NextInput: "in.Parameters", + + InputDoc: `// InitializeInput wraps the input parameters for the InitializeMiddlewares to +// consume. InitializeMiddleware may modify the parameter value before +// forwarding it along to the next InitializeHandler. +`, + Inputs: []InputFieldDecl{ + { + FieldDecl: FieldDecl{"Parameters", "interface{}"}, + Binding: "in", + }, + }, + Outputs: []OutputFieldDecl{ + { + FieldDecl: FieldDecl{"Result", "interface{}"}, + Binding: "res", + }, + }, + }, + { + Phase: "Serialize", + NextInput: "in.Request", + StepFields: []FieldDecl{ + {"newRequest", "func() interface{}"}, + }, + + InputDoc: `// SerializeInput provides the input parameters for the SerializeMiddleware to +// consume. SerializeMiddleware may modify the Request value before forwarding +// SerializeInput along to the next SerializeHandler. The Parameters member +// should not be modified by SerializeMiddleware, InitializeMiddleware should +// be responsible for modifying the provided Parameter value.`, + Inputs: []InputFieldDecl{ + { + FieldDecl: FieldDecl{"Parameters", "interface{}"}, + Binding: "in", + }, + { + FieldDecl: FieldDecl{"Request", "interface{}"}, + Binding: "s.newRequest()", + }, + }, + Outputs: []OutputFieldDecl{ + { + FieldDecl: FieldDecl{"Result", "interface{}"}, + Binding: "res", + }, + }, + }, + { + Phase: "Build", + NextInput: "in.Request", + + InputDoc: `// BuildInput provides the input parameters for the BuildMiddleware to consume. +// BuildMiddleware may modify the Request value before forwarding the input +// along to the next BuildHandler.`, + Inputs: []InputFieldDecl{ + { + FieldDecl: FieldDecl{"Request", "interface{}"}, + Binding: "in", + }, + }, + Outputs: []OutputFieldDecl{ + { + FieldDecl: FieldDecl{"Result", "interface{}"}, + Binding: "res", + }, + }, + }, + { + Phase: "Finalize", + NextInput: "in.Request", + + InputDoc: `// FinalizeInput provides the input parameters for the FinalizeMiddleware to +// consume. FinalizeMiddleware may modify the Request value before forwarding +// the FinalizeInput along to the next next FinalizeHandler.`, + Inputs: []InputFieldDecl{ + { + FieldDecl: FieldDecl{"Request", "interface{}"}, + Binding: "in", + }, + }, + Outputs: []OutputFieldDecl{ + { + FieldDecl: FieldDecl{"Result", "interface{}"}, + Binding: "res", + }, + }, + }, + { + Phase: "Deserialize", + NextInput: "in.Request", + + InputDoc: `// DeserializeInput provides the input parameters for the DeserializeInput to +// consume. DeserializeMiddleware should not modify the Request, and instead +// forward it along to the next DeserializeHandler.`, + Inputs: []InputFieldDecl{ + { + FieldDecl: FieldDecl{"Request", "interface{}"}, + Binding: "in", + }, + }, + Outputs: []OutputFieldDecl{ + { + FieldDecl: FieldDecl{"RawResponse", "interface{}"}, + Binding: "res", + }, + { + FieldDecl: FieldDecl{"Result", "interface{}"}, + Binding: "nil", + }, + }, + }, + } { + step.PhaseLowercase = strings.ToLower(step.Phase) + + f, err := os.Create(step.Filepath()) + if err != nil { + panic(err) + } + defer f.Close() + + if err := tmpl.Execute(f, step); err != nil { + panic(err) + } + } +} diff --git a/middleware/step_build.go b/middleware/step_build.go index cc7fe89c..d612c5e2 100644 --- a/middleware/step_build.go +++ b/middleware/step_build.go @@ -1,7 +1,9 @@ +// Code generated by smithy-go/middleware/generate.go DO NOT EDIT. package middleware import ( "context" + "fmt" ) // BuildInput provides the input parameters for the BuildMiddleware to consume. @@ -25,14 +27,14 @@ type BuildHandler interface { } // BuildMiddleware provides the interface for middleware specific to the -// serialize step. Delegates to the next BuildHandler for further +// build step. Delegates to the next BuildHandler for further // processing. type BuildMiddleware interface { - // Unique ID for the middleware in theBuildStep. The step does not allow - // duplicate IDs. + // ID returns a unique ID for the middleware in the BuildStep. The step does not + // allow duplicate IDs. ID() string - // Invokes the middleware behavior which must delegate to the next handler + // HandleBuild invokes the middleware behavior which must delegate to the next handler // for the middleware chain to continue. The method must return a result or // error to its caller. HandleBuild(ctx context.Context, in BuildInput, next BuildHandler) ( @@ -54,7 +56,9 @@ type buildMiddlewareFunc struct { id string // Middleware function to be called. - fn func(context.Context, BuildInput, BuildHandler) (BuildOutput, Metadata, error) + fn func(context.Context, BuildInput, BuildHandler) ( + BuildOutput, Metadata, error, + ) } // ID returns the unique ID for the middleware. @@ -69,23 +73,22 @@ func (s buildMiddlewareFunc) HandleBuild(ctx context.Context, in BuildInput, nex var _ BuildMiddleware = (buildMiddlewareFunc{}) -// BuildStep provides the ordered grouping of BuildMiddleware to be invoked on -// a handler. +// BuildStep provides the ordered grouping of BuildMiddleware to be +// invoked on a handler. type BuildStep struct { - ids *orderedIDs + head *decoratedBuildHandler + tail *decoratedBuildHandler } -// NewBuildStep returns a BuildStep ready to have middleware for -// initialization added to it. +// NewBuildStep returns an BuildStep ready to have middleware for +// build added to it. func NewBuildStep() *BuildStep { - return &BuildStep{ - ids: newOrderedIDs(baseOrderedItems), - } + return &BuildStep{} } var _ Middleware = (*BuildStep)(nil) -// ID returns the unique name of the step as a middleware. +// ID returns the unique ID of the step as a middleware. func (s *BuildStep) ID() string { return "Build stack step" } @@ -97,77 +100,171 @@ func (s *BuildStep) ID() string { func (s *BuildStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( out interface{}, metadata Metadata, err error, ) { - order := s.ids.GetOrder() - - var h BuildHandler = buildWrapHandler{Next: next} - for i := len(order) - 1; i >= 0; i-- { - h = decoratedBuildHandler{ - Next: h, - With: order[i].(BuildMiddleware), - } - } - sIn := BuildInput{ Request: in, } - res, metadata, err := h.HandleBuild(ctx, sIn) + wh := &buildWrapHandler{next} + if s.head == nil { + res, metadata, err := wh.HandleBuild(ctx, sIn) + return res.Result, metadata, err + } + + s.tail.Next = wh + res, metadata, err := s.head.HandleBuild(ctx, sIn) return res.Result, metadata, err } // Get retrieves the middleware identified by id. If the middleware is not present, returns false. func (s *BuildStep) Get(id string) (BuildMiddleware, bool) { - get, ok := s.ids.Get(id) - if !ok { - return nil, false + for h := s.head; h != nil; { + if h.With.ID() == id { + return h.With, true + } + if h.Next == nil { + break + } + h = h.Next.(*decoratedBuildHandler) } - return get.(BuildMiddleware), ok + return nil, false } // Add injects the middleware to the relative position of the middleware group. -// Returns an error if the middleware already exists. +// +// Add never returns an error. It used to for duplicate phases but this +// behavior has since been removed as part of a performance optimization. The +// return value from Add can be ignored. func (s *BuildStep) Add(m BuildMiddleware, pos RelativePosition) error { - return s.ids.Add(m, pos) + if s.head == nil { + s.head = &decoratedBuildHandler{nil, m} + s.tail = s.head + return nil + } + + if pos == Before { + s.head = &decoratedBuildHandler{s.head, m} + } else { + tail := &decoratedBuildHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } + + return nil } -// Insert injects the middleware relative to an existing middleware id. -// Returns an error if the original middleware does not exist, or the middleware +// Insert injects the middleware relative to an existing middleware ID. +// Returns error if the original middleware does not exist, or the middleware // being added already exists. func (s *BuildStep) Insert(m BuildMiddleware, relativeTo string, pos RelativePosition) error { - return s.ids.Insert(m, relativeTo, pos) + var prev, found *decoratedBuildHandler + for h := s.head; h != nil; { + if h.With.ID() == relativeTo { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decoratedBuildHandler) + } + if found == nil { + return fmt.Errorf("not found: %s", m.ID()) + } + + if pos == Before { + if prev == nil { // at the front + s.head = &decoratedBuildHandler{s.head, m} + } else { // somewhere in the middle + prev.Next = &decoratedBuildHandler{found, m} + } + } else { + if found.Next == nil { // at the end + tail := &decoratedBuildHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } else { // somewhere in the middle + found.Next = &decoratedBuildHandler{found.Next, m} + } + } + + return nil } // Swap removes the middleware by id, replacing it with the new middleware. -// Returns the middleware removed, or an error if the middleware to be removed +// Returns the middleware removed, or error if the middleware to be removed // doesn't exist. func (s *BuildStep) Swap(id string, m BuildMiddleware) (BuildMiddleware, error) { - removed, err := s.ids.Swap(id, m) - if err != nil { - return nil, err + for h := s.head; h != nil; { + if h.With.ID() == id { + swapped := h.With + h.With = m + return swapped, nil + } + if h.Next == nil { + break + } + h = h.Next.(*decoratedBuildHandler) } - - return removed.(BuildMiddleware), nil + return nil, fmt.Errorf("not found: %s", m.ID()) } // Remove removes the middleware by id. Returns error if the middleware // doesn't exist. func (s *BuildStep) Remove(id string) (BuildMiddleware, error) { - removed, err := s.ids.Remove(id) - if err != nil { - return nil, err + var prev, found *decoratedBuildHandler + for h := s.head; h != nil; { + if h.With.ID() == id { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decoratedBuildHandler) + } + if found == nil { + return nil, fmt.Errorf("not found: %s", id) + } + + if s.head == s.tail { // it's the only one + s.head = nil + s.tail = nil + } else if found == s.head { // at the front + s.head = s.head.Next.(*decoratedBuildHandler) + } else if found == s.tail { // at the end + prev.Next = nil + s.tail = prev + } else { + prev.Next = found.Next // somewhere in the middle } - return removed.(BuildMiddleware), nil + return found.With, nil } // List returns a list of the middleware in the step. func (s *BuildStep) List() []string { - return s.ids.List() + var ids []string + for h := s.head; h != nil; { + ids = append(ids, h.With.ID()) + if h.Next == nil { + break + } + + // once executed, tail.Next of the list will be set to an + // *buildWrapHandler, make sure to check for that + if hnext, ok := h.Next.(*decoratedBuildHandler); ok { + h = hnext + } + } + return ids } // Clear removes all middleware in the step. func (s *BuildStep) Clear() { - s.ids.Clear() + s.head = nil + s.tail = nil } type buildWrapHandler struct { @@ -176,7 +273,7 @@ type buildWrapHandler struct { var _ BuildHandler = (*buildWrapHandler)(nil) -// Implements BuildHandler, converts types and delegates to underlying +// HandleBuild implements BuildHandler, converts types and delegates to underlying // generic handler. func (w buildWrapHandler) HandleBuild(ctx context.Context, in BuildInput) ( out BuildOutput, metadata Metadata, err error, @@ -200,12 +297,12 @@ func (h decoratedBuildHandler) HandleBuild(ctx context.Context, in BuildInput) ( return h.With.HandleBuild(ctx, in, h.Next) } -// BuildHandlerFunc provides a wrapper around a function to be used as a build middleware handler. +// BuildHandlerFunc provides a wrapper around a function to be used as buildMiddleware. type BuildHandlerFunc func(context.Context, BuildInput) (BuildOutput, Metadata, error) -// HandleBuild invokes the wrapped function with the provided arguments. -func (b BuildHandlerFunc) HandleBuild(ctx context.Context, in BuildInput) (BuildOutput, Metadata, error) { - return b(ctx, in) +// HandleBuild calls the wrapped function with the provided arguments. +func (f BuildHandlerFunc) HandleBuild(ctx context.Context, in BuildInput) (BuildOutput, Metadata, error) { + return f(ctx, in) } var _ BuildHandler = BuildHandlerFunc(nil) diff --git a/middleware/step_deserialize.go b/middleware/step_deserialize.go index 9a6679a5..6485f30e 100644 --- a/middleware/step_deserialize.go +++ b/middleware/step_deserialize.go @@ -1,7 +1,9 @@ +// Code generated by smithy-go/middleware/generate.go DO NOT EDIT. package middleware import ( "context" + "fmt" ) // DeserializeInput provides the input parameters for the DeserializeInput to @@ -11,10 +13,7 @@ type DeserializeInput struct { Request interface{} } -// DeserializeOutput provides the result returned by the next -// DeserializeHandler. The DeserializeMiddleware should deserialize the -// RawResponse into a Result that can be consumed by middleware higher up in -// the stack. +// DeserializeOutput provides the result returned by the next DeserializeHandler. type DeserializeOutput struct { RawResponse interface{} Result interface{} @@ -29,7 +28,7 @@ type DeserializeHandler interface { } // DeserializeMiddleware provides the interface for middleware specific to the -// serialize step. Delegates to the next DeserializeHandler for further +// deserialize step. Delegates to the next DeserializeHandler for further // processing. type DeserializeMiddleware interface { // ID returns a unique ID for the middleware in the DeserializeStep. The step does not @@ -44,8 +43,8 @@ type DeserializeMiddleware interface { ) } -// DeserializeMiddlewareFunc returns a DeserializeMiddleware with the unique ID -// provided, and the func to be invoked. +// DeserializeMiddlewareFunc returns a DeserializeMiddleware with the unique ID provided, +// and the func to be invoked. func DeserializeMiddlewareFunc(id string, fn func(context.Context, DeserializeInput, DeserializeHandler) (DeserializeOutput, Metadata, error)) DeserializeMiddleware { return deserializeMiddlewareFunc{ id: id, @@ -78,16 +77,14 @@ var _ DeserializeMiddleware = (deserializeMiddlewareFunc{}) // DeserializeStep provides the ordered grouping of DeserializeMiddleware to be // invoked on a handler. type DeserializeStep struct { - ids *orderedIDs + head *decoratedDeserializeHandler + tail *decoratedDeserializeHandler } -// NewDeserializeStep returns a DeserializeStep ready to have middleware for -// initialization added to it. +// NewDeserializeStep returns an DeserializeStep ready to have middleware for +// deserialize added to it. func NewDeserializeStep() *DeserializeStep { - return &DeserializeStep{ - // downstream SDK typically has larger Deserialize step - ids: newOrderedIDs(baseOrderedItems * 2), - } + return &DeserializeStep{} } var _ Middleware = (*DeserializeStep)(nil) @@ -104,77 +101,171 @@ func (s *DeserializeStep) ID() string { func (s *DeserializeStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( out interface{}, metadata Metadata, err error, ) { - order := s.ids.GetOrder() - - var h DeserializeHandler = deserializeWrapHandler{Next: next} - for i := len(order) - 1; i >= 0; i-- { - h = decoratedDeserializeHandler{ - Next: h, - With: order[i].(DeserializeMiddleware), - } - } - sIn := DeserializeInput{ Request: in, } - res, metadata, err := h.HandleDeserialize(ctx, sIn) + wh := &deserializeWrapHandler{next} + if s.head == nil { + res, metadata, err := wh.HandleDeserialize(ctx, sIn) + return res.Result, metadata, err + } + + s.tail.Next = wh + res, metadata, err := s.head.HandleDeserialize(ctx, sIn) return res.Result, metadata, err } // Get retrieves the middleware identified by id. If the middleware is not present, returns false. func (s *DeserializeStep) Get(id string) (DeserializeMiddleware, bool) { - get, ok := s.ids.Get(id) - if !ok { - return nil, false + for h := s.head; h != nil; { + if h.With.ID() == id { + return h.With, true + } + if h.Next == nil { + break + } + h = h.Next.(*decoratedDeserializeHandler) } - return get.(DeserializeMiddleware), ok + return nil, false } // Add injects the middleware to the relative position of the middleware group. -// Returns an error if the middleware already exists. +// +// Add never returns an error. It used to for duplicate phases but this +// behavior has since been removed as part of a performance optimization. The +// return value from Add can be ignored. func (s *DeserializeStep) Add(m DeserializeMiddleware, pos RelativePosition) error { - return s.ids.Add(m, pos) + if s.head == nil { + s.head = &decoratedDeserializeHandler{nil, m} + s.tail = s.head + return nil + } + + if pos == Before { + s.head = &decoratedDeserializeHandler{s.head, m} + } else { + tail := &decoratedDeserializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } + + return nil } // Insert injects the middleware relative to an existing middleware ID. // Returns error if the original middleware does not exist, or the middleware // being added already exists. func (s *DeserializeStep) Insert(m DeserializeMiddleware, relativeTo string, pos RelativePosition) error { - return s.ids.Insert(m, relativeTo, pos) + var prev, found *decoratedDeserializeHandler + for h := s.head; h != nil; { + if h.With.ID() == relativeTo { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decoratedDeserializeHandler) + } + if found == nil { + return fmt.Errorf("not found: %s", m.ID()) + } + + if pos == Before { + if prev == nil { // at the front + s.head = &decoratedDeserializeHandler{s.head, m} + } else { // somewhere in the middle + prev.Next = &decoratedDeserializeHandler{found, m} + } + } else { + if found.Next == nil { // at the end + tail := &decoratedDeserializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } else { // somewhere in the middle + found.Next = &decoratedDeserializeHandler{found.Next, m} + } + } + + return nil } // Swap removes the middleware by id, replacing it with the new middleware. // Returns the middleware removed, or error if the middleware to be removed // doesn't exist. func (s *DeserializeStep) Swap(id string, m DeserializeMiddleware) (DeserializeMiddleware, error) { - removed, err := s.ids.Swap(id, m) - if err != nil { - return nil, err + for h := s.head; h != nil; { + if h.With.ID() == id { + swapped := h.With + h.With = m + return swapped, nil + } + if h.Next == nil { + break + } + h = h.Next.(*decoratedDeserializeHandler) } - - return removed.(DeserializeMiddleware), nil + return nil, fmt.Errorf("not found: %s", m.ID()) } // Remove removes the middleware by id. Returns error if the middleware // doesn't exist. func (s *DeserializeStep) Remove(id string) (DeserializeMiddleware, error) { - removed, err := s.ids.Remove(id) - if err != nil { - return nil, err + var prev, found *decoratedDeserializeHandler + for h := s.head; h != nil; { + if h.With.ID() == id { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decoratedDeserializeHandler) + } + if found == nil { + return nil, fmt.Errorf("not found: %s", id) + } + + if s.head == s.tail { // it's the only one + s.head = nil + s.tail = nil + } else if found == s.head { // at the front + s.head = s.head.Next.(*decoratedDeserializeHandler) + } else if found == s.tail { // at the end + prev.Next = nil + s.tail = prev + } else { + prev.Next = found.Next // somewhere in the middle } - return removed.(DeserializeMiddleware), nil + return found.With, nil } // List returns a list of the middleware in the step. func (s *DeserializeStep) List() []string { - return s.ids.List() + var ids []string + for h := s.head; h != nil; { + ids = append(ids, h.With.ID()) + if h.Next == nil { + break + } + + // once executed, tail.Next of the list will be set to an + // *deserializeWrapHandler, make sure to check for that + if hnext, ok := h.Next.(*decoratedDeserializeHandler); ok { + h = hnext + } + } + return ids } // Clear removes all middleware in the step. func (s *DeserializeStep) Clear() { - s.ids.Clear() + s.head = nil + s.tail = nil } type deserializeWrapHandler struct { @@ -188,9 +279,10 @@ var _ DeserializeHandler = (*deserializeWrapHandler)(nil) func (w deserializeWrapHandler) HandleDeserialize(ctx context.Context, in DeserializeInput) ( out DeserializeOutput, metadata Metadata, err error, ) { - resp, metadata, err := w.Next.Handle(ctx, in.Request) + res, metadata, err := w.Next.Handle(ctx, in.Request) return DeserializeOutput{ - RawResponse: resp, + RawResponse: res, + Result: nil, }, metadata, err } @@ -207,12 +299,12 @@ func (h decoratedDeserializeHandler) HandleDeserialize(ctx context.Context, in D return h.With.HandleDeserialize(ctx, in, h.Next) } -// DeserializeHandlerFunc provides a wrapper around a function to be used as a deserialize middleware handler. +// DeserializeHandlerFunc provides a wrapper around a function to be used as deserializeMiddleware. type DeserializeHandlerFunc func(context.Context, DeserializeInput) (DeserializeOutput, Metadata, error) -// HandleDeserialize invokes the wrapped function with the given arguments. -func (d DeserializeHandlerFunc) HandleDeserialize(ctx context.Context, in DeserializeInput) (DeserializeOutput, Metadata, error) { - return d(ctx, in) +// HandleDeserialize calls the wrapped function with the provided arguments. +func (f DeserializeHandlerFunc) HandleDeserialize(ctx context.Context, in DeserializeInput) (DeserializeOutput, Metadata, error) { + return f(ctx, in) } var _ DeserializeHandler = DeserializeHandlerFunc(nil) diff --git a/middleware/step_finalize.go b/middleware/step_finalize.go index 76eab249..94b3425c 100644 --- a/middleware/step_finalize.go +++ b/middleware/step_finalize.go @@ -1,6 +1,10 @@ +// Code generated by smithy-go/middleware/generate.go DO NOT EDIT. package middleware -import "context" +import ( + "context" + "fmt" +) // FinalizeInput provides the input parameters for the FinalizeMiddleware to // consume. FinalizeMiddleware may modify the Request value before forwarding @@ -23,7 +27,7 @@ type FinalizeHandler interface { } // FinalizeMiddleware provides the interface for middleware specific to the -// serialize step. Delegates to the next FinalizeHandler for further +// finalize step. Delegates to the next FinalizeHandler for further // processing. type FinalizeMiddleware interface { // ID returns a unique ID for the middleware in the FinalizeStep. The step does not @@ -38,8 +42,8 @@ type FinalizeMiddleware interface { ) } -// FinalizeMiddlewareFunc returns a FinalizeMiddleware with the unique ID -// provided, and the func to be invoked. +// FinalizeMiddlewareFunc returns a FinalizeMiddleware with the unique ID provided, +// and the func to be invoked. func FinalizeMiddlewareFunc(id string, fn func(context.Context, FinalizeInput, FinalizeHandler) (FinalizeOutput, Metadata, error)) FinalizeMiddleware { return finalizeMiddlewareFunc{ id: id, @@ -72,21 +76,19 @@ var _ FinalizeMiddleware = (finalizeMiddlewareFunc{}) // FinalizeStep provides the ordered grouping of FinalizeMiddleware to be // invoked on a handler. type FinalizeStep struct { - ids *orderedIDs + head *decoratedFinalizeHandler + tail *decoratedFinalizeHandler } -// NewFinalizeStep returns a FinalizeStep ready to have middleware for -// initialization added to it. +// NewFinalizeStep returns an FinalizeStep ready to have middleware for +// finalize added to it. func NewFinalizeStep() *FinalizeStep { - return &FinalizeStep{ - // downstream SDK typically has larger Finalize step - ids: newOrderedIDs(baseOrderedItems * 2), - } + return &FinalizeStep{} } var _ Middleware = (*FinalizeStep)(nil) -// ID returns the unique id of the step as a middleware. +// ID returns the unique ID of the step as a middleware. func (s *FinalizeStep) ID() string { return "Finalize stack step" } @@ -98,77 +100,171 @@ func (s *FinalizeStep) ID() string { func (s *FinalizeStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( out interface{}, metadata Metadata, err error, ) { - order := s.ids.GetOrder() - - var h FinalizeHandler = finalizeWrapHandler{Next: next} - for i := len(order) - 1; i >= 0; i-- { - h = decoratedFinalizeHandler{ - Next: h, - With: order[i].(FinalizeMiddleware), - } - } - sIn := FinalizeInput{ Request: in, } - res, metadata, err := h.HandleFinalize(ctx, sIn) + wh := &finalizeWrapHandler{next} + if s.head == nil { + res, metadata, err := wh.HandleFinalize(ctx, sIn) + return res.Result, metadata, err + } + + s.tail.Next = wh + res, metadata, err := s.head.HandleFinalize(ctx, sIn) return res.Result, metadata, err } // Get retrieves the middleware identified by id. If the middleware is not present, returns false. func (s *FinalizeStep) Get(id string) (FinalizeMiddleware, bool) { - get, ok := s.ids.Get(id) - if !ok { - return nil, false + for h := s.head; h != nil; { + if h.With.ID() == id { + return h.With, true + } + if h.Next == nil { + break + } + h = h.Next.(*decoratedFinalizeHandler) } - return get.(FinalizeMiddleware), ok + return nil, false } // Add injects the middleware to the relative position of the middleware group. -// Returns an error if the middleware already exists. +// +// Add never returns an error. It used to for duplicate phases but this +// behavior has since been removed as part of a performance optimization. The +// return value from Add can be ignored. func (s *FinalizeStep) Add(m FinalizeMiddleware, pos RelativePosition) error { - return s.ids.Add(m, pos) + if s.head == nil { + s.head = &decoratedFinalizeHandler{nil, m} + s.tail = s.head + return nil + } + + if pos == Before { + s.head = &decoratedFinalizeHandler{s.head, m} + } else { + tail := &decoratedFinalizeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } + + return nil } // Insert injects the middleware relative to an existing middleware ID. // Returns error if the original middleware does not exist, or the middleware // being added already exists. func (s *FinalizeStep) Insert(m FinalizeMiddleware, relativeTo string, pos RelativePosition) error { - return s.ids.Insert(m, relativeTo, pos) + var prev, found *decoratedFinalizeHandler + for h := s.head; h != nil; { + if h.With.ID() == relativeTo { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decoratedFinalizeHandler) + } + if found == nil { + return fmt.Errorf("not found: %s", m.ID()) + } + + if pos == Before { + if prev == nil { // at the front + s.head = &decoratedFinalizeHandler{s.head, m} + } else { // somewhere in the middle + prev.Next = &decoratedFinalizeHandler{found, m} + } + } else { + if found.Next == nil { // at the end + tail := &decoratedFinalizeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } else { // somewhere in the middle + found.Next = &decoratedFinalizeHandler{found.Next, m} + } + } + + return nil } // Swap removes the middleware by id, replacing it with the new middleware. // Returns the middleware removed, or error if the middleware to be removed // doesn't exist. func (s *FinalizeStep) Swap(id string, m FinalizeMiddleware) (FinalizeMiddleware, error) { - removed, err := s.ids.Swap(id, m) - if err != nil { - return nil, err + for h := s.head; h != nil; { + if h.With.ID() == id { + swapped := h.With + h.With = m + return swapped, nil + } + if h.Next == nil { + break + } + h = h.Next.(*decoratedFinalizeHandler) } - - return removed.(FinalizeMiddleware), nil + return nil, fmt.Errorf("not found: %s", m.ID()) } // Remove removes the middleware by id. Returns error if the middleware // doesn't exist. func (s *FinalizeStep) Remove(id string) (FinalizeMiddleware, error) { - removed, err := s.ids.Remove(id) - if err != nil { - return nil, err + var prev, found *decoratedFinalizeHandler + for h := s.head; h != nil; { + if h.With.ID() == id { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decoratedFinalizeHandler) + } + if found == nil { + return nil, fmt.Errorf("not found: %s", id) + } + + if s.head == s.tail { // it's the only one + s.head = nil + s.tail = nil + } else if found == s.head { // at the front + s.head = s.head.Next.(*decoratedFinalizeHandler) + } else if found == s.tail { // at the end + prev.Next = nil + s.tail = prev + } else { + prev.Next = found.Next // somewhere in the middle } - return removed.(FinalizeMiddleware), nil + return found.With, nil } // List returns a list of the middleware in the step. func (s *FinalizeStep) List() []string { - return s.ids.List() + var ids []string + for h := s.head; h != nil; { + ids = append(ids, h.With.ID()) + if h.Next == nil { + break + } + + // once executed, tail.Next of the list will be set to an + // *finalizeWrapHandler, make sure to check for that + if hnext, ok := h.Next.(*decoratedFinalizeHandler); ok { + h = hnext + } + } + return ids } // Clear removes all middleware in the step. func (s *FinalizeStep) Clear() { - s.ids.Clear() + s.head = nil + s.tail = nil } type finalizeWrapHandler struct { @@ -201,10 +297,10 @@ func (h decoratedFinalizeHandler) HandleFinalize(ctx context.Context, in Finaliz return h.With.HandleFinalize(ctx, in, h.Next) } -// FinalizeHandlerFunc provides a wrapper around a function to be used as a finalize middleware handler. +// FinalizeHandlerFunc provides a wrapper around a function to be used as finalizeMiddleware. type FinalizeHandlerFunc func(context.Context, FinalizeInput) (FinalizeOutput, Metadata, error) -// HandleFinalize invokes the wrapped function with the given arguments. +// HandleFinalize calls the wrapped function with the provided arguments. func (f FinalizeHandlerFunc) HandleFinalize(ctx context.Context, in FinalizeInput) (FinalizeOutput, Metadata, error) { return f(ctx, in) } diff --git a/middleware/step_initialize.go b/middleware/step_initialize.go index 312be3a3..91bf0ad1 100644 --- a/middleware/step_initialize.go +++ b/middleware/step_initialize.go @@ -1,10 +1,15 @@ +// Code generated by smithy-go/middleware/generate.go DO NOT EDIT. package middleware -import "context" +import ( + "context" + "fmt" +) // InitializeInput wraps the input parameters for the InitializeMiddlewares to // consume. InitializeMiddleware may modify the parameter value before // forwarding it along to the next InitializeHandler. + type InitializeInput struct { Parameters interface{} } @@ -72,15 +77,14 @@ var _ InitializeMiddleware = (initializeMiddlewareFunc{}) // InitializeStep provides the ordered grouping of InitializeMiddleware to be // invoked on a handler. type InitializeStep struct { - ids *orderedIDs + head *decoratedInitializeHandler + tail *decoratedInitializeHandler } // NewInitializeStep returns an InitializeStep ready to have middleware for -// initialization added to it. +// initialize added to it. func NewInitializeStep() *InitializeStep { - return &InitializeStep{ - ids: newOrderedIDs(baseOrderedItems), - } + return &InitializeStep{} } var _ Middleware = (*InitializeStep)(nil) @@ -97,77 +101,171 @@ func (s *InitializeStep) ID() string { func (s *InitializeStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( out interface{}, metadata Metadata, err error, ) { - order := s.ids.GetOrder() - - var h InitializeHandler = initializeWrapHandler{Next: next} - for i := len(order) - 1; i >= 0; i-- { - h = decoratedInitializeHandler{ - Next: h, - With: order[i].(InitializeMiddleware), - } - } - sIn := InitializeInput{ Parameters: in, } - res, metadata, err := h.HandleInitialize(ctx, sIn) + wh := &initializeWrapHandler{next} + if s.head == nil { + res, metadata, err := wh.HandleInitialize(ctx, sIn) + return res.Result, metadata, err + } + + s.tail.Next = wh + res, metadata, err := s.head.HandleInitialize(ctx, sIn) return res.Result, metadata, err } // Get retrieves the middleware identified by id. If the middleware is not present, returns false. func (s *InitializeStep) Get(id string) (InitializeMiddleware, bool) { - get, ok := s.ids.Get(id) - if !ok { - return nil, false + for h := s.head; h != nil; { + if h.With.ID() == id { + return h.With, true + } + if h.Next == nil { + break + } + h = h.Next.(*decoratedInitializeHandler) } - return get.(InitializeMiddleware), ok + return nil, false } // Add injects the middleware to the relative position of the middleware group. -// Returns an error if the middleware already exists. +// +// Add never returns an error. It used to for duplicate phases but this +// behavior has since been removed as part of a performance optimization. The +// return value from Add can be ignored. func (s *InitializeStep) Add(m InitializeMiddleware, pos RelativePosition) error { - return s.ids.Add(m, pos) + if s.head == nil { + s.head = &decoratedInitializeHandler{nil, m} + s.tail = s.head + return nil + } + + if pos == Before { + s.head = &decoratedInitializeHandler{s.head, m} + } else { + tail := &decoratedInitializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } + + return nil } // Insert injects the middleware relative to an existing middleware ID. // Returns error if the original middleware does not exist, or the middleware // being added already exists. func (s *InitializeStep) Insert(m InitializeMiddleware, relativeTo string, pos RelativePosition) error { - return s.ids.Insert(m, relativeTo, pos) + var prev, found *decoratedInitializeHandler + for h := s.head; h != nil; { + if h.With.ID() == relativeTo { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decoratedInitializeHandler) + } + if found == nil { + return fmt.Errorf("not found: %s", m.ID()) + } + + if pos == Before { + if prev == nil { // at the front + s.head = &decoratedInitializeHandler{s.head, m} + } else { // somewhere in the middle + prev.Next = &decoratedInitializeHandler{found, m} + } + } else { + if found.Next == nil { // at the end + tail := &decoratedInitializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } else { // somewhere in the middle + found.Next = &decoratedInitializeHandler{found.Next, m} + } + } + + return nil } // Swap removes the middleware by id, replacing it with the new middleware. // Returns the middleware removed, or error if the middleware to be removed // doesn't exist. func (s *InitializeStep) Swap(id string, m InitializeMiddleware) (InitializeMiddleware, error) { - removed, err := s.ids.Swap(id, m) - if err != nil { - return nil, err + for h := s.head; h != nil; { + if h.With.ID() == id { + swapped := h.With + h.With = m + return swapped, nil + } + if h.Next == nil { + break + } + h = h.Next.(*decoratedInitializeHandler) } - - return removed.(InitializeMiddleware), nil + return nil, fmt.Errorf("not found: %s", m.ID()) } // Remove removes the middleware by id. Returns error if the middleware // doesn't exist. func (s *InitializeStep) Remove(id string) (InitializeMiddleware, error) { - removed, err := s.ids.Remove(id) - if err != nil { - return nil, err + var prev, found *decoratedInitializeHandler + for h := s.head; h != nil; { + if h.With.ID() == id { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decoratedInitializeHandler) + } + if found == nil { + return nil, fmt.Errorf("not found: %s", id) + } + + if s.head == s.tail { // it's the only one + s.head = nil + s.tail = nil + } else if found == s.head { // at the front + s.head = s.head.Next.(*decoratedInitializeHandler) + } else if found == s.tail { // at the end + prev.Next = nil + s.tail = prev + } else { + prev.Next = found.Next // somewhere in the middle } - return removed.(InitializeMiddleware), nil + return found.With, nil } // List returns a list of the middleware in the step. func (s *InitializeStep) List() []string { - return s.ids.List() + var ids []string + for h := s.head; h != nil; { + ids = append(ids, h.With.ID()) + if h.Next == nil { + break + } + + // once executed, tail.Next of the list will be set to an + // *initializeWrapHandler, make sure to check for that + if hnext, ok := h.Next.(*decoratedInitializeHandler); ok { + h = hnext + } + } + return ids } // Clear removes all middleware in the step. func (s *InitializeStep) Clear() { - s.ids.Clear() + s.head = nil + s.tail = nil } type initializeWrapHandler struct { @@ -200,12 +298,12 @@ func (h decoratedInitializeHandler) HandleInitialize(ctx context.Context, in Ini return h.With.HandleInitialize(ctx, in, h.Next) } -// InitializeHandlerFunc provides a wrapper around a function to be used as an initialize middleware handler. +// InitializeHandlerFunc provides a wrapper around a function to be used as initializeMiddleware. type InitializeHandlerFunc func(context.Context, InitializeInput) (InitializeOutput, Metadata, error) // HandleInitialize calls the wrapped function with the provided arguments. -func (i InitializeHandlerFunc) HandleInitialize(ctx context.Context, in InitializeInput) (InitializeOutput, Metadata, error) { - return i(ctx, in) +func (f InitializeHandlerFunc) HandleInitialize(ctx context.Context, in InitializeInput) (InitializeOutput, Metadata, error) { + return f(ctx, in) } var _ InitializeHandler = InitializeHandlerFunc(nil) diff --git a/middleware/step_serialize.go b/middleware/step_serialize.go index a4ce4bee..3b639bf8 100644 --- a/middleware/step_serialize.go +++ b/middleware/step_serialize.go @@ -1,6 +1,10 @@ +// Code generated by smithy-go/middleware/generate.go DO NOT EDIT. package middleware -import "context" +import ( + "context" + "fmt" +) // SerializeInput provides the input parameters for the SerializeMiddleware to // consume. SerializeMiddleware may modify the Request value before forwarding @@ -41,8 +45,8 @@ type SerializeMiddleware interface { ) } -// SerializeMiddlewareFunc returns a SerializeMiddleware with the unique ID -// provided, and the func to be invoked. +// SerializeMiddlewareFunc returns a SerializeMiddleware with the unique ID provided, +// and the func to be invoked. func SerializeMiddlewareFunc(id string, fn func(context.Context, SerializeInput, SerializeHandler) (SerializeOutput, Metadata, error)) SerializeMiddleware { return serializeMiddlewareFunc{ id: id, @@ -75,17 +79,15 @@ var _ SerializeMiddleware = (serializeMiddlewareFunc{}) // SerializeStep provides the ordered grouping of SerializeMiddleware to be // invoked on a handler. type SerializeStep struct { + head *decoratedSerializeHandler + tail *decoratedSerializeHandler newRequest func() interface{} - ids *orderedIDs } -// NewSerializeStep returns a SerializeStep ready to have middleware for -// initialization added to it. The newRequest func parameter is used to -// initialize the transport specific request for the stack SerializeStep to -// serialize the input parameters into. +// NewSerializeStep returns an SerializeStep ready to have middleware for +// serialize added to it. func NewSerializeStep(newRequest func() interface{}) *SerializeStep { return &SerializeStep{ - ids: newOrderedIDs(baseOrderedItems), newRequest: newRequest, } } @@ -104,78 +106,172 @@ func (s *SerializeStep) ID() string { func (s *SerializeStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( out interface{}, metadata Metadata, err error, ) { - order := s.ids.GetOrder() - - var h SerializeHandler = serializeWrapHandler{Next: next} - for i := len(order) - 1; i >= 0; i-- { - h = decoratedSerializeHandler{ - Next: h, - With: order[i].(SerializeMiddleware), - } - } - sIn := SerializeInput{ Parameters: in, Request: s.newRequest(), } - res, metadata, err := h.HandleSerialize(ctx, sIn) + wh := &serializeWrapHandler{next} + if s.head == nil { + res, metadata, err := wh.HandleSerialize(ctx, sIn) + return res.Result, metadata, err + } + + s.tail.Next = wh + res, metadata, err := s.head.HandleSerialize(ctx, sIn) return res.Result, metadata, err } // Get retrieves the middleware identified by id. If the middleware is not present, returns false. func (s *SerializeStep) Get(id string) (SerializeMiddleware, bool) { - get, ok := s.ids.Get(id) - if !ok { - return nil, false + for h := s.head; h != nil; { + if h.With.ID() == id { + return h.With, true + } + if h.Next == nil { + break + } + h = h.Next.(*decoratedSerializeHandler) } - return get.(SerializeMiddleware), ok + return nil, false } // Add injects the middleware to the relative position of the middleware group. -// Returns an error if the middleware already exists. +// +// Add never returns an error. It used to for duplicate phases but this +// behavior has since been removed as part of a performance optimization. The +// return value from Add can be ignored. func (s *SerializeStep) Add(m SerializeMiddleware, pos RelativePosition) error { - return s.ids.Add(m, pos) + if s.head == nil { + s.head = &decoratedSerializeHandler{nil, m} + s.tail = s.head + return nil + } + + if pos == Before { + s.head = &decoratedSerializeHandler{s.head, m} + } else { + tail := &decoratedSerializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } + + return nil } // Insert injects the middleware relative to an existing middleware ID. // Returns error if the original middleware does not exist, or the middleware // being added already exists. func (s *SerializeStep) Insert(m SerializeMiddleware, relativeTo string, pos RelativePosition) error { - return s.ids.Insert(m, relativeTo, pos) + var prev, found *decoratedSerializeHandler + for h := s.head; h != nil; { + if h.With.ID() == relativeTo { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decoratedSerializeHandler) + } + if found == nil { + return fmt.Errorf("not found: %s", m.ID()) + } + + if pos == Before { + if prev == nil { // at the front + s.head = &decoratedSerializeHandler{s.head, m} + } else { // somewhere in the middle + prev.Next = &decoratedSerializeHandler{found, m} + } + } else { + if found.Next == nil { // at the end + tail := &decoratedSerializeHandler{nil, m} + s.tail.Next = tail + s.tail = tail + } else { // somewhere in the middle + found.Next = &decoratedSerializeHandler{found.Next, m} + } + } + + return nil } // Swap removes the middleware by id, replacing it with the new middleware. // Returns the middleware removed, or error if the middleware to be removed // doesn't exist. func (s *SerializeStep) Swap(id string, m SerializeMiddleware) (SerializeMiddleware, error) { - removed, err := s.ids.Swap(id, m) - if err != nil { - return nil, err + for h := s.head; h != nil; { + if h.With.ID() == id { + swapped := h.With + h.With = m + return swapped, nil + } + if h.Next == nil { + break + } + h = h.Next.(*decoratedSerializeHandler) } - - return removed.(SerializeMiddleware), nil + return nil, fmt.Errorf("not found: %s", m.ID()) } // Remove removes the middleware by id. Returns error if the middleware // doesn't exist. func (s *SerializeStep) Remove(id string) (SerializeMiddleware, error) { - removed, err := s.ids.Remove(id) - if err != nil { - return nil, err + var prev, found *decoratedSerializeHandler + for h := s.head; h != nil; { + if h.With.ID() == id { + found = h + break + } + prev = h + if h.Next == nil { + break + } + h = h.Next.(*decoratedSerializeHandler) + } + if found == nil { + return nil, fmt.Errorf("not found: %s", id) + } + + if s.head == s.tail { // it's the only one + s.head = nil + s.tail = nil + } else if found == s.head { // at the front + s.head = s.head.Next.(*decoratedSerializeHandler) + } else if found == s.tail { // at the end + prev.Next = nil + s.tail = prev + } else { + prev.Next = found.Next // somewhere in the middle } - return removed.(SerializeMiddleware), nil + return found.With, nil } // List returns a list of the middleware in the step. func (s *SerializeStep) List() []string { - return s.ids.List() + var ids []string + for h := s.head; h != nil; { + ids = append(ids, h.With.ID()) + if h.Next == nil { + break + } + + // once executed, tail.Next of the list will be set to an + // *serializeWrapHandler, make sure to check for that + if hnext, ok := h.Next.(*decoratedSerializeHandler); ok { + h = hnext + } + } + return ids } // Clear removes all middleware in the step. func (s *SerializeStep) Clear() { - s.ids.Clear() + s.head = nil + s.tail = nil } type serializeWrapHandler struct { @@ -184,7 +280,7 @@ type serializeWrapHandler struct { var _ SerializeHandler = (*serializeWrapHandler)(nil) -// Implements SerializeHandler, converts types and delegates to underlying +// HandleSerialize implements SerializeHandler, converts types and delegates to underlying // generic handler. func (w serializeWrapHandler) HandleSerialize(ctx context.Context, in SerializeInput) ( out SerializeOutput, metadata Metadata, err error, @@ -208,12 +304,12 @@ func (h decoratedSerializeHandler) HandleSerialize(ctx context.Context, in Seria return h.With.HandleSerialize(ctx, in, h.Next) } -// SerializeHandlerFunc provides a wrapper around a function to be used as a serialize middleware handler. +// SerializeHandlerFunc provides a wrapper around a function to be used as serializeMiddleware. type SerializeHandlerFunc func(context.Context, SerializeInput) (SerializeOutput, Metadata, error) // HandleSerialize calls the wrapped function with the provided arguments. -func (s SerializeHandlerFunc) HandleSerialize(ctx context.Context, in SerializeInput) (SerializeOutput, Metadata, error) { - return s(ctx, in) +func (f SerializeHandlerFunc) HandleSerialize(ctx context.Context, in SerializeInput) (SerializeOutput, Metadata, error) { + return f(ctx, in) } var _ SerializeHandler = SerializeHandlerFunc(nil)