* Server improvements
The server's start_link didn't actually start_link. I've changed this to
bring the server's supervision into the user's application.
Also, we weren't properly cleaning up after server errors, so now I just crash.
* Allow 'default required' fields to be nil
We discovered that other Thrift implementations we use internally do not
serialize unset 'default required' fields. This change brings our
implementation's behavior in line with the others.
* Test that optional fields are serialized
- Our command line options now more closely mimic the Apache Thrift
compiler's. We support both long and "short" option formats.
- The compile task's output now simply prints "Compiling N files", which
is the Elixir 1.3+ output convention. Use the `--verbose` command line
option to see per-file output.
- The compiler task's unit test helper code has been simplified a bit.
Enforce field requiredness during serialization
The IDL spec [1] states that required fields must always be written during
serialization. There are also "default required" fields, i.e. fields specified
neither as required or optional. Apparently they also should always be written,
though there are exceptions to which the spec alludes but about which it does
not deign to elaborate.
[1]: https://thrift.apache.org/docs/idl#field-requiredness
This gives us the ability to use 1.3+ APIs as we develop our 2.0 branch.
Many other libraries (Absinthe, Dialyxir) also have a 1.3+ requirement.
Also, Elixir 1.4 is imminent, so add that to our testing matrix too.
* Binary Framed server
This is the implementation of the binary thrift framed server. It features
a configurable acceptor pool and generates code to make serialization and
deserialization automatic.
Our :thrift compiler is now implemented in terms of our Elixir code
generation framework. This drops our dependency on the Apache Thrift
compiler binary.
The new Thrift.Generator.targets/1 function is used to determine the
full set of generated output files for a given input .thrift file. This
ensures that we only generate Elixir source code for stale outputs.
It can now do everything that `thrift.generate` could do, so we can
retire the latter.
This appears to be case-sensitive, and I wasn't noticing because the
macOS's file system isn't.
Also, remove the Apache License batch from the README because it doesn't
render that well as part of the generated documentation. We may want to
remove the other badges later too if we continue to use the README as a
key part of our Hex-published docs.
We still have a copy under test/support/src/ that's used by our
integration tests, but we otherwise no longer have any need to ship a
copy of Apache Thrift Erlang runtime.
Define :test-specific (instead of :prod-specific) lists of build paths.
This fixes an issue where :dev builds would include test code and things
like `mix docs` would parse and document tests.
Because our benchmarks also use test code (e.g. ParserUtils), that
command is runs in the :test environment.
We previously defined a @types map that was used to generate function
matches for each known type. Because we only use @types for that one
purpose, it's simpler and more readable to just write out the function
heads explicitly.
This change also renames `int_type` to `type_id` for consistency with
the typespec name.
This eliminates the private bool_to_int/1 function and lets us return
constant binary result values directly.
We also strictly match on just the true and false atoms.
There is a nominal performance improvement, but nothing significant.
We were previously generating private copies of the "skip" functions in
each generated struct module. These functions are generic and have been
moved to the top-level Binary protocol module instead. The reduces the
size of the generated modules by a nice amount.
We only skip unrecognized fields so this code shouldn't be called very
often. In practice, however, we can't predict how often this case will
arise, so the performance of these function is important. Fortunately,
this change doesn't introduce a measurable performance cost.
Lastly, this change adds Binary module documentation and some initial
typespecs.
The changes to ParserUtils were fumbled and broke BinaryProtocolBenchmark,
which is the more valuable benchmark. UnionSerializationBenchmark was used to
check the performance impact of a particular commit and isn't really worth
maintaining.
* Behaviour module generation
For the server side, I imagine that the user would specify a handler
module and pass it into the service. Then it would be called with the
appropriate arguments.
I thought it might be nice to have a behaviour for these modules that
users could be implement.
Behaviours here are fully typed with the correct success types.
* Improve iolist optimization
The new function `optimize_iolist` combines the old `merge_binaries` and
`simplify_iolist` functions. It also improves on them slightly, for instance by
terminating iolists with a binary instead of the empty list, and by more
consistently combining adjacent binaries.
* Document iolist optimization steps
It was producing a redundant case statement.
case foo do
nil -> <<>>
_ ->
[<<2, id::size(16)>>, case foo do
nil -> <<0>>
false -> <<0>>
_ -> <<1>>
end]
end
The new output is simpler, both in the number of case statements and in the
structure of the iolist returned.
case foo do
nil -> <<>>
false -> <<2, id::size(16), 0>>
_ -> <<2, id::size(16), 1>>
end
* More robust handling of void return types
The erlang server replies to void responses with <<12, 0, 0, 0, 0>>
which is an empty struct and the stop byte from the respone
struct. Other implementations just reply with the stop byte from the
response struct. We can now parse both.
I also fixed a bug that would occur if the sequence ids or messages
would mismatch. I added tests for all cases.
* Formatting is more consistent