Instead of using struct embedding to build web.Mux, start moving towards
explicit mappings. This doesn't actually change the public API of
web.Mux, but feels a little cleaner to me.
The longer-term thing here is to get rid of the functions defined on
Muxes in the public documentation that are defined on "rt *Mux", which
is just plain ugly.
If you're manipulating your middleware stack concurrently with active
requests you're probably doing something wrong, and it's not worth
either the complexity or runtime cost to support you hitting yourself.
We can probably take this principle a bit further and disallow mutating
the middleware stack after any requests have been made (which will
eliminate even more complexity) but that can be a project for another
day.
Previously, we would keep the URLParams / Env associated with a cStack
around until the next request flushed them. However, this might cause
either of these maps to stick around for much longer than they ought to,
potentially keeping references to many, many objects.
Instead, clear out the saved context on every release.
Previously, the middleware stack passed the router a C, but this was
both odd semantically (a pattern which mutated the environment might see
a *different* environment) and bad for perf: it cost us an allocation.
Now we only pass around *C's internally.
Importantly ("importantly"), this gets us down to 0 allocations for the
static routing case, and one allocation (the URLParams map) for the
normal routing case.
Let's just hope the GC does its job correctly and don't try to help it
out. This case is probably triggered very infrequently since most people
set up their middleware before they accept a single request, and it's
worth about 100ns of perf on the common case for us if we get rid of the
defer.
The "name" parameter was originally a workaround for the fact that function
pointers in Go never compare equal to each other (unless they are both nil).
Unfortunately, this presents a pretty terrible interface to the end programmer,
since they'll probably end up stuttering something like:
mux.Use("MyMiddleware", MyMiddleware)
Luckily, I found a workaround for doing function pointer equality (it doesn't
even require "unsafe"!), so we can get rid of the name parameter for good.
They say that every programmer builds a web framework at some point. This one is
mine.
The basic idea behind this one is that I wanted a Sinatra for Go, and I couldn't
find one anywhere. Furthermore, net/http is in many ways really close to what I
want out of a Sinatra-in-Go, and many of the frameworks I did find seemed to
reinvent too much, or were incompatible with net/http in weird ways, or used too
much questionable reflection magic. So long story short, I wrote my own.
This implementation is only half-baked, and among other things it's missing a
whole lot of tests.