3 ms·
Whenever someone writes bad things™ about some language, one of the language's fanboys shows up and starts nitpicking! Yes, now is the time! > Another bad part
by barosl 11y ago
Whenever someone writes bad things™ about some language, one of the language's fanboys shows up and starts nitpicking! Yes, now is the time!
> Another bad part is Rust’s JSON handling. It badly needs macros which make things easier.
Actually this is not the end of the world. As you mentioned, Rust's JSON library supports `ToJson` for primitive types, but also provides compile-time code generation for arbitrary `struct`s. Quoting the code from my project:[1]
#[derive(RustcDecodable, RustcEncodable)]
struct Msg {
cmd: String,
id: i32,
x: Option<i32>,
y: Option<i32>,
speed: Option<i32>,
}
What the mystical `#[derive]` thing does is to direct the compiler to create the boilerplate for converting the `struct` to/from a string automatically. So, now you can do this:
// Decoding a JSON string
let text = r#"{"cmd": "move", "x": 5, "y": 10, "speed": 200}"#;
let decoded: Msg = json::decode(text);
// Encoding a Msg object to JSON
let msg = Msg { cmd: "new", x: 10, y: 20 };
let encoded = json::encode(msg);
The `Msg` struct is full of `Option`s because my project allowed many fields to be missing, but if the JSON messages in your protocol are in fairly similar format, you can eliminate most of them.
One more benefit of this approach is that it type checks. If the JSON you received is missing some fields that are not defined as `Option`, the decoding process produces an error! So you can be certain that you're handling a valid JSON after the decoding stage. This is analogous to schemaless vs. schema-enforced database design.
> Compared to many static languages, the handlers look tidy. Compared to dynamic languages, they’re terrible.
This is the property of the Iron framework, not of the Rust language itself! Another web framework for Rust, namely Nickel.rs[2], provides much simpler APIs.
I believe the author of Iron is trying to establish essential things first, and build more "user friendly" APIs on top of them. (FWIW, the Rust project itself follows the similar strategy.)
[1] https://github.com/barosl/pgr21-online-server/blob/master/src/server.rs https://github.com/barosl/pgr21-online-server/blob/master/sr...
[2] http://nickel.rs/ http://nickel.rs/
- tomjakubowski 11y ago> Actually this is not the end of the world. As you mentioned, Rust's JSON library supports `ToJson` for primitive types, but also provides compile-time code generation for arbitrary `struct`s. Quoting the code from my project:[1] Pardon my self-promotion: if you just need some one-off JSON and are willing to use the nightly compiler, I wrote a compiler plugin that expands JSON-like literals into an expression that expands to the tedious way of building up a JSON object. https://github.com/tomjakubowski/json_macros https://github.com/tomjakubowski/json_macros I find it's super handy for testing libraries or applications that emit JSON meant to go across some well-specified protocol. Some day I'll get around to expanding the library to support pattern matching with JSON literals as well (pull requests very welcome!).
- wtetzner 11y agoI haven't actually gotten a chance to use Rust yet, but would something like this work? #[derive(RustcDecodable, RustcEncodable)] enum Msg { Basic { cmd: String, id: i32 }, Positioned { cmd: String, id: i32, x: i32, y: i32 }, Speed { cmd: String, id: i32, speed: i32 }, Full { cmd: String, id: i32, x: i32, y: i32, speed: i32 } } That would allow you to prevent weird cases like x being provided but y not being provided.
- drbawb 11y agoYup, you can encode enums just fine. ADTs get encoded with an explicit `variant` tag at the front, and then an array of field values. For e.g: { "variant": "Basic", fields: ["cmd-value", 42] } { "variant": "Positioned", fields: ["cmd-value", 42, 0, 0] } //etc ...