chris-zen / coremidi

CoreMIDI library for Rust
https://chris-zen.github.io/coremidi/coremidi/
MIT License
75 stars 20 forks source link

Cloning Destination/Source? #13

Closed Boddlnagg closed 5 years ago

Boddlnagg commented 5 years ago

I was finally able to spend some time porting my latest midir changes to macOS, but ran into a problem. The goal is to be able to have a input/output port identifier that is not just an index, in the hope that they would be more stable than a plain index (imagine you have a list of devices, select index 2, then device 1 is plugged out before you establish the connection; so you end up with what was originally index 3 or an out-of-range index). I tried to solve this by storing a Destination or Source object directly, instead of an index. However, my connection API takes Destination by reference, not by value, but I need to store it then to use it for sending. Long story short: it would be handy if I could just clone() the Destination, but that's currently not possible. Since technically a Destination seems to just wrap an integer, I wondered if it would be possible to change this. But I'm not very familiar with the ObjC object model ...

chris-zen commented 5 years ago

@Boddlnagg that integer is an opaque handler to a CoreMIDI resource, if we clone it, then, there would be two owners for the same object, which violates the rules from the borrow checker.

Could you use an Arc<Destination> ?

I think I am doing something similar here:

The alternative would be to use certain features from the CoreMIDI API to retrieve the object unique id, and use it to create a new Destination instance (but this is not fully supported by the rust coremidi lib yet, although you could add the exports yourself).

Boddlnagg commented 5 years ago

Yes, looking at the definition of Destination, cloning would need to clone all the way down to the underlying Object. And I thought it might be possible, because there's no Drop implementation. So technically the ownership semantics is not encoded in the type (this is somewhat related to #8), but I do understand that this would be a little un-Rust-y. So it's totally okay if you don't want to go that route.

However, thank you for the hint towards Arc<Destination>, I think that should actually work, and if it doesn't, I will use MIDIObjectFindByUniqueID (I can add the export myself, but it would still be nice if you could add something like Destination::from_unique_id, although I don't know whether that would need to be unsafe because you don't know from a unique ID if it actually refers to the right kind of object, right?).

chris-zen commented 5 years ago

Please try Arc<Destination> and if it doesn't work for you, we can talk about Destination::from_unique_id. This was in my mind before, but not as a priority thing. About the unique id not existing anymore I guess this shouldn't be a problem as the factory method could return a Result.

Boddlnagg commented 5 years ago

I was finally able to work on this again, and it turns out that Arc<Destination> works just fine 👍