Git Product home page Git Product logo

rust-objc's People

Contributors

alexbool avatar burtonageo avatar bvssvni avatar jrmuizel avatar leaexplores avatar mehcode avatar ngrewe avatar pcwalton avatar ssheldon avatar syntheorem avatar waywardmonkeys avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rust-objc's Issues

add function to send message without using msg_send! ?

I'm writing a library where I would like to hide the use of objc in the implementation. In the library, I define a macro that internally uses msg_send! and sel! I've managed to hide most objc dependencies using $crate references, but due to the way macro expansion works, I can't hide msg_send! and sel!, which means that the call site needs to have an extern crate objc to use them.

Here is the call site for my macro (notice the extern crate objc earlier):
https://github.com/jmquigs/rs-barfly/blob/master/examples/simple/src/main.rs#l24

And here is the macro definition:
https://github.com/jmquigs/rs-barfly/blob/master/src/lib.rs#l170
(notice how it uses msg_send!)

Is it feasible to export a send_msg() function from objc so that msg_send! can be bypassed? I looked at using "expanded" code directly, but quickly ran into dependencies on MessageArguments and (worse) the associated platform modules. So this may be non-trivial to implement.

Thanks in advance

mem::swap doesn't work with Objects

For example, the following code:

let mut a: Id<NSString> = INSString::from_str("a");
let mut b: Id<NSString> = INSString::from_str("b");
println!("{} {}", a, b);

mem::swap(a.deref_mut(), b.deref_mut());
println!("{} {}", a, b);

Expected output:

a b
b a

Actual output:

a b
a b

We cannot have the expected output happen, because an NSObject's memory address cannot change after it has been constructed.

How can I just execute a function?

CGError CGWarpMouseCursorPosition ( CGPoint newCursorPosition );

I just want to execute this, with this library. Can you give me an example?

Consider making objc no_std compatible

This crate is mainly just a wrapper around the objc runtime dylib, so it shouldn't need much else. If we can make it no_std then it might be usable in more places, perhaps even in the rust compiler itself.

The current std dependencies that aren't part of libcore are:

  • Nul-terminating &str via CString in the runtime module and the declare module
  • Reading the length of a C string via CStr in the runtime module and for Encoding
  • Using a String in Encoding to store dynamically-sized, runtime defined type encodings
  • Allocating a buffer via String when declaring methods to represent their type encodings in the declare module
  • Using a String in the representation of MessageError
  • Implementing the Error trait for MessageError
  • Using the std::os::raw types instead of the libc types in the runtime module and for implementing the Encode trait

encode should return ? for types that don't implement Encode

Implementing #10 would currently require that any type used in a method argument must implement Encode. This is difficult for cases like functions, whose ObjC type encoding is just '?' but it's hard to implement Encode for all fns (because there's fn() -> R, extern fn() -> R, unsafe extern fn() -> R, unsafe fn() -> R, fn(A) -> R, etc).

It'd be simplest if encode<fn()> == "?" without implementing Encode for fn(), and then if Encode isn't implemented when it should be, it would just be an error at runtime.

API for passing already nul-terminated strings to avoid allocation

Currently, in the runtime and declare modules, the API takes &str for ease of use. However, this requires copying the string into a buffer and adding a nul terminator byte. It might be desirable for some cases to have a way to pass in strings which are already known to be nul-terminated so that this allocation can be avoided.

Stabilize declaration of root classes

Declaring root classes can now be done since superclasses were made optional in 154d679. This might deserve a bit more thought:

  • Should declaring a root class be done through a different constructor to make it clear that this is a complicated process? (for example, root classes won't have retain/release/dealloc and so shouldn't be passed to Objective-C code that will expect this, like anything using ARC)
  • Apple's runtime expects a +initialize method to be present and will try to call it, should an empty one be provided by default? Should it be a required parameter when creating a root class?

Implement DerefMut for the owned Id

The owned Id struct should implement DerefMut so that its object can be mutated. However, when DerefMut is implemented, dereferencing to &mut is always chosen over &, which breaks many uses of Id, so this should wait for rust-lang/rust#12825.

Should the MessageArguments trait be made more general?

The MessageArguments trait could be reworked to only have one method: given an IMP, id, and SEL, call the IMP with yourself as arguments. This will work for messaging superclasses, as well, and might allow a clearer separation for GNUstep-specific logic.

Is this worth changing? Is it's purpose clear then? Seems a bit silly to have to pass an IMP when, given the object and selector, the implementation can be looked up.

ICE triggered by Encode, "coherence failed to report ambiguity"

Reported by @bvssvni at rust-windowing/glutin#359, compiling on the 2015-04-03 nightly causes an ICE:

src/declare.rs:138:21: 138:67 error: internal compiler error: coherence failed to report ambiguity: cannot locate the impl of the trait `core::marker::MarkerTrait` for the type `<F as declare::IntoMethodImp>::Ret`
src/declare.rs:138     let mut types = <<F as IntoMethodImp>::Ret as Encode>::encode().as_str().to_string();
                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
note: run with `RUST_BACKTRACE=1` for a backtrace
thread 'rustc' panicked at 'Box<Any>', /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/libsyntax/diagnostic.rs:130

stack backtrace:
   1:        0x111246987 - sys::backtrace::write::h8872f4f658a62d46iJC
   2:        0x1112748a3 - panicking::on_panic::h845201cbea1c5a54uxI
   3:        0x111198cee - rt::unwind::begin_unwind_inner::hfc7848f7429ac5d45eI
   4:        0x1109711ae - rt::unwind::begin_unwind::h396107918539692450
   5:        0x11097115b - diagnostic::SpanHandler::span_bug::hc2e54b04fea5078eYmB
   6:        0x10e42d836 - middle::traits::error_reporting::report_fulfillment_error::hded3e0d571682b65FQN
   7:        0x10e299c01 - middle::traits::error_reporting::report_fulfillment_errors::hd4a5143b2dcf3b1bVPN
   8:        0x10d7dc432 - check::vtable::select_all_fcx_obligations_or_error::h68378d314e6e162eX1b
   9:        0x10d89b010 - check::check_bare_fn::hcbfa2ceb51ac809fvPn
  10:        0x10d894942 - check::check_item::hcd4af901dd683671g8n
  11:        0x10d8992f2 - visit::walk_item::h14171734647403984035
  12:        0x10d970751 - check_crate::closure.36252
  13:        0x10d96ad17 - check_crate::h34c23998ac3af75d1oC
  14:        0x10d68a2e5 - driver::phase_3_run_analysis_passes::h1e90d1b6a6af8247gGa
  15:        0x10d66ea15 - driver::compile_input::h43156fddb0e7acceQba
  16:        0x10d72c985 - run_compiler::hf5bcc2a2a9004c41S4b
  17:        0x10d72a152 - boxed::F.FnBox<A>::call_box::h9818158584254676665
  18:        0x10d729647 - rt::unwind::try::try_fn::h13069897533439949939
  19:        0x1112febe8 - rust_try_inner
  20:        0x1112febd5 - rust_try
  21:        0x10d72993a - boxed::F.FnBox<A>::call_box::h16467879214397932316
  22:        0x11125dd8d - sys::thread::create::thread_start::h81aa05d82aaf9eebbeH
  23:     0x7fff865d8267 - _pthread_body
  24:     0x7fff865d81e4 - _pthread_start

Looks to be this ICE: rust-lang/rust#23853

Add custom derive for Encode

Implementing derive for custom structs is tedious, but all the information it needs is in the declaration of the struct: the name, and the type and order of its members. We should be able to create a custom derive procedural macro to allow #[derive(Encode)].

Remove the EncodePtr trait

The EncodePtr trait may not be necessary. Currently, its main purpose is to express that reference/pointers to any NSObject may be encoded. This can partially be described using where clauses, like where *mut Self: Encode.

Unfortunately, this doesn't allow expressing where &'a Self: Encode because the lifetime is unconstrained, but working around this by casting to a pointer might not be so bad.

The main issue with this is rust-lang/rust#20671; even if a where clause is added to the INSObject trait, it doesn't propagate to subclasses.

Automate iOS tests on Travis

With #25 I put in the work to get the tests working on iOS, but since they aren't run automatically by Travis they don't get run that often.

Running these tests on Travis would be tricky, since we need a Rust compiler that supports iOS. This might have to wait until there's easier cross-compilation support by just downloading the standard library for iOS, which was mentioned as goal for 2016:

We’re shooting for push-button cross-compiles. The idea is that compiling Rust code for another target should be easy:

  1. Download a precompiled version of libstd for the target in question, if you don’t already have it.
  2. Execute cargo build --target=foo.

Adding a method isn't ergonomic

Adding a method to a ClassDecl isn't ergonomic because you need to cast the function to a function pointer, like so:

add_method(sel!(setFoo:), my_obj_set_foo as extern fn(&mut Object, Sel, u32))

This is a bummer because you need to repeat the types that you've already specified.

This wasn't always the case for Rust, but this behavior changed in rust-lang/rust#19891. rust-lang/rust#21086 was opened about this, but was closed as expected behavior.

Example for calling methods with a block as a param?

I'm working on a project that interops with Objective C and got stuck on figuring out how to pass a block [0] as a param to a method. As the comment in cocoa-rs mentions, I am "unsure how to bind to blocks" [1]. I think the next step is looking at how PyObjC implements this and finding a solution for rust. I got as far as reading through the Objective C docs to realize it is an object, but unclear how it is constructed, or invoked. Any ideas or things I should read to try and implement this?

[0] https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html
[1] https://github.com/servo/cocoa-rs/blob/master/src/appkit.rs#L2265

Implement Encode for more types

Encode should be implemented for more types. For example, it currently doesn't support pointers to many value types; this could easily be added for all value types, except it'd conflict with the implementation for C strings.

Specialization, as described in rust-lang/rfcs#1210, would allow implementing this.

encode! macro should safely return an Encoding

The encode! macro should return an Encoding without any unsafe blocks, instead of returning a str like it currently does.

It currently allows creating some invalid encodings that would have to be fixed:

  • encode!() == ""
  • encode!(u8, u8) == "CC"

mem::swap can mess up a Block's memory representation

This issue is similar to #6, but since Block isn't 0-sized it doesn't just cause unexpected behavior, it can actually cause undefined behavior by modifying the memory representation of a block.

let a: &mut Block<_, _> = ...;
let b: &mut Block<_, _> = ...;

mem::swap(a, b);

Safe code can implement Message and therefore Object traits for any type to invoke undefined behavior

Implementing Message doesn't require actually implementing anything, and then implementing INSObject doesn't require any unsafe code. Safe code therefore can implement INSObject for types that it shouldn't and invoke undefined behavior by calling the INSObject methods.

impl Message for uint { }

impl INSObject for uint {
    fn class_name() -> ClassName<uint> {
        ClassName("uint")
    }
}

fn main() {
    let x = 0u;
    let hash_code = x.hash_code();
}

Return an error for IntoMethodImp

IntoMethodImp::into_imp can fail and currently just returns unit in that case; it should return an actual error describing mismatched arguments.

Bring back a smart pointer for reference counting

The Id struct was moved into an external crate in 81a972f, but it seems fundamental enough to exist in this crate in some form.

It was removed because, although its design satisfied the requirements of my foundation wrapper, it isn't compatible with the cocoa crate. The cocoa crate is a lower-level wrapper that operates with raw pointers, so it expects objects as *mut Object where the Id struct could be dereferenced to &Object.

The smart pointer should return with a design that will also be usable by cocoa and other libraries without requiring that users put a lot of effort into determining a safe interface for them.

Make "into" methods take self with type Id<Self>

Currently, functions like INSArray's into_vec cannot be methods because they must consume an Id<Self>. For example, into_vec is currently written as:

fn into_vec(array: Id<Self>) -> ...

This means it must be called as INSArray::into_vec(array). Ideally, it'd be nice to write this as:

fn into_vec(self: Id<Self>) -> ...

Then it'd be possible to just call array.into_vec().

In the May 6th meetings notes, it was mentioned this was apparently possible in a patch at the time: https://github.com/rust-lang/meeting-minutes/blob/master/weekly-meetings/2014-05-06.md#boxself, but this functionality doesn't appear to have shipped.

Return a CowString from Encode

Implementing Encode for structs that are a composition of other Encode types is hard because the output must be static.

It might also be good to make a new type for the return value of Encode so that future abstractions can be built around it.

Id<Object> and friends are unsound and trigger undefined behaviour

The type Id<Object> implements Deref and DerefMut, returning references of type Object. Object is defined as an opaque empty enum:

pub struct Object {
    _priv: PrivateMarker,
}
enum PrivateMarker { }

This is unsound, and may make rustc produce wildly different results in the future. At no point should anyone have a reference to a type that is uninhabited.

Should gnustep be a feature?

Features for crates are usually used for optional functionality. GNUstep support is currently implemented as a feature, but that might not be the right way to think about it. Using GNUstep on Linux isn't really optional, and there doesn't seem to be a use case for using it on OSX when Apple's Objective-C runtime is available.

Perhaps this would be better handled as a configuration, not a feature. A build script could detect whether Apple's runtime is available or the GNUstep runtime and emit cargo:rustc-cfg=gnustep accordingly. It's not clear to me how this detection should be done.

Remove unnecessary Sized bounds

PhantomFn bounds were replaced with Sized in ef565e4 as a way to remove PhantomFn while still compiling on the beta. These Sized bounds didn't impact anything but aren't actually necessary, so they should be removed from:

  • Encode
  • Message
  • Ownership

Run tests on iOS

Support for other architectures was added in e1a9133..2e9192f, so these architectures should also be tested.

This is difficult because Rust's test compile down to an executable, and arbitrary executables can't be run on iOS. rust-lang/rfcs#816 will likely be required to run the existing tests on iOS.

Stabilize EncodeArguments trait

The EncodeArguments trait was added in c6756b5. It seems generally useful since it can be used for declaring methods, too (045a49d), so it's worth stabilizing and making available even without the verify feature.

Some questions:

  • Should it include id and SEL as the first two encodings? Or should this be a more generic "encodable-tuple" trait?
  • If id and SEL are included, should it be named EncodeMessageArguments? To be explicit that this is what the encodings will be when these are used as arguments to a message.
  • Documentation needs to be added for it.

Encode is not implemented for *mut libc::c_void anymore

dee2e48#diff-00e732ca6ab3c3211cacd023da8d7b48L4 is not on crates.io yet, but I think it’s breaking for dependents like glutin who rely on the Encode trait being implemented for libc types. That’s OK for c_char which is just a type alias of u8 or i8, but not for c_void which is unfortunately a different type in std::os::raw and libc: rust-lang/libc#71

I’d recommend bringing back the libc dependency (unfortunate, but the alternative will be a pain) and implementing the trait for both c_void types.

Exceptions should panic at the site of msg_send!

Currently, with the exception feature enabled, when an exception is thrown the panic starts from within the implementation of messaging. This should be raised to the macro, so that the first thing the user sees is which line of their code was the issue without having to re-run with backtraces on.

This might also be a good way to surface verification errors once they're finalized in #38.

Warnings with beta and nightly

Hi,

I'm making progress on setting up a travis build job, and it promptly discovered a few warnings when building rust-objc with rust beta or nightly:

src/runtime.rs:108:38: 108:43 warning: found non-foreign-function-safe member in struct marked #[repr(C)]: found zero-size struct in foreign module, consider adding a member to this struct, #[warn(improper_ctypes)] on by default
src/runtime.rs:108     pub fn class_getName(cls: *const Class) -> *const c_char;
                                                        ^~~~~

That's caused by PrivateMarker being a unit struct. So it affects Class, Object, Ivar, and Method. Not sure what to do here. It's not really a dangerous thing since you only ever manipulate pointers to these structs, but it would still be nice to have this handled properly.

NSCopying for collections allows creating aliased owned Ids

I had envisioned the Id struct would own its object so you could get a mutable reference to the object, and also that NSArray would own the objects it contains. However, this doesn't work if NSArray also implements NSCopying, because NSCopying is a shallow copy. This means I could copy an NSArray, turn them both into Vec<Id<T>>, and then have two Ids for the same object which would allow aliasing &mut references.

Alignment for ivars may be wrong

I thought I saw objects being way too big when declared by this crate, with lots of empty space between each ivar. Maybe a log2 needs to be thrown at the alignment before declaring an ivar?

Type register and method export attributes for objc in Rust like C# in xamarin?

It is very convenient to expose a C# class to objc by using attributes. (Usage: https://developer.xamarin.com/guides/ios/advanced_topics/registrar/ Implement: https://github.com/mono/cocoa-sharp/) .

Rust has the same attribute system like C#. So is it possible to have these attributes in Rust?

One of the benefits or needs is to use solid type instead of marked type connect between Rust and objc, and to wrap Rust struct method instead of static method for objc message receiving.

cocoa-sharp has these tricks.

How to implement a selector for a menuitem?

Hello,

I'm trying to add a selector for a menuitem command. Basically I have this:

let itemtitle = NSString::alloc(nil).init_str("PREFS");
let no_key = NSString::alloc(nil).init_str("");
let action = sel!(myhandler);
let item = NSMenuItem::alloc(nil).initWithTitle_action_keyEquivalent_(itemtitle, action, no_key);
menu.addItem_(item);

The menu works, but the item is disabled, which I think is because my object does not respond to the "myhandler" selector. I'm not quite sure how to use this API to add one. I tried implementing a custom object for the selector based on this example (https://github.com/SSheldon/rust-objc-foundation/blob/master/examples/custom_class.rs#L34), but it has no effect; I guess that is because I am defining the selector on "MYObject" and not the menu item. Is this kind of selector implementation supported by the library at the moment?

code relies on type inference rules which are likely to change

probably msg_send macro is using type inference rules which will be removed in the next coming rustc.
my current rustc version is rustc 1.19.0-nightly (d015610db 2017-06-05)

complete warning is:

  • note: #[warn(resolve_trait_on_defaulted_unit)] on by default
  • warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  • note: for more information, see issue #39216 rust-lang/rust#39216
  • note: this error originates in a macro outside of the current crate

Zero-allocation encodings

Currently primitive types have encodings that do not allocate (they're defined from static strings) but compositions like structs either have to jump through hoops and use different encoding strings for different architectures or accept the cost of allocating a string and pushing the encoding of their fields.

Is there a better way to do this, where encodings from structs could more simply be composed without allocating?

Cannot call methods with unnamed parameters

It seems rust-objc's msg_send! doesn't let you call methods with unnamed parameters.

For example, CIImage has the following methods:

- (instancetype)initWithImageProvider:(id)p size:(size_t)width :(size_t)height format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs options:(NSDictionary<NSString *,id> *)options;
+ (CIImage *)imageWithImageProvider:(id)p size:(size_t)width :(size_t)height format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs options:(NSDictionary<NSString *,id> *)options;

CAMediaTimingFunction has the following methods:

+ (instancetype)functionWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;
- (instancetype)initWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;

The 3rd parameter of each of the CIImage methods, and the 2nd, 3rd and 4th parameters of the CAMediaTimingFunction methods don't have a label (even though they have an internal name). msg_send! won't let you call such methods.

Stabilize verification of message types

Verifying argument types for messages was added back with #10. It should remain behind a feature, but before it ships a couple things should be done:

  • What type should the error be? String isn't a very rust-y error type.
  • Should there be a public API for verifying these types? Or is panicking internally when they're incorrect sufficient?
  • The feature should be documented.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.