package server import ( "errors" "io" "net/http" "unsafe" ) // maxParams defines the maximum number of parameters per route. const maxParams = 16 // Context represents the interface for a request & response context. type Context interface { Bytes([]byte) error Error(status int, messages ...any) error Reader(io.Reader) error SetStatus(status int) String(string) error } // context represents a request & response context. type context struct { request *http.Request response http.ResponseWriter paramNames [maxParams]string paramValues [maxParams]string paramCount int } // newContext returns a new context from the pool. func newContext(request *http.Request, response http.ResponseWriter) *context { ctx := contextPool.Get().(*context) ctx.request = request ctx.response = response ctx.paramCount = 0 return ctx } // Bytes responds with a raw byte slice. func (ctx *context) Bytes(body []byte) error { _, err := ctx.response.Write(body) return err } // Error is used for sending error messages to the client. func (ctx *context) Error(status int, messages ...any) error { var combined []error for _, msg := range messages { switch err := msg.(type) { case error: combined = append(combined, err) case string: combined = append(combined, errors.New(err)) } } ctx.SetStatus(status) return errors.Join(combined...) } // Reader sends the contents of the io.Reader without creating an in-memory copy. func (ctx *context) Reader(reader io.Reader) error { _, err := io.Copy(ctx.response, reader) return err } // SetStatus writes the header with the given HTTP status code. func (ctx *context) SetStatus(status int) { ctx.response.WriteHeader(status) } // String responds with the given string. func (ctx *context) String(body string) error { slice := unsafe.Slice(unsafe.StringData(body), len(body)) return ctx.Bytes(slice) } // addParameter adds a new parameter to the context. func (ctx *context) addParameter(name string, value string) { ctx.paramNames[ctx.paramCount] = name ctx.paramValues[ctx.paramCount] = value ctx.paramCount++ }