Skip to content

Instantly share code, notes, and snippets.

@bkase
Last active August 2, 2017 11:53
Show Gist options
  • Save bkase/3da9c46195961ed58bc8a7b1b05c1f87 to your computer and use it in GitHub Desktop.
Save bkase/3da9c46195961ed58bc8a7b1b05c1f87 to your computer and use it in GitHub Desktop.
Algebraic Data Types in Objective-C with Macros
//
// BKOneOf.h
// BKOneOf
//
#ifndef BKOneOf_h
#define BKOneOf_h
/*
* Interface and Implementation separate:
*
* BK_ONE_OF(BKSchema,
* BK_CASE(Object, NSString *, name, NSArray<NSString *>, methods),
* BK_CASE(String, NSString *, str)
* )
*
* @class BKSchemaObject;
* @class BKSchemaString;
*
* typedef NS_ENUM(NSInteger, BKSchemaTag) {
* BKSchemaTagString = 0,
* BKSchemaTagObject
* };
*
* @interface BKSchema <ObjectType> : NSObject
* @property (nonatomic, assign, readonly) BKSchemaTag tag;
*
* -(instancetype)init NS_UNAVAILABLE;
* -(instancetype)initWithTag:( BKSchemaTag )tag;
* +(ObjectType)match:( BKSchema *)sum
* caseObject : (ObjectType(^)( BKSchemaObject *))handleObject
* caseString : (ObjectType(^)( BKSchemaString *))handleString;
* @end
*
* @interface BKSchemaObject : BKSchema
* @property (nonatomic, readonly) NSString * name;
* @property (nonatomic, readonly) NSArray<NSString *> * methods;
* -(instancetype)init NS_UNAVAILABLE;
* -(id)initWithname:(NSString *)name
* methods : (NSArray<NSString *>*)methods;
* @end
*
* @interface BKSchemaString : BKSchema
* @property (nonatomic, readonly) NSString * str;
* -(instancetype)init NS_UNAVAILABLE;
* -(id)initWithstr:(NSString *)str ;
* @end
*
*
* BK_ONE_OF_IMPL(BKSchema,
* BK_CASE(Object, NSString *, name, NSArray<NSString *>, methods),
* BK_CASE(String, NSString *, str)
* )
*
* @interface BKSchemaObject ()
* @property (nonatomic) NSString * name;
* @property (nonatomic) NSArray<NSString *>* methods;
* @end
*
* @implementation BKSchemaObject
* -(id)initWithname:(NSString *)name methods : (NSArray<NSString *>*)methods
* {
* BKSchemaTag tag = BKSchemaTagObject;
* if (self = [super initWithTag: tag]) {
* _name = name;
* _methods = methods;
* }
* return self;
* }
* @end
*
* @interface BKSchemaString ()
* @property (nonatomic) NSString * str;
* @end
*
* @implementation BKSchemaString
* -(id)initWithstr:(NSString *)str {
* BKSchemaTag tag = BKSchemaTagString;
* if (self = [super initWithTag: tag]) {
* _str = str;
* }
* return self;
* }
* @end
*
* @interface BKSchema ()
* -(instancetype)initWithTag:( BKSchemaTag )tag;
* @end
*
* @implementation BKSchema
* -(instancetype)initWithTag : (prefix##Tag)tag
* {
* if (self = [super init]) {
* _tag = tag;
* }
* return self;
* }
* +(id)match:( BKSchema *)sum
* orObject : (id (^)( BKSchemaObject *))handleObject
* orString : (id (^)( BKSchemaString *))handleString {
* switch (sum.tag) {
* case BKSchemaObjectTag:
* return handleObject(( BKSchemaObject *)sum);
* case BKSchemaStringTag:
* return handleString(( BKSchemaString *)sum);
* default:
* NSAssert(false, @"Match error");
* return nil;
* }
* }
* @end
*/
// clang-format off
/// See BKOneOfTestCase.m for usage
#define BK_ONE_OF(prefix, ...) \
BK_ONE_OF_TAGS_DEFINE(prefix, __VA_ARGS__) \
\
BK_ONE_OF_FOR_QUINT_CONST_EACH(BK_ONE_OF_ONE_FORWARD_DECLARATION, prefix, __VA_ARGS__) \
BK_ONE_OF_BASE_INTERFACE(prefix, __VA_ARGS__) \
\
BK_ONE_OF_FOR_QUINT_CONST_EACH(BK_ONE_OF_ONE_CHILD_INTERFACE, prefix, __VA_ARGS__)
/// See BKOneOfTestCase.m for usage
#define BK_ONE_OF_IMPL(prefix, ...) \
@interface prefix () \
@property (nonatomic, assign) prefix##Tag tag; \
@end \
\
BK_ONE_OF_FOR_QUINT_CONST_EACH(BK_ONE_OF_ONE_CHILD_IMPL, prefix, __VA_ARGS__) \
\
BK_ONE_OF_BASE_IMPLEMENTATION(prefix, __VA_ARGS__)
// BK_CASE helpers
#define BK_ONE_OF_CASE_PROPERTY_DECLARE(typ, var) @property (nonatomic) typ var;
#define BK_ONE_OF_CASE_PROPERTY_READONLY(typ, var) @property (nonatomic, readonly) typ var;
#define BK_ONE_OF_CASE_METHOD_EXTRA(typ, var) var:(typ) var
#define BK_ONE_OF_CASE_INIT_IMPL(typ, var) _##var = var;
// name, (typ, arg)...
// returns:
// (name, ifaceChunk, implChunk1, implChunk2, privateChunk)...
// where chunk =
// starting at the line after @interface
// and the line after @implementation
// INCLUDES @end
// where implChunk1,implChunk2 is partitioned on
// prefix##Tag tag = prefix##Tag##name; (to go inside super call)
// since we need the prefix here
#define BK_CASE(name, typ, var, ...) \
name, \
\
BK_ONE_OF_CONCATENATE(-(id)initWith, var) \
: (typ)var BK_ONE_OF_FOR_DOUBLE_EACH(BK_ONE_OF_CASE_METHOD_EXTRA, __VA_ARGS__); \
BK_ONE_OF_FOR_DOUBLE_EACH(BK_ONE_OF_CASE_PROPERTY_READONLY, typ, var, __VA_ARGS__); \
@end, \
\
BK_ONE_OF_CONCATENATE(-(id)initWith, var) \
: (typ)var BK_ONE_OF_FOR_DOUBLE_EACH(BK_ONE_OF_CASE_METHOD_EXTRA, __VA_ARGS__) \
{ \
, if (self = [super initWithTag:tag]) \
{ \
BK_ONE_OF_FOR_DOUBLE_EACH(BK_ONE_OF_CASE_INIT_IMPL, typ, var, __VA_ARGS__) \
} \
return self; \
} \
@end, \
\
BK_ONE_OF_FOR_DOUBLE_EACH(BK_ONE_OF_CASE_PROPERTY_DECLARE, typ, var, __VA_ARGS__); \
@end
#define BK_ONE_OF_ONE_FORWARD_DECLARATION(prefix, name, ifaceChunk, implChunk1, implChunk2, privateChunk) \
@class prefix##name;
#define BK_ONE_OF_ONE_CHILD_INTERFACE(prefix, name, ifaceChunk, implChunk1, implChunk2, privateChunk) \
@interface prefix##name : prefix - (instancetype)init NS_UNAVAILABLE; \
ifaceChunk
#define BK_ONE_OF_ONE_CHILD_IMPL(prefix, name, ifaceChunk, implChunk1, implChunk2, privateChunk) \
@interface prefix##name() \
privateChunk \
@implementation prefix##name \
implChunk1 \
prefix##Tag tag = prefix##Tag##name; \
implChunk2
#define BK_ONE_OF_ONE_MATCH_PARAM(prefix, name, ifaceChunk, implChunk1, implChunk2, privateChunk) \
or##name : (ObjectType (^)(prefix##name *))handle##name
#define BK_ONE_OF_BASE_INTERFACE(prefix, ...) \
@interface prefix<ObjectType> : NSObject \
@property (nonatomic, assign, readonly) prefix##Tag tag; \
\
-(instancetype)init NS_UNAVAILABLE; \
-(instancetype)initWithTag : (prefix##Tag)tag; \
+(ObjectType)match \
: (prefix *)sum BK_ONE_OF_FOR_QUINT_CONST_EACH(BK_ONE_OF_ONE_MATCH_PARAM, prefix, __VA_ARGS__); \
@end
#define BK_ONE_OF_ONE_MATCH_IMPL_PARAM(prefix, name, ifaceChunk, implChunk1, implChunk2, privateChunk) \
or##name : (id (^)(prefix##name *))handle##name
#define BK_ONE_OF_ONE_MATCH_CONDITION(prefix, name, ifaceChunk, ifaceChunk1, implChunk2, privateChunk) \
case prefix##Tag##name: \
return handle##name((prefix##name *)sum);
#define BK_ONE_OF_BASE_IMPLEMENTATION(prefix, ...) \
@implementation prefix \
-(instancetype)initWithTag : (prefix##Tag)tag \
{ \
if (self = [super init]) { \
_tag = tag; \
} \
return self; \
} \
\
+(id)match : (prefix *)sum BK_ONE_OF_FOR_QUINT_CONST_EACH(BK_ONE_OF_ONE_MATCH_IMPL_PARAM, prefix, __VA_ARGS__) \
{ \
switch (sum.tag) { \
BK_ONE_OF_FOR_QUINT_CONST_EACH(BK_ONE_OF_ONE_MATCH_CONDITION, prefix, __VA_ARGS__) \
default: \
NSAssert(false, @"Match error"); \
return nil; \
} \
} \
@end
#define BK_ONE_OF_ONE_TAG_DEFINE(prefix, name, ifaceChunk, implChunk1, implChunk2, privateChunk) , prefix##Tag##name
#define BK_ONE_OF_TAGS_DEFINE(prefix, name, ifaceChunk, implChunk1, implChunk2, privateChunk, ...) \
typedef NS_ENUM(NSInteger, prefix##Tag) { \
prefix##Tag##name = 0 BK_ONE_OF_FOR_QUINT_CONST_EACH(BK_ONE_OF_ONE_TAG_DEFINE, prefix, __VA_ARGS__) \
};
// clang-format on
/*
* HELPERS
*/
// This macro lets you x##y but x and/or y
// can be nested macro calls.
//
// from http://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros
#define BK_ONE_OF_CONCATENATE(x, y) BK_ONE_OF_CONCATENATE1(x, y)
#define BK_ONE_OF_CONCATENATE1(x, y) BK_ONE_OF_CONCATENATE2(x, y)
#define BK_ONE_OF_CONCATENATE2(x, y) x##y
// Apply macro over every two varargs
// BK_ONE_OF_FOR_DOUBLE_EACH : (what: (a, b) -> c, ...args)
#define BK_ONE_OF_FOR_DOUBLE_EACH_0(...)
#define BK_ONE_OF_FOR_DOUBLE_EACH_1(what, x, y, ...) what(x, y)
#define BK_ONE_OF_FOR_DOUBLE_EACH_2(what, x, y, ...) \
what(x, y) BK_ONE_OF_FOR_DOUBLE_EACH_1(what, __VA_ARGS__)
#define BK_ONE_OF_FOR_DOUBLE_EACH_3(what, x, y, ...) \
what(x, y) BK_ONE_OF_FOR_DOUBLE_EACH_2(what, __VA_ARGS__)
#define BK_ONE_OF_FOR_DOUBLE_EACH_4(what, x, y, ...) \
what(x, y) BK_ONE_OF_FOR_DOUBLE_EACH_3(what, __VA_ARGS__)
#define BK_ONE_OF_FOR_DOUBLE_EACH_5(what, x, y, ...) \
what(x, y) BK_ONE_OF_FOR_DOUBLE_EACH_4(what, __VA_ARGS__)
#define BK_ONE_OF_FOR_DOUBLE_EACH_6(what, x, y, ...) \
what(x, y) BK_ONE_OF_FOR_DOUBLE_EACH_5(what, __VA_ARGS__)
#define BK_ONE_OF_FOR_DOUBLE_EACH_7(what, x, y, ...) \
what(x, y) BK_ONE_OF_FOR_DOUBLE_EACH_6(what, __VA_ARGS__)
#define BK_ONE_OF_FOR_DOUBLE_EACH_8(what, x, y, ...) \
what(x, y) BK_ONE_OF_FOR_DOUBLE_EACH_7(what, __VA_ARGS__)
#define BK_ONE_OF_FOR_DOUBLE_EACH_NARG(...) \
BK_ONE_OF_FOR_DOUBLE_EACH_NARG_(__VA_ARGS__, \
BK_ONE_OF_FOR_DOUBLE_EACH_RSEQ_N())
#define BK_ONE_OF_FOR_DOUBLE_EACH_NARG_(...) \
BK_ONE_OF_FOR_DOUBLE_EACH_ARG_N(__VA_ARGS__)
#define BK_ONE_OF_FOR_DOUBLE_EACH_ARG_N(_0, F0, F01, _1, F1, _2, F2, _3, F3, \
_4, F4, _5, F5, _6, F6, _7, F7, N, \
...) \
N
#define BK_ONE_OF_FOR_DOUBLE_EACH_RSEQ_N() \
8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0
#define BK_ONE_OF_FOR_DOUBLE_EACH_(N, what, ...) \
BK_ONE_OF_CONCATENATE(BK_ONE_OF_FOR_DOUBLE_EACH_, N)(what, __VA_ARGS__)
#define BK_ONE_OF_FOR_DOUBLE_EACH(what, ...) \
BK_ONE_OF_FOR_DOUBLE_EACH_(BK_ONE_OF_FOR_DOUBLE_EACH_NARG(__VA_ARGS__), \
what, __VA_ARGS__)
// Apply macro over every three varargs with a const param
// BK_ONE_OF_FOR_QUAD_CONST_EACH : (what: (const, a, b, c, d) -> e, const,
// ...args)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_0(...)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_1(what, c, x, y, z, w, ...) \
what(c, x, y, z, w)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_2(what, c, x, y, z, w, ...) \
what(c, x, y, z, w) BK_ONE_OF_FOR_QUAD_CONST_EACH_1(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_3(what, c, x, y, z, w, ...) \
what(c, x, y, z, w) BK_ONE_OF_FOR_QUAD_CONST_EACH_2(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_4(what, c, x, y, z, w, ...) \
what(c, x, y, z, w) BK_ONE_OF_FOR_QUAD_CONST_EACH_3(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_5(what, c, x, y, z, w, ...) \
what(c, x, y, z, w) BK_ONE_OF_FOR_QUAD_CONST_EACH_4(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_6(what, c, x, y, z, w, ...) \
what(c, x, y, z, w) BK_ONE_OF_FOR_QUAD_CONST_EACH_5(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_7(what, c, x, y, z, w, ...) \
what(c, x, y, z, w) BK_ONE_OF_FOR_QUAD_CONST_EACH_6(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_8(what, c, x, y, z, w, ...) \
what(c, x, y, z, w) BK_ONE_OF_FOR_QUAD_CONST_EACH_7(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_NARG(...) \
BK_ONE_OF_FOR_QUAD_CONST_EACH_NARG_(__VA_ARGS__, \
BK_ONE_OF_FOR_QUAD_CONST_EACH_RSEQ_N())
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_NARG_(...) \
BK_ONE_OF_FOR_QUAD_CONST_EACH_ARG_N(__VA_ARGS__)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_ARG_N(_0, F0, F00, F000, _1, F1, F11, \
F111, _2, F2, F22, F222, _3, F3, \
F33, F333, _4, F4, F44, F444, _5, \
F5, F55, F555, _6, F6, F66, F666, \
_7, F7, F77, F777, N, ...) \
N
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_RSEQ_N() \
8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, \
2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0
#define BK_ONE_OF_FOR_QUAD_CONST_EACH_(N, what, c, ...) \
BK_ONE_OF_CONCATENATE(BK_ONE_OF_FOR_QUAD_CONST_EACH_, N)(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUAD_CONST_EACH(what, c, ...) \
BK_ONE_OF_FOR_QUAD_CONST_EACH_( \
BK_ONE_OF_FOR_QUAD_CONST_EACH_NARG(__VA_ARGS__), what, c, __VA_ARGS__)
// Apply macro over every three varargs with a const param
// BK_ONE_OF_FOR_QUINT_CONST_EACH : (what: (const, a, b, c, d) -> e, const,
// ...args)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_0(...)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_1(what, c, x, y, z, w, v, ...) \
what(c, x, y, z, w, v)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_2(what, c, x, y, z, w, v, ...) \
what(c, x, y, z, w, v) BK_ONE_OF_FOR_QUINT_CONST_EACH_1(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_3(what, c, x, y, z, w, v, ...) \
what(c, x, y, z, w, v) BK_ONE_OF_FOR_QUINT_CONST_EACH_2(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_4(what, c, x, y, z, w, v, ...) \
what(c, x, y, z, w, v) BK_ONE_OF_FOR_QUINT_CONST_EACH_3(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_5(what, c, x, y, z, w, v, ...) \
what(c, x, y, z, w, v) BK_ONE_OF_FOR_QUINT_CONST_EACH_4(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_6(what, c, x, y, z, w, v, ...) \
what(c, x, y, z, w, v) BK_ONE_OF_FOR_QUINT_CONST_EACH_5(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_7(what, c, x, y, z, w, v, ...) \
what(c, x, y, z, w, v) BK_ONE_OF_FOR_QUINT_CONST_EACH_6(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_8(what, c, x, y, z, w, v, ...) \
what(c, x, y, z, w, v) BK_ONE_OF_FOR_QUINT_CONST_EACH_7(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_NARG(...) \
BK_ONE_OF_FOR_QUINT_CONST_EACH_NARG_( \
__VA_ARGS__, BK_ONE_OF_FOR_QUINT_CONST_EACH_RSEQ_N())
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_NARG_(...) \
BK_ONE_OF_FOR_QUINT_CONST_EACH_ARG_N(__VA_ARGS__)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_ARG_N( \
_0, F0, F00, F000, F0000, _1, F1, F11, F111, F1111, _2, F2, F22, F222, \
F2222, _3, F3, F33, F333, F3333, _4, F4, F44, F444, F4444, _5, F5, F55, \
F555, F5555, _6, F6, F66, F666, F6666, _7, F7, F77, F777, F7777, N, ...) \
N
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_RSEQ_N() \
8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, \
3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
#define BK_ONE_OF_FOR_QUINT_CONST_EACH_(N, what, c, ...) \
BK_ONE_OF_CONCATENATE(BK_ONE_OF_FOR_QUINT_CONST_EACH_, N) \
(what, c, __VA_ARGS__)
#define BK_ONE_OF_FOR_QUINT_CONST_EACH(what, c, ...) \
BK_ONE_OF_FOR_QUINT_CONST_EACH_( \
BK_ONE_OF_FOR_QUINT_CONST_EACH_NARG(__VA_ARGS__), what, c, __VA_ARGS__)
/*
* Testing Macro Widgets
*/
// For double each
// #define FOO(x, y) hello123##x##y
// BK_ONE_OF_FOR_DOUBLE_EACH(FOO)
// BK_ONE_OF_FOR_DOUBLE_EACH(FOO, a, b)
// BK_ONE_OF_FOR_DOUBLE_EACH(FOO, a, b, c, d)
// BK_ONE_OF_FOR_DOUBLE_EACH(FOO, a, b, c, d, e, f)
// BK_ONE_OF_FOR_DOUBLE_EACH(FOO, a, b, c, d, e, f, g, h)
// For quint-const-each
// #define FOO(const, a,b,c,d,e) hello##a##b##c##d##e
// BK_ONE_OF_FOR_QUINT_CONST_EACH(FOO, const, a, b, c, d, e)
// BK_ONE_OF_FOR_QUINT_CONST_EACH(FOO, const, a1, b1, c1, d1, e1, a2, b2, c2,
// d2, e2)
// For double each after consuming the first param
// #define FOO(x, y) hello123##x##y
// #define CONSUMER(name, ...) \
// BK_ONE_OF_CONCATENATE(name , BK_ONE_OF_FOR_DOUBLE_EACH(FOO, __VA_ARGS__))
// CONSUMER(MyName, a, b, c, d)
// Send info from parent to child with no param
// #define CHILD(a, b) a , b , -(id)initWith##a ( a b, NSString * string)
// #define PARENT(secret, c) RUN (c, secret)
// #define RUN(x, y, z, secret) x woo secret y woo z
// PARENT(password, CHILD(a, b))
// Send info from parent to for_each child with no param
// #define CHILD(a, b) a , b, -(id)initWith##b ( a b, NSString * string), wow
// #define PARENT(secret, ...) \
// BK_ONE_OF_FOR_QUAD_CONST_EACH(RUN, secret, __VA_ARGS__)
// #define RUN(secret, x, y, z, w) x woo secret y woo z w
// PARENT(password, CHILD(a, b), CHILD(c, d), CHILD(e, f))
// PARENT(password, CHILD(a, b), CHILD(c, d), CHILD(e, f), CHILD(g, h))
#endif /* BKOneOf_h */
//
// BKOneOfTestCase.m
// BKOneOf
//
//
#import <XCTest/XCTest.h>
#import <Foundation/Foundation.h>
#import "BKOneOf.h"
// A simple ADT using only objects with nullability annotations
BK_ONE_OF(BKSchema,
BK_CASE(Object, NSString * _Nonnull, name, NSArray<NSString *>* _Nonnull, methods),
BK_CASE(String, NSString * _Nonnull, str);
)
typedef NSNumber *(^StrToNumberBlock)(NSString * str);
// An ADT using primitives for metadata
BK_ONE_OF(BKPrimBlock,
BK_CASE(Prim, NSInteger, i),
BK_CASE(Block, StrToNumberBlock, blk);
)
@interface BKOneOfTests : XCTestCase
@end
BK_ONE_OF_IMPL(BKSchema,
BK_CASE(Object, NSString * _Nonnull, name, NSArray<NSString *>* _Nonnull, methods),
BK_CASE(String, NSString * _Nonnull, str);
)
BK_ONE_OF_IMPL(BKPrimBlock,
BK_CASE(Prim, NSInteger, i),
BK_CASE(Block, StrToNumberBlock, blk);
)
@implementation BKOneOfTests
- (void)testOneOfUsage
{
__auto_type one = [[BKSchemaObject alloc] initWithname: @"fred" methods:@[@"a", @"b"]];
__auto_type two = [[BKSchemaString alloc] initWithstr:@"hello"];
[BKSchema match:one orObject:^id(BKSchemaObject * obj) {
XCTAssert([obj.name isEqualToString:@"fred"]);
} orString:^id(BKSchemaString * str) {
XCTFail(@"Wrong case (one)");
return nil;
}];
[BKSchema match:two orObject:^id(BKSchemaObject * obj) {
XCTFail(@"Wrong case (two)");
return nil;
} orString:^id(BKSchemaString * str) {
XCTAssert([str.str isEqualToString:@"hello"]);
}];
}
- (void)testOneOfPrimBlock
{
__auto_type blk = [[BKPrimBlockBlock alloc] initWithblk:^NSNumber *(NSString *str) {
NSLog(@"Hello %@", str);
return @1;
}];
__auto_type prim = [[BKPrimBlockPrim alloc] initWithi:4];
[BKPrimBlock match:prim orPrim:^id(BKPrimBlockPrim * p) {
XCTAssert(p.i == 4);
} orBlock:^id(BKPrimBlockBlock * blk) {
XCTFail(@"Wrong case (prim)");
return nil;
}];
[BKPrimBlock match:blk orPrim:^id(BKPrimBlockPrim * p) {
XCTFail(@"Wrong case (blk)");
return nil;
} orBlock:^id(BKPrimBlockBlock* blk) {
XCTAssert([blk.blk(@"fred") integerValue] == 1);
}];
}
@end
Copyright 2017 Brandon Kase
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment