RACTuple.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. //
  2. // RACTuple.h
  3. // ReactiveObjC
  4. //
  5. // Created by Josh Abernathy on 4/12/12.
  6. // Copyright (c) 2012 GitHub, Inc. All rights reserved.
  7. //
  8. #import <Foundation/Foundation.h>
  9. #import "metamacros.h"
  10. @class RACSequence;
  11. /// Creates a new tuple with the given values. At least one value must be given.
  12. /// Values can be nil.
  13. #define RACTuplePack(...) \
  14. RACTuplePack_(__VA_ARGS__)
  15. /// Declares new object variables and unpacks a RACTuple into them.
  16. ///
  17. /// This macro should be used on the left side of an assignment, with the
  18. /// tuple on the right side. Nothing else should appear on the same line, and the
  19. /// macro should not be the only statement in a conditional or loop body.
  20. ///
  21. /// If the tuple has more values than there are variables listed, the excess
  22. /// values are ignored.
  23. ///
  24. /// If the tuple has fewer values than there are variables listed, the excess
  25. /// variables are initialized to nil.
  26. ///
  27. /// Examples
  28. ///
  29. /// RACTupleUnpack(NSString *string, NSNumber *num) = [RACTuple tupleWithObjects:@"foo", @5, nil];
  30. /// NSLog(@"string: %@", string);
  31. /// NSLog(@"num: %@", num);
  32. ///
  33. /// /* The above is equivalent to: */
  34. /// RACTuple *t = [RACTuple tupleWithObjects:@"foo", @5, nil];
  35. /// NSString *string = t[0];
  36. /// NSNumber *num = t[1];
  37. /// NSLog(@"string: %@", string);
  38. /// NSLog(@"num: %@", num);
  39. #define RACTupleUnpack(...) \
  40. RACTupleUnpack_(__VA_ARGS__)
  41. NS_ASSUME_NONNULL_BEGIN
  42. /// A sentinel object that represents nils in the tuple.
  43. ///
  44. /// It should never be necessary to create a tuple nil yourself. Just use
  45. /// +tupleNil.
  46. @interface RACTupleNil : NSObject <NSCopying, NSCoding>
  47. /// A singleton instance.
  48. + (RACTupleNil *)tupleNil;
  49. @end
  50. /// A tuple is an ordered collection of objects. It may contain nils, represented
  51. /// by RACTupleNil.
  52. @interface RACTuple : NSObject <NSCoding, NSCopying, NSFastEnumeration>
  53. @property (nonatomic, readonly) NSUInteger count;
  54. /// These properties all return the object at that index or nil if the number of
  55. /// objects is less than the index.
  56. @property (nonatomic, readonly, nullable) id first;
  57. @property (nonatomic, readonly, nullable) id second;
  58. @property (nonatomic, readonly, nullable) id third;
  59. @property (nonatomic, readonly, nullable) id fourth;
  60. @property (nonatomic, readonly, nullable) id fifth;
  61. @property (nonatomic, readonly, nullable) id last;
  62. /// Creates a new tuple out of the array. Does not convert nulls to nils.
  63. + (instancetype)tupleWithObjectsFromArray:(NSArray *)array;
  64. /// Creates a new tuple out of the array. If `convert` is YES, it also converts
  65. /// every NSNull to RACTupleNil.
  66. + (instancetype)tupleWithObjectsFromArray:(NSArray *)array convertNullsToNils:(BOOL)convert;
  67. /// Creates a new tuple with the given objects. Use RACTupleNil to represent
  68. /// nils.
  69. + (instancetype)tupleWithObjects:(id)object, ... NS_REQUIRES_NIL_TERMINATION;
  70. /// Returns the object at `index` or nil if the object is a RACTupleNil. Unlike
  71. /// NSArray and friends, it's perfectly fine to ask for the object at an index
  72. /// past the tuple's count - 1. It will simply return nil.
  73. - (nullable id)objectAtIndex:(NSUInteger)index;
  74. /// Returns an array of all the objects. RACTupleNils are converted to NSNulls.
  75. - (NSArray *)allObjects;
  76. /// Appends `obj` to the receiver.
  77. ///
  78. /// obj - The object to add to the tuple. This argument may be nil.
  79. ///
  80. /// Returns a new tuple.
  81. - (instancetype)tupleByAddingObject:(nullable id)obj;
  82. @end
  83. @interface RACTuple (RACSequenceAdditions)
  84. /// Returns a sequence of all the objects. RACTupleNils are converted to NSNulls.
  85. @property (nonatomic, copy, readonly) RACSequence *rac_sequence;
  86. @end
  87. @interface RACTuple (ObjectSubscripting)
  88. /// Returns the object at that index or nil if the number of objects is less
  89. /// than the index.
  90. - (nullable id)objectAtIndexedSubscript:(NSUInteger)idx;
  91. @end
  92. /// This and everything below is for internal use only.
  93. ///
  94. /// See RACTuplePack() and RACTupleUnpack() instead.
  95. #define RACTuplePack_(...) \
  96. ([RACTuple tupleWithObjectsFromArray:@[ metamacro_foreach(RACTuplePack_object_or_ractuplenil,, __VA_ARGS__) ]])
  97. #define RACTuplePack_object_or_ractuplenil(INDEX, ARG) \
  98. (ARG) ?: RACTupleNil.tupleNil,
  99. #define RACTupleUnpack_(...) \
  100. metamacro_foreach(RACTupleUnpack_decl,, __VA_ARGS__) \
  101. \
  102. int RACTupleUnpack_state = 0; \
  103. \
  104. RACTupleUnpack_after: \
  105. ; \
  106. metamacro_foreach(RACTupleUnpack_assign,, __VA_ARGS__) \
  107. if (RACTupleUnpack_state != 0) RACTupleUnpack_state = 2; \
  108. \
  109. while (RACTupleUnpack_state != 2) \
  110. if (RACTupleUnpack_state == 1) { \
  111. goto RACTupleUnpack_after; \
  112. } else \
  113. for (; RACTupleUnpack_state != 1; RACTupleUnpack_state = 1) \
  114. [RACTupleUnpackingTrampoline trampoline][ @[ metamacro_foreach(RACTupleUnpack_value,, __VA_ARGS__) ] ]
  115. #define RACTupleUnpack_state metamacro_concat(RACTupleUnpack_state, __LINE__)
  116. #define RACTupleUnpack_after metamacro_concat(RACTupleUnpack_after, __LINE__)
  117. #define RACTupleUnpack_loop metamacro_concat(RACTupleUnpack_loop, __LINE__)
  118. #define RACTupleUnpack_decl_name(INDEX) \
  119. metamacro_concat(metamacro_concat(RACTupleUnpack, __LINE__), metamacro_concat(_var, INDEX))
  120. #define RACTupleUnpack_decl(INDEX, ARG) \
  121. __strong id RACTupleUnpack_decl_name(INDEX);
  122. #define RACTupleUnpack_assign(INDEX, ARG) \
  123. __strong ARG = RACTupleUnpack_decl_name(INDEX);
  124. #define RACTupleUnpack_value(INDEX, ARG) \
  125. [NSValue valueWithPointer:&RACTupleUnpack_decl_name(INDEX)],
  126. @interface RACTupleUnpackingTrampoline : NSObject
  127. + (instancetype)trampoline;
  128. - (void)setObject:(nullable RACTuple *)tuple forKeyedSubscript:(NSArray *)variables;
  129. @end
  130. NS_ASSUME_NONNULL_END