ryanmcgrath / cacao

Rust bindings for AppKit (macOS) and UIKit (iOS/tvOS). Experimental, but working!
MIT License
1.79k stars 65 forks source link

Story for unowned pointers in collections #99

Open agg23 opened 11 months ago

agg23 commented 11 months ago

Both of the collection types (NSArray and NSMutableDictionary) only accept owned pointers to elements. This makes sense, but there are many types that are always shared (NSURL, NSImage, etc), which means we cannot store these elements in any collections. This prevents using some APIs and just generally is a bit weird.

Why are those types always unowned, and what would need to happen in order to properly add them to a collection without leaking?

ryanmcgrath commented 11 months ago

Can you provide a situation you're running into where this is causing friction? Truth be told, I've long considered NSArray and NSMutableDictionary to be more internal in nature and don't expect that one would reach for them for this kind of thing. I'm open to changing my mind though.

NSURL could be redesigned at this point, as some of the logic in and around that stems from a super early implementation that was mostly focused on getting file pickers working.

agg23 commented 11 months ago

Take duplicateURLs:completionHandler:. It's first argument is an array of URLs (not constructible) and it returns (via completion handler) a dictionary <NSURL, NSURL> (which is also not constructible/~kind of readable).

There are definitely more APIs of this type that are currently out of reach.

ryanmcgrath commented 11 months ago

Ah, I see. So this is where the thought process differs. I always envisioned that cacao would have something akin to:

/// pseudocode~
pub struct Workspace(...);

impl Workspace {
    pub fn duplicate_urls<U, F>(urls: Vec<U>, completion: F) { }
}

Aka the Cocoa-ness would be massaged away with an actual Rust layer.

Now with that said, this isn't the first time people have found this annoying, so I don't mind fixing up the types in the foundation module to be more friendly for use outside of cacao so that we can enable these kinds of scenarios. It probably makes sense to combine #100 with this issue and just formulate a revamped approach to it all.

I don't have time to do it myself at the moment, but I'm happy to treat this issue as a working issue/collab space for it.

agg23 commented 11 months ago

Actually I agree with you completely. This came up because I started to build out the duplicate_urls implementation and found out that there weren't existing primitives for me. I suppose I could figure out how the shared ref counts are supposed to work and manually handle it in the method, but it would be much nicer if the collections themselves supported it :P

I will (probably) do the work; I'm just unsure what needs to happen because the specifics of how memory is being managed in this bridge is not apparent to me.

EDIT: Oh, and I don't think there's a good pattern for returning NSURLs currently. They wrap more information than just a string or PathBuf, so I think NSURL has to be returned to the user directly (though maybe it could be a different type)

ryanmcgrath commented 11 months ago

Hmmm, well let's maybe start with NSURL and devise a better setup for that. It's used in less areas comparatively but should have a decent combination of scenarios to test against.

I'm wondering if the current Id and ShareId types make this more confusing to work through than they need to. I've got a few ideas rolling around in my head that I'd need to find time to mess around with, but I think we can figure something out. Something like std::borrow::Cow but for ObjC types.

Actually... @madsmtm your work over in objc2 - does it touch on Id and ShareId? It's been a bit since I looked but I get the feeling it does... would love any input you have as well if you're down to give it. Maybe there's some overlap that'd make sense for me to buckle down and finish #30. :)

madsmtm commented 11 months ago

There's a lot of work done on this in objc2, see https://github.com/madsmtm/objc2/issues/265 and https://github.com/madsmtm/objc2/pull/419, thanks for pinging me!

I'm still working on more "user-level" documentation on this (stashed away somewhere locally), but the gist is to realize that mutability is (almost [1]) always something tied to the class, not to the usage site. So e.g. NSMutableArray<NSString> is always mutable, and it's elements are always immutable, there is no other choice. ShareId is gone, and Id just picks the right configuration depending on the type.

[1]: Technically you could choose to use a shared mutability approach on e.g. NSMutableString, if you eschewed thread safety, the ability to safely access -UTF8String and iteration - but this was deemed out of scope for now at least, though my approach hasn't seen enough use (yet) to know if the use case is there.

ryanmcgrath commented 11 months ago

Interesting... I do like that approach actually.

I think it probably makes sense to go down the rabbit hole of getting the ObjC2 stuff merged and sorted before doing too much else (at this level of things) since it might be rough if we bake in a ton of assumptions now or end up redoing the work you've done elsewhere.

madsmtm commented 11 months ago

Agreed.

A quick status update on that, I'm slowly getting closer to something where I feel it is stable enough that people can start depending on it. I expect it to be ready at the end of the next month, though that very much depends on the amount of free time I get.