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_encodingandStackBlock::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 haveihere. - 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 signature | Runtime 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§
Sourceconst ENCODING_CSTR: &'static CStr
const ENCODING_CSTR: &'static CStr
The raw encoding information string.
Required Associated Types§
Sourcetype Arguments: EncodeArguments
type Arguments: EncodeArguments
The function’s input argument types.
Sourcetype Return: EncodeReturn
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.