A number of cases were not handled properly: even though optional
userdata was allowed, the handling would cause unreachable to be
reached if null handles were actually passed. Also, being able to use
void to specify "no userdata please" is useful; however, in this case
we do have to still pass NULL to the C library calls.
The casting logic has been pulled out to some helper functions, which
make it more consistent. Some mediocre additional test coverage has
been added as well.
Various type definitions in std.builtin got renamed to avoid field/decl
collisions as was required for the implementation of decl literals.
Since this is the only thing busted, shim it and retain cross-version
support for now.
This is mainly updates to the build system, but there were a couple of
stdlib changes for the tests. The build system does include handling
more properly now as well, I think. It has fewer hacks, at least.
By performing more pointer casting gymnastics, additional types of
pointer can be supported. For example, now const qualified pointers
can be passed through thanks to the use of constCast. Also, having
explicit ptrCast allows nested pointers (e.g. a pointer to a slice,
such as `*[]const u8`) to be passed as userdata as well (the compiler
refuses to coerce a pointer to a pointer to `?*anyopaque` for some
reason, I guess because maybe it's ambiguous somehow?) Hopefully this
extra casting does not appreciably reduce the compiler's ability to
catch real bugs (for example, on a 64-bit machine, ptrCast can convert
a *u64 into a **u64 because there is no alignment change).
Also, the `volatile` pointer specifier is still not supported.
`allowzero` pointers probably also have a problem. Those are both
extreme edge cases, however.
This was intended to work before but did not due to an oversight.
Specifically, because the userdata pointers are stored as ?*anyopaque,
which does *not* have the const qualifier, they must have their const
qualifiers also removed. This is safe because the thunk guarantees
that the consumer code never sees the non-const version of the
pointer, and the nats library itself does nothing except pass the
pointer through to the user callback.
The tests have been updated to ensure this case works. The examples
still use a mutable userdata pointer to show that that case also
works. More tests could be added for the sake of increased rigor, but
I don't think it adds much.
One of the things I have 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).
This is a simple enough change. However, there are no tests for the
streaming functionality, and I need to decide if I want to actually
try to write bindings for them.
1. I'm not using git-subrepo for this because most of the protobuf-c
git repository is for the protocol buffers compiler integration,
which we do not need because nats.c already has the generated files
in its source tree.
2. The protobuf-c runtime library is pretty simple, so maintaining its
build process should be quite straightforward. It seems stable as
well, which should simplify the maintenance burden.
3. Not having streaming support is the last major nats.c feature
missing from this project (as far as I am aware). Building this
functionality into the library, even if a nice zig API is missing
(as it is with jetStream as well), can still allow a determined
user to wrap and use the functionality while benefitting from the
zig build system and package manager, which is a win.
I was originally going to have this generate a random token by default,
but I don't think it matters. the bigger thing would perhaps be to
manage the listen port to avoid conflicts, but this isn't currently a
problem, so I will pretend it won't ever be a problem.
Once the Subscription and Message tests have been fleshed out, this
will go into maintenance mode, since I've pretty much accomplished
everything I wanted to accomplish with it.
If you think these unit tests look crappy, that's because they are.
Actual behavioral tests are pretty much exclusively relying on the
underlying C library being well-tested, so all these tests are really
trying to do is ref the bindings in our endpoints to make sure there
aren't any compilation issues with them. Obviously this is making a
difference, since a variety of issues have been found and addressed as
a result.
Since I went to the effort of getting this to build with LibreSSL, it
makes sense to check that it works. And it seems to. There's nothing
special about the certificates added, except that they don't expire
for 100 years, which is hopefully long enough that nothing will matter
any more. They get baked into the test executable, since this was the
best way I could figure out to be able to consistently load them
during runtime, since they're stored relative to the source, not
necessarily relative to the working directory in use when the test
executable is run.
This required some augmentation to the test server launcher which will
make it easier to add additional flags to it in the future, if that
becomes necessary.
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.
I don't have a single clue in heck if this actually works, but it at
least does compile. At some point I will probably add a test or two to
find out how broken this is.
Various copypasta and typing errors around the thunks, some other
copypasta errors, etc. Also add a test which hits a decent chunk of
the API surface of ConnectionOptions, which is how these issues were
caught in the first place. This is an ugly test, but it has clearly
served its purpose.
I created a utility class to spawn a NATS server. This assumes it is
installed and in PATH, which should be easy enough to accomplish for a
CI environment. The current approach will not work with parallel
tests, but that's not a practical reality, so this route should be
fine for the time being. It might be nice to spawn a default server at
the beginning of testing and tear it down at the end, to save waiting
for the startup/shutdown time in many individual tests. This makes me
wonder: if I initialize a server in the beginning of the `test` block
in main that imports the other modules, does that scope stay live
while the "child" tests are running? My default guess would be
probably not, but that would be very convenient, so I might try it out
and see.
I've gotten tired of trying to find this in the cache dir, since the
build system does not rerun it once it is cached. Also sometimes the
build runner does weird things to the output.
These are mostly just tests to make sure the wrappers function as
written, rather than testing for any specific output. This commit
demonstrates the simple value of actually referencing the various
wrapper functions, as a variety of really basic compilation errors
were caught and addressed.
This is probably the sort of thing that I wouldn't actually think of
having explicit test coverage for if I hadn't accidentally ran across
it while fiddling. I will compensate for this easily by not actually
writing tests at all.
This was the point that I realized there's no reason to have the string
variants of the publishing methods. But also there's not really much
point in porting the other getting-started examples, since we've
covered all their functionality in the existing examples
(actually, this one is redundant too, but I have already done it, so
it's getting grandfathered in).
Porting some of the more interesting examples might be a good idea, but
those have a weird argument parser that I don't really want to port
(even though it is very simple in the way that it works). For the most
part, I think writing unit tests will do a better of flexing the
bindings.
There's not much of a reason this should be used externally, but I also
favor having things be exported rather than not exported. There will
probably be more opening up of the other imports here in the future.
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.