Glossing over many details, I have something if this approximate shape:
// Similar in principle to FileDescriptorWatcher::WatchReadable
SignalHandle RegisterStreamHandler(base::RepeatingClosure callback);
void StartStream(base::OnceClosure callback) {
auto handle = std::make_unique<SignalHandle>();
auto* handle_ptr = handle.get();
*handle_ptr = RegisterStreamHandler(base::BindRepeating(&OnStreamSignal, /* pass handle */, /* pass callback */));
CallCreateStreamDBusMethod();
}
void OnStreamSignal(base::OnceCallback<std::unique_ptr<SignalHandle> handle, base::expected<void, Error>> callback) {
handle.reset(); // This callback guaranteed never to be called again.
std::move(callback).Run();
}
The question is what to do for /* pass handle */ and /* pass callback */
I can't do base::BindRepeating(&OnStreamSignal, std::move(handle), std::move(callback)) because BindRepeating won't accept move-only types by default, since those can only be passed once. The previous way to handle this would be to write base::BindRepeating(&OnStreamSignal, base::Passed(&handle), base::Passed(&callback)), where Passed means "I promise this RepeatingCallback is only actually called once. Please pass by move and CHECK if I'm wrong." This seems to be what I want, but is deprecated. The alternative I found was to do base::BindRepeating(&OnStreamSignal, base::OwnedRef(std::move(handle)), base::OwnedRef(std::move(callback))), which moves the values into the bind state and passes them by reference to OnStreamSignal, which can then modify / move from them through the reference. This works and isn't deprecated, but it seems strictly worse than Passed here: the intent isn't as explicit, and there's no CHECK to catch if the callback is accidentally invoked twice. (Though the second call to Run() would still CHECK in this case.)
I was wondering if there was a better third option that I am overlooking.