[ my public key: https://keybase.io/lilyball; my proof: https://keybase.io/lilyball/sigs/okmRsMzqujmfu5cZO3uh8L1hmbSarnLcQJTjev7R60c ]
- lilyball parentApple Keychain syncing is end-to-end encrypted, Apple cannot see the contents of your synced keychain.
- In Pattern: Defensively Handle Constructors, it recommends using a nested inner module with a private Seal type. But the Seal type is unnecessary. The nested inner module is all you need, a private field `_private: ()` is only settable from within that inner module, so you don't need the extra private type.
- I haven't used Homebrew in a long time, but if I ever did it would be in the way that you describe (so far I've always found reasonable alternatives for the software I want). What I'm wondering is if this is entirely to support unsigned casks, why does Homebrew not simply resign the software itself at install time with an adhoc signature as though it had just built it?
- I'm fascinated by ASN.1, I don't know why it appeals to me so much but I find working with it oddly fun. I've always wanted to find the time to write an ASN.1 compiler for Rust, because for some reason all of the Rust implementations I've seen end up just either being derive macros on Rust structs (so going the other direction), or even just providing a bunch of ASN.1 types and functions and expecting you to manually chain them together using nom.
- Unlock over SSH terminates the connection after unlocking the data volume, so it doesn't even attempt to start the shell until you reconnect after it's fully booted up.
FWIW you can fix the shell issue by wrapping your shell in a shim that essentially runs wait4path on the nix store before exec'ing your real shell. I set up my environment to install that shim binary directly onto the data volume at a known path so it can be used as my login shell.
- It's not just 5 moves. It's 5 crossing changes (which don't change the number of crossings, they just change the order of the strings in a crossing). Unknotting also involves moving the strings around to add or remove crossings, without performing crossing changes (if you take a loop and twist it into a figure eight, you've moved the strings and created a crossing but you haven't cut the strings and performed a crossing change).
If you look at the preprint paper, the knot it starts with has 14 crossings, but they actually move the strings around to end up with 20 crossings prior to performing the first 2 crossing changes in the unknotting sequence. So the potential space for moves here is actually rather large.
- If you need to hold a lock across an await point, you can switch to an async-aware mutex. Both the futures crate and the tokio crate have implementations of async-aware mutexes. You usually only want this if you're holding it across an await point because they're more expensive than blocking mutexes (the other reason to use this is if you expect the mutex to be held for a significant amount of time, so an async-aware lock will allow other tasks to progress while waiting to take the lock).
- Your argument here is basically just "I already know Markdown". Sure, the Markdown image syntax is similar to its hyperlink syntax, so if you know the hyperlink syntax then the image syntax is easy, but the same argument works for reST but even better, the image syntax is the same as any other directive, so if you know how to write a directive then you know how to write an image.
- It's extremely distracting. I'm not normally one to have issues that require reduced motion, but the asteroids are almost distracting enough on their own, and the fact that it causes my cursor to vanish is a real accessibility issue. I didn't actually realize just how much I use my mouse cursor when reading stuff until now, partly as a fidget, partly as a controllable visual anchor as my eyes scan the page.
- It's worth noting that the percentage of Steam users that are Mac users is not going to be equal to the percentage of gamers who play games on Macs, because not only is Steam not the only distribution channel for games on Mac, it's always been a fairly poor UX there, so bad I don't usually even bother installing it on my Macs anymore. Steam sees me as a Linux user as I have a Steam Deck, but I spend more time playing non-Steam games on my Mac than I do using that.
Actually, I think the last time I installed Steam on a Mac I did so in a CrossOver Games bottle, so even there Steam would have seen that install as a non-Mac user.
EDIT: Also just because I think it's interesting to note this, Steam Deck accounts for most of Linux's headroom there, if you subtract the SteamOS numbers from the rest of Linux it's at 2.07% instead, which is much closer to Mac.
- Full screen stuff isn't supposed to go behind the notch, unless they opt in to supporting it. By default, fullscreen stuff just gets the notchless 16:10 area under the menubar, and the menubar area goes black, so the notch becomes invisible and nothing is "glaring", it just looks like the top bezel of the screen is larger.
- Good! Wipr was very cheap, so was Wipr 2, if paying a tiny fee every few years for a well-made app that does its job well keeps the developer in business and able to keep maintaining it, then I'm happy to do it.
That said, I'm not actually convinced there will be a Wipr 3, at least not without some significant change to the ecosystem first. Wipr 2 was a complete rewrite of Wipr, there's no reason to expect it will need yet another complete rewrite.
- You're describing a different format entirely then if you're doing generic whitespace trimming without any consideration for the definition of "whitespace". The Git config format explicitly defines ignorable whitespace as spaces and horizontal tabs, and says that these whitespace characters are trimmed from values, which means nothing else gets trimmed from values. If you try to write a parser for this using a regular expression and `\s*` then you'd better look up what `\s` means to your regex engine because it almost certainly includes more than just SP and HT.
I can't think of any features in Rust that will lead someone away from this pattern of error, where this pattern of error is not realizing that round-tripping the serialized output back through the deserializer can change the boundaries of line endings. It's really easy to think "if I have a bunch of single-line strings and I join them with newlines I now have multiline text, and I can split that back up into individual lines and get back what I started with". This is doubly true if you start with a parser that splits on newline characters and then change it after the fact to use BufRead::lines() in response to someone telling you it doesn't work on Windows.
- The "destinations much closer than 500 miles" was explicitly handled in the story, I don't know why that was even in the FAQ except that the asker failed reading comprehension.
> "There are a number of destinations within that radius that we can't reach, either, or reach sporadically, but we can never email farther than this radius."
- I can easily see this bug happening in Rust. At some level you need to transform your data model into text to write out, and to parse incoming text. If you want to parse linewise you might use BufRead::lines(), and then write a parser for those lines. That parser won't touch CRs at all, which means when you do the opposite and write the code that serializes your data model back to lines, it's easy to forget that you need to avoid having a trailing CR, since CR appears nowhere else in your code.
- Darwin has its own set of futex primitives that it only fairly recently made public API, see https://developer.apple.com/documentation/os/os_sync_wait_on.... But there is a problem with this approach on Darwin, which is that the Darwin kernel has a Quality of Service thread priority implementation that differs from other kernels such that mutexes implemented with spinlocks or with primitives like this are vulnerable to priority inversion. Priority inversion is of course possible on other platforms, but other kernels typically guarantee even low-priority threads always eventually get serviced, whereas on Darwin a low-QoS thread will only get serviced if there are no higher-QoS threads that want to run.
For this reason, on Darwin if you want a mutex of the sort this article describes, you'll typically want to reach for os_unfair_lock, as that will donate the priority of the waiting threads to the thread that holds the lock, thus avoiding the priority inversion issue.
- Ah right, std::io::Read, I didn't think about that. And so it needs to explicitly track the initialized portion because otherwise calling .ensure_init() every time you want to do a read becomes expensive, that makes sense. And presumably this is also why the Buffer trait from this article cannot ever replace BorrowedBuf, because Buffer is not compatible with the Read trait without explicitly initializing the buffer every time (though I suppose it could still be added on top of BorrowedBuf if you add a new method init_len() that returns the length of the already-known-to-be-initialized prefix of parts_mut()).
EDIT: adding init_len() isn't good enough, we'd need an ensure_init() method too that returns a &mut [u8], and with those we could impl Buffer for BorrowedCursor, but if Read::read_buf() took this modified Buffer trait the default impl would be very inefficient when using a &mut [MaybeUninit<u8>] and that becomes a performance footgun.
- What is the reason for explicitly tracking the initialized-but-unfilled portion? AIUI there's no harm in treating initialized bytes as uninitialized since you're working with u8, so what do you actually gain by knowing the initialized portion? I mean, at an API level you gain the ability to return a &mut [u8] for the initialized portion, but presumably anyone actually trying to write to this buffer either wants to copy in from a &[u8] or write to a &mut [MaybeUninit<u8>].
- Note that if you have a `&mut T` then the memory must already be initialized for T, so writing to that pointer doesn't initialize anything new (although as you say it can deinitialize bytes, but that only matters if you use transmute or pointer casting to get access to those padding bytes somehow).