I'll also add that I've actually been really impressed with how much attention Rust takes to not break stable packages. Between crater[1] and how aggressively they've cut point releases to fix any issues that (rarely) happen to slip by.
I've been using bindgen for ages on stable and just grabbed the latest version on an empty project and it still works for me.
You shouldn't be using rustfmt-nightly at this point either; install the rustfmt-preview component through rustup. It works on stable!
So yeah looks like I'm tethered to the nightly toolchain after all. :/
Before I ended up going down the TryFrom rabbit hole I ran into two issues with bindgen:
1.) Bindgen segfaults with the ancient LLVM on OSX 10.9. Issue #1006. Solution: use LLVM >= 5 binaries from the LLVM site.
2.) Stable (deprecated) rustfmt causes bindgen to segfault. Solution: cargo install -f rustfmt-nightly. It could be as simple as "stable rustfmt requires --force to run because it's been deprecated", but more helpful error messages would be a great thing here.
(TryFrom is being stabilized fairly soon, it got caught up in some silly stuff but is basically good to go)
Custom { kind: Other, error: StringError("Internal rustfmt error") }
I get the same results if I call the bindgen executable or have build.rs call the bindgen API. I've stuck with having build.rs call the bindgen executable because if I use the bindgen API, compilation is SLOW.
rustup component add rustfmt-preview $ cargo uninstall rustfmt && rustup component add rustfmt-preview
Removing /home/alex/.cargo/bin/cargo-fmt
Removing /home/alex/.cargo/bin/rustfmt
info: downloading component 'rustfmt-preview'
info: installing component 'rustfmt-preview'
$ bindgen bindings.h -- -I/usr/local/include/libr > /dev/null
Custom { kind: Other, error: StringError("Cannot find binary path") }
$ rustc --version
rustc 1.28.0-nightly (29f48ccf3 2018-06-03)
$ cat bindings.h
#include <r_lib.h>
#include <r_asm.h>
#include <r_reg.h>
#include <r_anal.h>
#include <r_bin.h>Also, while I recognize it's a third party project, the hyper API keeps changing faster than I can adapt my code. If you are aware of a more stable HTTP server, ideally one that has proper TLS support and support for unix domain sockets, I would be very interested.
EDIT: on the other hand, after working with rust daily for ~1.5 years, I have only run into one compiler bug and had zero actual bugs in my application due to language/compiler updates so far. There have been a few occasions were essential features were missing from the standard library/language though and several times were we had to backport some code to an older, stable rust version that we're one (when a developer had mistakenly tested their code locally with a newer version).
The highest up on my wish list would be that - as I understand it - you can not currently exit the process cleanly (EDIT: early) with a non-zero exit code in stable rust. That makes it pretty hard to implement good command line utilities. Happy to be corrected if I am wrong on this one though.
EDIT: to expand on this: a suggested workaround is to only call std::process::exit at the very end of the main function. But consider stuff like "env_logger::init". What about that? Ok, that doesn't use Drop and if it did you could put it into it's own scope I guess - so there are workarounds - but it in my opinion that gets pretty ugly. Comparing to c++, std::process::exit or panic! is like abort(), but what I want is a "return 1" from main.
panic! does return a non-zero exit code, but isn't really designed for good end-user output.
That most of my programs have some global (i.e. "for the runtime of the program") stuff that is setup at the beginning of main. And that some of that might want to Drop when the program exits, for example to delete a temporary directory. Now, if I want to return a non-zero exit code I can not do so while still getting all this global stuff destructed correctly (or use a workaround like having a wrapper-main).
> Calling `std::process:exit(1)` at the end of main is identical to `return 1`.
The thing is that it is actually not the same with respect to destructors -- the documentation explicitly calls that out. See also the C++ comparison in my other comment.
fn main() {
if let Err(e) = real_main() {
let status = status_from_error(e);
// print the error message, or whatever
std::process:exit(status);
}
}
fn real_main() -> Result<(), TopErrorType> {
// ...
}
And simply returning Result<_, SomethingConvertibleToTopErrorType> from functions called by real_main that might need to exit the program.I believe that in a recent stable version of Rust, you can make this even simpler and have `main()` return a Result directly.
edit: not quite as simple as I described, but maybe more powerful because of the Termination trait: https://github.com/rust-lang/rfcs/blob/master/text/1937-ques... see: https://github.com/rust-lang/rfcs/blob/master/text/1937-ques...
fn main() -> Result<(), io::Error> {
let mut stdin = io::stdin();
let mut raw_stdout = io::stdout();
let mut stdout = raw_stdout.lock();
for line in stdin.lock().lines() {
stdout.write(line?.trim().as_bytes())?;
stdout.write(b"\n")?;
}
stdout.flush()
}EDIT: I assume you mean RFC1937? Looks like it isn't implemented yet, so we will probably have to at least another year before we can get it in stable rust. But yes - without having read the entire RFC - I think that was what I was looking for!
The rest of it makes it even better; it's a bit limited in ways right now.
You're writing a server with hyper directly? Is there a particular reason you're not using one of the frameworks written on top? I may have some advice there, depending.
I do need a lot of pretty specific other features though. Unix domain sockets are currently a must (luckily that works with hyperlocal).
The code runs on a pretty resource constrained system so I like the low level of control that hyper gives me of the request/response chunking behaviour (I can not afford to buffer large requests in memory and what exactly I do with the body payload differs between API calls).
One thing that would be lovely is proper TLS/HTTPS support. I need support for x509 client certificates and I need to get access to the full client certificate data, ideally including the full chain that signed it from the request handler. I have to admit that I currently run a hacked together nginx in front of my app and put this stuff into HTTP headers (hence the unix domain sockets) because I could not get it to work with rust ecosystem libraries.
EDIT: The TLS stuff is also true for the HTTP client case. Currently using the libcurl rust binding because it's the only thing that implements all the features I need (--cainfo, --cert, --key, --resolv). Also it needs to run on OpenSSL or something else that supports x509v3 extended attributes (subtree constraints).
I don't know if rustls supports your use-case for TLS, but you may want to check it out.
Thanks again. It's really invaluable to hear about these kinds of things.
You don't need any fancy features to do this. Every single one of my Rust CLI programs has done this on stable Rust for years. All you need to do is bubble your errors up to main.
If you have destructors that you want to run, then put those in a function that isn't main.
EDIT: I should have said explicitly in my initial comment that I knew about std::process::exit and panic!, but did not consider them to be a clean solution for exiting the program under normal circumstance -- more of an abort() mechanism.
The whole point of Erlang and Elixir is robustness in the face of high concurrency. All other design choices (eg functional programming, immutable data), follow from that goal. Core is that if one green thread ("process" in Erl/Ex lingo) crashes for whatever reason, the rest keep on running. Interop with native code is the sole exception here, which makes interop very scary. If a C function that's called into from Erl/Ex crashes, the entire program crashes. Boom, gone. Sure that holds for most other languages too, but Erlang/Elixir people get extra nervous because they're more accustomed to thinking about error scenarios and because they don't always have the same seven restart/recover layers outside the VM process that good devopsers wrap eg Node processes with because hey, no need, we have Erlang, we never crash.
As a result, the idea of a technology that allows writing native code that has a tremendously small likelihood of crashing is very appealing. Until recently, no such technology was available but Rust changed that. Rust allows writing native functions that can be called from Erlang/Elixir with much fewer worries than C/C++ native extensions ever did, because of all the safety guarantees provided by the compiler. This is a big thing and I hope that as the interop story improves, it means that Erlang/Elixir will in practice become much faster because more libraries will be rewritten in native code.
It's not just crashing either, it's taking a long time to execute a given function in the native code - that can also cause problems for the Erlang system running it.
Oh, this is cute statement xD No, ports also carry the same risk as NIFs if you use port drivers, because it's still the same way of running the code, just with different API. You need ports backed by external process to be isolated from the crash, though there's still the problem of such ports eagerly reading all the available data without any backpressure whatsoever, so your BEAM can trigger OOM killer. This is much easier to avoid, fortunately.
No such technology was available, barring maybe Ada or some other languages.
We’ve also made some small changes that in theory can break code but weren’t observed in the wild. The tolerance for that has dropped over time, of course.