Writing my network protocol in Rust
ayende.com
ayende.com
I think Rust development is going to continue to be less focused on big features and more on small iterative improvements. Rust doesn't need silver bullets; it needs lots of lead bullets.
That said, even with all the nagging faults I find that rust development feels more productive than lots of other languages. A large part of that is the tools, sure, but the other major part is the rust community itself.
Still, when having to do things with JS/Python/C++ I’ve wasted many afternoons down the rabbit hole of trying to glean information from Github Issues, stackoverflow answers, Twitter threads and obscure forum threads — usually to find the problem (and fix) I ran into was so trivial it could have been a single line in an error message. (I feel like a lot of JS tools - particularly Webpack, Jest and Babel - have regressed a fair bit recently in this regard. Python just fails silently (or bizarrely) too often and C/C++ compiler error messages are often less readable than the code itself.)
OTOH the contrast to Javascript is pretty stark. As much as I've got plenty of complaints about the language itself, the community really a detriment. Things like Electron and Node actively shun cross-platform compatibility. Tools like webpack tend to attract cargo cultists. It seems there's a lot of wizardry and hair pulling involved anytime I touch JS.
C/C++ though has gotten a lot better with the advent of clang.
Also, over time, as I gained experience with the language, I found myself taking repeating code fragments and creating higher-order macros - both for Diesel.rs stuff. That reduces the repetitive code and errors. Macros in Rust are a great way to reduce a complexity where the functions can’t.
Source: during the past 1.5 years period in a couple of 2-3 month spurts I rewrote a C#/ASP.Net homegrown NMS dealing with provisioning and operation of a large-ish (about 15K people) event network consisting ~500 devices, all in all probably about 50KLoC of Rust code doing FTP/TFTP/SNMP and ssh/telnet interactions and this year the frontend.
Now (over the new year holidays) I am using the learnings from that to build a stateless-at-server ASP.Net-like framework using Iron, Diesel.rs, rust-Mustache and iron-sessionstorage on the server side and HyperHTML on the client side. I hope to open source it (the framework) at some point, when I get it to Rails-like ease of use.
Some additional impressions: I feel I am about half as productive with Rust initially compared to C# for smaller changes, but the final result is much more solid, requiring practically zero debugging. And as I build the abstractions later it becomes easier and easier.
Also it is a joy to get a consistent and easily traceable memory footprint compared to mono and about 10x the performance (in debug build) compared to the mono version. And the benchmarks show I have about 5x-7x more if I run it in release mode. So - a very happy Rust user here.
Emphasizing which part of the tuple didn't match up would be a big win, but IMO it should be pulled out and mentioned first. Highlighting could get lost in the noise (moreso without all the ANSI escape codes if you're redirecting output or whatnot).
It needs steel bullets. Lead only oxidizes at high temperatures.
lazy_static! {
static ref msg_break : TwoWaySearcher<'static> = {
TwoWaySearcher::new("\r\n\r\n".as_bytes())
};
}
AFAICT all the code is doing is parsing the input on a double newline (e.g. the equivalent of strstr(input, "\r\n")). And this five-line expression is defining the equivalent of the "\r\n" literal.What is it that requires that mess? I mean, I get that sometimes typesafety requires some loss of concision, but...
The "lazy ref" is part of that macro's syntax. "msg_break" is the name of the static variable. Then, in Rust, all static things must have type annotations. In this case, it's the "TwoWaySearcher<'static>". The "TwoWaySearcher::new("\r\n\r\n".as_bytes())" is the initializer code that's being only called once. The as_bytes function is solely a type casting operation to convert from a str for which the typesystem guarantees that it's utf-8 formatted to a byte slice that just represents arbitrary data.
The question was more about "why"? Again in C the equivalent is literally a string literal. There's really no easier way to express "double newline" in Rust than this thing which requires that the reader parse a "lazy static", a parametrized type, an explicit type conversion and a library utility? Why not?
The code doesn't express 'double newline'. That would be just the "\r\n\r\n".as_bytes()
The code lazily initializes an TwoWaySearcher to parse such double newlines.
If that setup-performance doesn't matter one can use https://crates.io/crates/twoway to write:
twoway::find_bytes(&buffer[to_scan..], b"\r\n\r\n")
at the place where the search happens and skip all the caching effort.I've talked extensively about performance in CoreCLR and how to approach it. Several records talks are found here:
Thanks Ayende for all your content and contributions.