Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Converting a msg_send_id received NSArray to Vec #595

Closed
josephjohnston opened this issue Mar 22, 2024 · 2 comments
Closed

Converting a msg_send_id received NSArray to Vec #595

josephjohnston opened this issue Mar 22, 2024 · 2 comments
Labels
A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates question Further information is requested

Comments

@josephjohnston
Copy link

josephjohnston commented Mar 22, 2024

When I model some Objective-C object type Value I'm confused on the best way to receive an NSArray of these objects and convert toVec<Id<Value>>.

Here I model some fictional Objective-C type Value as

#[derive(Debug)]
#[repr(C)]
pub struct Value(AnyObject);
unsafe impl RefEncode for Value {
    const ENCODING_REF: Encoding = AnyObject::ENCODING_REF;
}
unsafe impl Message for Value {}
impl ::std::ops::Deref for Value {
    type Target = AnyObject;
    #[inline]
    fn deref(&self) -> &AnyObject {
        &self.0
    }
}

Then calling method values with self some instance of struct Value I receive an NSArray of these values

let mut v: Vec<Id<Value>> = Vec::new();
let values: Id<NSArray> = msg_send_id![self, values];
values.iter_retained().map(|x| v.push(x));

The issue is x is of type Id<AnyObject> rather than Id<Value> because I typed values as Id<NSArray>.
I can't type values as Id<NSArray<Value>> because Value doesn't implement the ClassType trait. I model many types as above and never have to deal with classes, and I hope to keep it that way.
The following fails for the same reason

NSArray::to_vec_retained(msg_send_id![self, values])

In 0.3.0-beta.5 the following worked fine

NSArray::into_vec(msg_send_id![self, values])

I see you took away into_vec for lack of safety because the array is IsIdCloneable so may be cloned even when containing mutable elements.
When I try the into_vec code you used, that is

array
    .to_vec()
    .into_iter()
    .map(|obj| unsafe {
        Id::retain(obj as *const T as *mut T).unwrap_unchecked()
    })
    .collect()

where T=Value here, this fails because to_vec converts to a vector of &AnyObject and then casting &AnyObject to *const T is an invalid cast.
So I'm really not sure at this point how to properly convert an array to a vector when the type of objects in the array don't implement ClassType.

@madsmtm
Copy link
Owner

madsmtm commented Apr 3, 2024

I assume you closed this because you figured out the problem by yourself, but for future reference, I'll give my two cents on this: What you're doing should be possible as just values.to_vec_retained(), and will (probably) eventually be fixed by #563.

But while it's not, the easiest fix is probably to use the code from to_vec_retained directly, with Value plugged in as the T:

let values: Id<NSArray<Value>> = msg_send_id![self, values];
let v: Vec<Id<Value>> = values.to_vec().into_iter().map(|obj| unsafe {
    Id::retain(obj as *const Value as *mut Value).unwrap_unchecked()
}).collect();

@madsmtm madsmtm added question Further information is requested A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates labels Apr 3, 2024
@josephjohnston
Copy link
Author

Thanks, yes I realized I just needed to parameterize NSArray with Value

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants