Prototype Wrapup #21

Last week I made 5 prototypes, and this week I made 7. I'm pretty happy about that, but I'm aware that, as previously, the progress is easy to lose if I don't maintain the conditions that led to it. I'm still feeling good about prototype size, but I haven't put that much effort into making and releasing small projects which I think is key to keeping this working. Still, I remain cautiously optimistic.


This was part 3 of CouchDB scheduling (parts 1 and 2 were last week), and it actually works! I used it to write First class the day before, which was a good feeling. It is somewhat damning of Rust that it took over three hours to make a fairly simple web tool, whereas the same thing would have taken me at most an hour in Javascript, Ruby, Python, or really any popular web development language. I think the mismatch between Rust's focus on type safety and the web's total ignorance of it is partly responsible, but I also think there's a lack of library maturity that should right itself as the ecosystem expands.


In order to actually run the Couch scheduler, I needed to give it permission to access my server. I didn't want to use my regular account, so I made something to generate random user id/passwords the same way Cloudant does. Here again I ran into some substantial issues with Rust's web stack. The JSON encoder can't encode structs that contain a "type" field, because that's a reserved word. So I just generated the string myself. I hear a better JSON encoder is coming, but depends on unstable Rust because of some compiler feature etc etc.


Since my prototypes had picked up recently, I thought it would be nice to track them on my stats page. This turned out to be fairly complicated because I needed to recursively read out files and directories. I just threw more and more Promises at it until it worked, and although the result is fairly gross it worked well. I even got it to guess the project language based on (non-gitignored) file extensions.


To make a ringtone loop in Android you need to make it an Ogg file and set some special Ogg metadata. I thought it'd be interesting to write something to do this. In the end it didn't work very well, because ever library that deals with Ogg metadata is either awful or incomplete. I very nearly used inline C++ in Rust before I decided I wasn't desperate enough. In the end I went with incomplete over awful and made something that sets a different metadata field.


As part of my Unix explanation post I spent a bit of time reading back through old Unix history. A hidden gem that I hadn't heard about was the face server, which would store and retrieve "ikons": small visual representations of people's faces. I thought it'd be cool to reproduce the look of these faces using Floyd-Steinberg dithering. My first attempt used Rust's image library, but I found myself fighting against its pixel representation too much to get anything to work.


I had been meaning to set up my Ubuntu/Android side-by-side system again on my tablet. I'd previously wiped the tablet it was on and, since this was the third time I'd needed to write the bind-mount/chroot script that gets the whole thing running, I figured I'd count it as my prototype this time and commit the sucker.


Part 2 of Floyd-Steinberg. This time I decided to avoid the clever typed representation used by the image library and just work on the raw pixels. This was much easier, though I ended up doing a fair bit of fiddling around with number types; the pixel data uses unsigned 8-bit numbers, but to calculate the accumulated error I needed signed numbers. To top it off, the numbers have to be multiplied by a fraction, so in the end I used signed 32-bit integers and did integer multiplication and division (the other option was to use floating point numbers). I'd forgotten how tricky math is in languages with actual number types.