This repository has been archived by the owner on Dec 5, 2019. It is now read-only.
Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
libextobjc/extobjc/EXTKeyPathCoding.h
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
77 lines (61 sloc)
2.95 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// EXTKeyPathCoding.h | |
// extobjc | |
// | |
// Created by Justin Spahr-Summers on 19.06.12. | |
// Copyright (C) 2012 Justin Spahr-Summers. | |
// Released under the MIT license. | |
// | |
#import <Foundation/Foundation.h> | |
#import "metamacros.h" | |
/** | |
* \@keypath allows compile-time verification of key paths. Given a real object | |
* receiver and key path: | |
* | |
* @code | |
NSString *UTF8StringPath = @keypath(str.lowercaseString.UTF8String); | |
// => @"lowercaseString.UTF8String" | |
NSString *versionPath = @keypath(NSObject, version); | |
// => @"version" | |
NSString *lowercaseStringPath = @keypath(NSString.new, lowercaseString); | |
// => @"lowercaseString" | |
* @endcode | |
* | |
* ... the macro returns an \c NSString containing all but the first path | |
* component or argument (e.g., @"lowercaseString.UTF8String", @"version"). | |
* | |
* In addition to simply creating a key path, this macro ensures that the key | |
* path is valid at compile-time (causing a syntax error if not), and supports | |
* refactoring, such that changing the name of the property will also update any | |
* uses of \@keypath. | |
*/ | |
#define keypath(...) \ | |
_Pragma("clang diagnostic push") \ | |
_Pragma("clang diagnostic ignored \"-Warc-repeated-use-of-weak\"") \ | |
(NO).boolValue ? ((NSString * _Nonnull)nil) : ((NSString * _Nonnull)@(cStringKeypath(__VA_ARGS__))) \ | |
_Pragma("clang diagnostic pop") \ | |
#define cStringKeypath(...) \ | |
metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__))(keypath1(__VA_ARGS__))(keypath2(__VA_ARGS__)) | |
#define keypath1(PATH) \ | |
(((void)(NO && ((void)PATH, NO)), \ | |
({ char *__extobjckeypath__ = strchr(# PATH, '.'); NSCAssert(__extobjckeypath__, @"Provided key path is invalid."); __extobjckeypath__ + 1; }))) | |
#define keypath2(OBJ, PATH) \ | |
(((void)(NO && ((void)OBJ.PATH, NO)), # PATH)) | |
/** | |
* \@collectionKeypath allows compile-time verification of key paths across collections NSArray/NSSet etc. Given a real object | |
* receiver, collection object receiver and related keypaths: | |
* | |
* @code | |
NSString *employeesFirstNamePath = @collectionKeypath(department.employees, Employee.new, firstName) | |
// => @"employees.firstName" | |
NSString *employeesFirstNamePath = @collectionKeypath(Department.new, employees, Employee.new, firstName) | |
// => @"employees.firstName" | |
* @endcode | |
* | |
*/ | |
#define collectionKeypath(...) \ | |
metamacro_if_eq(3, metamacro_argcount(__VA_ARGS__))(collectionKeypath3(__VA_ARGS__))(collectionKeypath4(__VA_ARGS__)) | |
#define collectionKeypath3(PATH, COLLECTION_OBJECT, COLLECTION_PATH) \ | |
(YES).boolValue ? (NSString * _Nonnull)@((const char * _Nonnull)[[NSString stringWithFormat:@"%s.%s", cStringKeypath(PATH), cStringKeypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String]) : (NSString * _Nonnull)nil | |
#define collectionKeypath4(OBJ, PATH, COLLECTION_OBJECT, COLLECTION_PATH) \ | |
(YES).boolValue ? (NSString * _Nonnull)@((const char * _Nonnull)[[NSString stringWithFormat:@"%s.%s", cStringKeypath(OBJ, PATH), cStringKeypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String]) : (NSString * _Nonnull)nil | |