ManualBlockEncoding

Trait ManualBlockEncoding 

Source
pub unsafe trait ManualBlockEncoding {
    type Arguments: EncodeArguments;
    type Return: EncodeReturn;

    const ENCODING_CSTR: &'static CStr;
}
Expand description

Interim abstraction to manually provide block encodings for use at compile time with StackBlock::with_encoding and RcBlock::with_encoding.

See these functions for examples of how to implement and use this trait, since its sole purpose is passing values at compile time to them.

As a side note, one might be surprised by the additional Self::Arguments and Self::Return associated types requiring concrete implementations to specify them while they are not actually used. This is intentional:

  • the types are checked at compile-time to be equal to the ones used with RcBlock::with_encoding and StackBlock::with_encoding, usually inferred by the compiler when giving a closure: this should help avoid some easy oversights;
  • the user is forced to write both the standard Rust types and the encoding string at the same time, so particular attention to the types is put to the forefront for them;
  • reading a block encoding string is tough when not initiated, so these also serve as self-documentation;
  • the safety validation can be moved to the trait implementation, so that the use can be marked safe.

§Safety

Self::ENCODING_CSTR must correspond to the actual signature string a recent-enough Objective-C compiler would generate for a block taking in Self::Arguments as input and returning Self::Return as output. This information is actually used by the Objective-C runtime in order to correctly invoke the block, so specifying a wrong encoding is definitely a soundness issue: see this issue comment for more details about what exactly goes on behind the scenes in order to justify all the following precautions.

The easiest way to do this is probably to ask Clang; the following program will print the signature of the block (if you’re having trouble linking, you should be able to find the signature in the assembly output).

#import <Foundation/Foundation.h>

// Unstable API, but fine for test usage like this.
const char * _Block_signature(void *);

int main() {
    // Declare the signature of your block.
    // This one takes `id` and `int`, and returns `NSString*`.
    id block = ^NSString* (id a, int b) {
        return nil;
    };

    printf("%s\n", _Block_signature((void*)block));
    return 0;
}

A more thorough but manual approach is to only follow the rules described below.

In this process, you may be able to use Encoding::to_string in order to get the various components of the signature string and then concatenate them manually with the required numbers (described below) inserted at their correct place.

§Encoding string generation

This is the result of the @encode Objective-C compiler directive. The Apple documentation and GCC documentation explain how each base type is encoded into a string representation. See there for a somewhat-formal specification and a few basic examples. See also Encoding.

See also the GCC method signatures section. It is mostly valid for blocks as well, since they are basically functions with captured environment – i.e. closures, except that no selector is implicitly sent, only the block object is. In short, the “signature” is a null-terminated string, composed of the following, in order:

  • The return type, including type qualifiers. For example, a block returning int (i32) would have i here.
  • The total size (in bytes) required to pass all the parameters: the call frame size. This includes the hidden block object parameter that is passed as a pointer, so at least 4 bytes when under a 32-bit system or most probably 8 bytes when under a 64-bit one.
  • Each argument, with the type encoding, followed by the offset (in bytes) of the argument in the list of parameters. The first is the always the hidden block object pointer and is therefore @?0.

Examples:

Objective-C signatureRuntime encoding
void (^)(void)v8@?0
int (^)(void)i8@?0
int (^)(float)i12@?0f8
int (^)(float, _Bool)i16@?0f8B12
void (^)(int*)v16@?0^i8
void (^)(NSError*)v16@?0@8 or v16@?0@"NSError"8
NSError* (^)(NSError*)@16@?0@8 or @"NSError"16@?0@"NSError"8

Required Associated Constants§

Source

const ENCODING_CSTR: &'static CStr

The raw encoding information string.

Required Associated Types§

Source

type Arguments: EncodeArguments

The function’s input argument types.

Source

type Return: EncodeReturn

The function’s return type.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§