//
//  YSRACSubscriptingAssignmentTrampoline.h
//  ReactiveObjC
//
//  Created by Josh Abernathy on 9/24/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "YSRACEXTKeyPathCoding.h"

@class YSRACSignal<__covariant ValueType>;

NS_ASSUME_NONNULL_BEGIN

/// Assigns a signal to an object property, automatically setting the given key
/// path on every `next`. When the signal completes, the binding is automatically
/// disposed of.
///
/// There are two different versions of this macro:
///
///  - YSRAC(TARGET, KEYPATH, NILVALUE) will bind the `KEYPATH` of `TARGET` to the
///    given signal. If the signal ever sends a `nil` value, the property will be
///    set to `NILVALUE` instead. `NILVALUE` may itself be `nil` for object
///    properties, but an NSValue should be used for primitive properties, to
///    avoid an exception if `nil` is sent (which might occur if an intermediate
///    object is set to `nil`).
///  - YSRAC(TARGET, KEYPATH) is the same as the above, but `NILVALUE` defaults to
///    `nil`.
///
/// See -[YSRACSignal setKeyPath:onObject:nilValue:] for more information about the
/// binding's semantics.
///
/// Examples
///
///  YSRAC(self, objectProperty) = objectSignal;
///  YSRAC(self, stringProperty, @"foobar") = stringSignal;
///  YSRAC(self, integerProperty, @42) = integerSignal;
///
/// WARNING: Under certain conditions, use of this macro can be thread-unsafe.
///          See the documentation of -setKeyPath:onObject:nilValue:.
#define YSRAC(TARGET, ...) \
    metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \
        (YSRAC_(TARGET, __VA_ARGS__, nil)) \
        (YSRAC_(TARGET, __VA_ARGS__))

/// Do not use this directly. Use the YSRAC macro above.
#define YSRAC_(TARGET, KEYPATH, NILVALUE) \
    [[YSRACSubscriptingAssignmentTrampoline alloc] initWithTarget:(TARGET) nilValue:(NILVALUE)][@keypath(TARGET, KEYPATH)]

@interface YSRACSubscriptingAssignmentTrampoline : NSObject

- (nullable instancetype)initWithTarget:(nullable id)target nilValue:(nullable id)nilValue;
- (void)setObject:(YSRACSignal *)signal forKeyedSubscript:(NSString *)keyPath;

@end

NS_ASSUME_NONNULL_END
