One of the things I have not learned but done a better job of
internalizing while working with zig over the last few months is that
the less magic that exists, the better. In the case of parameterized
functions, this means that it is much better to restrict the range of
types that are permitted to be passed than to perform type
manipulation. In other words, it's more confusing to see a function
that is parameterized with `SomeType` taking a pointer to that type
than having it be parameterized directly to take the pointer.
Obviously there are exceptions to this rule, like std.mem.eql taking
slices of its parameterized type.
In fact, this new approach fixes some edge cases. Null userdata may now
be passed in, since the user can now actually specify an optional
pointer type (e.g. `?*void` may be used to provide always-null
userdata). Additionally, a pointer to a constant value can now be
passed in, which wasn't possible before (this could have been worked
around by use of constCast and being careful, but that's an
exceedingly bad option compared to having the type system work for
you).
Tests are CC0/public domain because there's no reason for them not to
be. Examples are also CC0/public domain, but this may be a little bit
weird because they are largely straightforward ports of examples from
nats.c which carry the Apache license. However, I personally wrote
them against the zig bindings and I doubt anyone will end up in a
court of law due to their software containing uselessly trivial
example code.
After contemplating this for a little bit, there's no point in exposing
these separately from the plain variants. Even nats.c internally calls
its plain variants after calling `strlen` on the input. Zig benefits
from having nicer pointer types than C, so we get "string" handling
for free from the fact that the standard variants take slices anyway.