I needed something like this a few months ago. I use my MacBook to run my (musical) keyboard rig for live performances, and use low-latency wireless headphones for monitoring. The headphones have a transmitter dongle that plugs into my laptop, and the dongle sends a "play/pause" command if I press a button on my headphones...causing Music to launch and begin playing audio out of my default output device. It doesn't even care whether my headphone transmitter is selected as the default output device; in a complex multi-device setup, I can press a button on my headphones and it will happily play audio out of some other device.
This is problematic because if I were to accidentally hit the button in the middle of a set, and it decides to default to whatever interface is connected to the P.A. system, then now I've just started blasting some random song at full volume to everyone in the venue.
(It's not an immediate problem for me anymore because I've reworked my hardware setup such that the dongle connects through my audio interface rather than directly to my laptop, meaning my laptop no longer receives "play/pause" commands from it. There were additional reasons for this rework, but preventing this misbehavior was absolutely part of the consideration.)
It's absurd that a premium device marketed to creative professionals has unconfigurable behavior like this which is so unacceptable for a live show.
That'd be a terrifying setup for me as a live player! I'm curious where you found low latency wireless headphones though.
Have a look at Loopback - very mature app now. I use this for doing live and studio routing, you set a live profile so that only your soft synths actually get an output and Music (and FaceTime, system, whatever) get sent to the musical equivalent of /dev/null. So an accidental press of "Play" has no effect (beyond perhaps catastrophic stuttering as Music.app opens.)
My laptop is disconnected at the moment so it's full of "missing device" notifications but this screenshot[1] will give you an idea. Profiles on the left, apps in the next column, routing to mixer channels (I have a multichannel interface) next and then "monitor devices" which can be multiplexed.
Loopback looks nice, but I prefer to keep the routing entirely within my DAW (or my interface where possible) to keep latency to a minimum, particularly since I'm already using wireless headphones that add 10ms latency.
Another mitigation I now have is to use an aggregate device that has BlackHole on the first two channels rather than the main outputs. That way, if I accidentally start playing audio, it gets harmlessly sent to the void; and it also means I can easily capture and forward it in my DAW if I actually want to play PC audio (for example, listening to a recording during a rehearsal).
"Hi there, I'm ABC, nice to meet you, what's your name"
"...Huh? I'm XYZ. We've met before."
"Oh right...sorry, I promise I remember you! We knew each other from there, and we've worked on this and that together, and etc. etc. etc. I'm just terrible with faces, I'm so sorry!"
It's not "you know things about them without recognizing them"; it's "you don't recognize them at first, it gets awkward, and so you recite facts about them prove that you didn't forget who they were"
My aunt said tells neighbors/acquaintances to just introduce themselves by name every time when they start chatting with her, and reports great success with this — but my entire family is also rather 'take it or leave it' re: social stuff, so the people that don't introduce themselves don't get remembered, which seems perfectly fair.
I recently learned that I have some level of face-blindness (I took the CFMT online and scored 43).
It's something I've had my whole life but only recently realized wasn't "normal". It's not like I can't recognize people at all, but rather that faces aren't very distinctive to me compared to other identifying characteristics (such as hair color/style/length, clothing, skin tone, height, voice, gait, mannerisms, etc.) It takes me a while to learn to distinguish everyone in a group of people (especially people who are similar along all of those attributes), but once I know someone well I will usually recognize them without problems.
The only real issues are when someone changes their appearance (e.g. getting glasses or shaving a beard), or when I run into someone in an unexpected context (like randomly meeting someone I know on the street). A few months ago I ran into my cousin at an event in another city, and didn't recognize her until after 20 or 30 seconds of conversation.
It's also not usually too hard to mask. I realized I have a subconscious habit of never greeting people by name because I'm always afraid of getting it wrong, and it's easy enough to bluff through "oh hi, how are you, good to see you, what have you been up to" pleasantries until I figure out who I'm talking to. The most awkward situations are when I'm unsure whether or not I know someone and have to risk either mistaking a stranger for a friend, or accidentally ignoring/reintroducing myself to an acquaintance. Also, starting a new TV show sucks.
Now that I know it's an actual condition with a name, I'm not sure yet whether it makes things better or worse if I try to explain it to people to excuse my mistakes.
If any other face blind people have useful tips or experiences, I'm all ears :)
If someone talks to you and you're not sure who they are, tell them you're faceblind and ask. It takes some getting used to, but it's worth it.
In my previous company we gave a short introduction when joining, and I included faceblindness. "If I meet you randomly on the street and don't say hello, that's not with malicious intent."
Most people are understanding, though a few are not, but really then it's their problem.
> My only gripe is that a lot of it is feeling a bit kick-starter-y
IMO the term "project goals" is quite misleading for what this actually is. A project goal is a system for one person (or a small group of people) to express that they'd like to work on something and ask for Rust project volunteers to commit ongoing time and effort to supporting them through code review, answering questions, etc. It doesn't mean that the Rust project itself has set the goal, or even necessarily endorsed it.
So it's not quite right to treat it as a formal roadmap for Rust, just a "there are some contributors interested in working on these areas".
> if optional were a general sum type you wouldn't be able to make these optimizations easily without extra information
Rust has these optimizations (called "niche optimizations") for all sum types. If a type has any unused or invalid bit patterns, then those can be used for enum discriminants, e.g.:
- References cannot be null, so the zero value is a niche
- References must be aligned properly for the target type, so a reference to a type with alignment 4 has a niche in the bottom 2 bits
- bool only uses two values of the 256 in a byte, so the other 254 form a niche
There's limitations though, in that you still must be able to create and pass around pointers to values contained within enum, and so the representation of a type cannot change just because it's placed within an enum. So, for example, the following enum is one byte in size:
enum Foo {
A(bool),
B
}
Variant A uses the valid bool values 0 and 1, whereas variant B uses some other bit pattern (maybe 2).
But this enum must be two bytes in size:
enum Foo {
A(bool),
B(bool)
}
...because bool always has bit patterns 0 and 1, so it's not possible for an invalid value for A's fields to hold a valid value for B's fields.
You also can't stuff niches in padding bytes between struct fields, because code that operates on the struct is allowed to clobber the padding.
Yes, the care that Rust goes through to ensure that niches work properly, especially when composing arbitrary types from arbitrary sources, shows why you absolutely don't want to be implementing these optimizations by hand.
Nearly every available filesystem API in Rust's stdlib maps one-to-one with a Unix syscall (see Rust's std::fs module [0] for reference -- for example, the `File` struct is just a wrapper around a file descriptor, and its associated methods are essentially just the syscalls you can perform on file descriptors). The only exceptions are a few helper functions like `read_to_string` or `create_dir_all` that perform slightly higher-level operations.
And, yeah, the Unix syscalls are very prone to mistakes like this. For example, Unix's `rename` syscall takes two paths as arguments; you can't rename a file by handle; and so Rust has a `rename` function that takes two paths rather than an associated function on a `File`. Rust exposes path-based APIs where Unix exposes path-based APIs, and file-handle-based APIs where Unix exposes file-handle-based APIs.
So I agree that Rust's stdilb is somewhat mistake prone; not so much because it's being opinionated and "nudg[ing] the developer towards using neat APIs", but because it's so low-level that it's not offering much "safety" in filesystem access over raw syscalls beyond ensuring that you didn't write a buffer overflow.
> So I agree that Rust's stdilb is somewhat mistake prone; not so much because it's being opinionated and "nudg[ing] the developer towards using neat APIs", but because it's so low-level that it's not offering much "safety" in filesystem access over raw syscalls beyond ensuring that you didn't write a buffer overflow.
`openat()` and the other `*at()` syscalls are also raw syscalls, which Rust's stdlib chose not to expose. While I can understand that this may not be straight forward for a cross-platform API, I have to disagree with your statement that Rust's stdlib is mistake prone because it's so low-level. It's more mistake prone than POSIX (in some aspects) because it is missing a whole family of low-level syscalls.
There are lots of unstable things in Rust that have been unstable for many years, and the intentional segregating of unstable means that it's a nonstarter for most use cases, like libraries. It's unstable because there's significant enough issues that nobody wants to mark it as stable, no matter what those issues are.
As long as it's unstable it's totally fair to say Rust's stdlib does not expose them. You might as well say it's fixed because someone posted a patch on a mailing list somewhere.
There are lots of unstable things in Rust that have been unstable for many years, but this isn't one of them. openat() was added in September, and the next PR in the series implementing unlinkat() and removeat() received a code review three weeks ago and is currently waiting on the author for minor revisions.
> As long as it's unstable it's totally fair to say Rust's stdlib does not expose them. You might as well say it's fixed because someone posted a patch on a mailing list somewhere
Agreed. My comment was intended to be read as "it's planned and being worked on", not "it's available".
They're not missing, Rust just ships them (including openat) as part of the first-party libc crate rather than exposing them directly from libstd. You'll find all the other libc syscalls there as well: https://docs.rs/libc/0.2.186/libc/ . I agree that Rust's stdlib could use some higher-level helper functions to help head off TOCTOU, but it's not as simple as just exposing `openat`, which, in addition to being platform-specific as you say, is also error-prone in its own right.
The parent was asking for access to the C syscall, and C syscalls are unsafe, including in C. You can wrap that syscall in a safe interface if you like, and many have. And to reiterate, I'm all for supporting this pattern in Rust's stdlib itself. But openat itself is a questionable API (I have not yet seen anyone mention that openat2 exists), and if Rust wanted to provide this, it would want to design something distinct.
> Why can I easily use "*at" functions from Python's stdlib, but not Rust's?
I'm not sure you can. The supported pattern appears to involve passing the optional `opener` parameter to `os.open`, but while the example of this shown in the official documentation works on Linux, I just tried it on Windows and it throws a PermissionError exception because AFAIK you can't open directories on Windows.
I took parent's message to be asking why the standard library fs primitives don't use `at` functions under the hood, not that they wanted the `at` functions directly exposed.
> why the standard library fs primitives don't use `at` functions under the hood
In this case it wouldn't seem to make sense to use `at` functions to back the standard file opening interface that Rust presents, because it requires different parameters, so a different API would need to be designed. Someone above mentioned that such an API is being considered for inclusion in libstd in this issue: https://github.com/rust-lang/rust/issues/120426
You can but you have to go through the lower level API: NtCreateFile can open a directory, and you can pass in a RootDirectory handle to following calls to make them handle-relative.
The correct comparison is to rustix, not libc, and rustix is not first-party. And even then the rustix API does not encapsulate the operations into structs the same way std::fs and std::io do.
The correct comparison to someone asking for first-party access to a C syscall is to the first-party crate that provides direct bindings to C syscalls. If you're willing to go further afield to third-party crates, you might as well skip rustix's "POSIX-ish" APIs (to quote their documentation) and go directly to the openat crate, which provides a Rust-style API.
If I have to use unsafe just to open a file, I might as well use C. While Rustix is a happy middle that is usually enough and more popular than the open at crate, libc is in the same family as the "*-sys" crate and, generally speaking, it is not intended for direct use outside other FFI crates.
I agree it is an exaggeration in that of course you could write a wrapper. The point was that if everyone had to write their own FFI wrappers, Rust wouldn't go far and openat is not an exception.
There is code available at the right level of abstraction (the rustix or openat crates), and while it's not managed by the Rust team, uutils already have many third party dependencies. Bringing up libc just because it's first party, instead, is comparing apple to oranges.
> For example, Unix's `rename` syscall takes two paths as arguments; you can't rename a file by handle
And then there’s renameat(2) which takes two dirfd… and two paths from there, which mostly has all the same issues rename(2) does (and does not even take flags so even O_NOFOLLOW is not available).
I’m not sure what you’d need to make a safe renameat(), maybe a triplet of (dirfd, filefd, name[1]) from the source, (dirfd, name) from the target, and some sort of flag to indicate whether it is allowed to create, overwrite, or both.
How about fd of the file you wanna rename, dirfd of the directory you want to open it in, and name of the new file? You could then represent a "rename within the same directory" as: dfd = opendir(...); fd = openat(dfd, "a"); rename2(fd, dfd, "b");
I can't think of a case this API doesn't cover, but maybe there is one.
The file may have been renamed or deleted since the fd was opened, and it might have been legitimate and on purpose, but there’s no way to tell what trying to resolve the fd back to a path will give you.
And you need to do that because nothing precludes having multiple entries to the same inode in the same directory, so you need to know specifically what the source direntry is, and a direntry is just a name in the directory file.
> The Oregon Department of Revenue administers tax programs for the Tri-County Metropolitan Transportation District (TriMet). Nearly every employer who pays wages for services performed in this district must pay transit payroll tax.
> The transit tax is imposed directly on the employer. The tax is figured only on the amount of gross payroll for services performed within the TriMet Transit District. This includes traveling sales representatives and employees working from home.
I know quite a few people who've had SNESes with failing ICs in recent years (mainly PPU and APU chips). That's pretty annoying because the only way to get replacement parts is from a donor console.
> you built what was basically a raspberry pi with a microcontroller by hand, and you had to use the dumb speaker and controller to make your own music firmware to produce notes
This sounds like they were most likely bit banging square waves into a speaker directly via a GPIO on a microcontroller (or maybe using a PWM output if they were fancy about it). In that case, the audio frequency will be derived directly from the microcontroller's clock speed, and the tolerance of an internal oscillator on a microcontroller can be as bad as 10%.
This is problematic because if I were to accidentally hit the button in the middle of a set, and it decides to default to whatever interface is connected to the P.A. system, then now I've just started blasting some random song at full volume to everyone in the venue.
(It's not an immediate problem for me anymore because I've reworked my hardware setup such that the dongle connects through my audio interface rather than directly to my laptop, meaning my laptop no longer receives "play/pause" commands from it. There were additional reasons for this rework, but preventing this misbehavior was absolutely part of the consideration.)
It's absurd that a premium device marketed to creative professionals has unconfigurable behavior like this which is so unacceptable for a live show.
reply