Source/TNLAttemptMetaData.m (129 lines of code) (raw):

// // TNLAttemptMetaData.m // TwitterNetworkLayer // // Created on 1/16/15. // Copyright © 2020 Twitter. All rights reserved. // #import "TNLAttemptMetaData_Project.h" NS_ASSUME_NONNULL_BEGIN static NSString * const kMetaDataDictionaryKey = @"metaDataDictionary"; static NSString * const kFinalKey = @"final"; @interface TNLAttemptMetaData () { NSDictionary<NSString *, id> *_metaDataDictionary; BOOL _final; } @end @implementation TNLAttemptMetaData - (instancetype)initWithMetaDataDictionary:(nullable NSDictionary<NSString *, id> *)dictionary { if (self = [super init]) { _final = NO; _metaDataDictionary = [dictionary mutableCopy] ?: [NSMutableDictionary dictionary]; } return self; } - (instancetype)init { return [self initWithMetaDataDictionary:nil]; } - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { if (self = [super init]) { _final = [aDecoder decodeBoolForKey:kFinalKey]; NSDictionary *metaDataDictionary = [aDecoder decodeObjectOfClass:[NSDictionary class] forKey:kMetaDataDictionaryKey]; _metaDataDictionary = (_final) ? [metaDataDictionary copy] : [metaDataDictionary mutableCopy]; } return self; } - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:[_metaDataDictionary copy] forKey:kMetaDataDictionaryKey]; [aCoder encodeBool:_final forKey:kFinalKey]; } + (BOOL)supportsSecureCoding { return YES; } - (NSUInteger)hash { return _metaDataDictionary.hash; } - (BOOL)isEqual:(id)object { if (self == object) { return YES; } if ([object isKindOfClass:[TNLAttemptMetaData class]]) { return [_metaDataDictionary isEqualToDictionary:[object metaDataDictionary]]; } return NO; } - (NSString *)description { return [NSString stringWithFormat:@"<%@ %p: %@>", NSStringFromClass([self class]), self, _metaDataDictionary]; } - (NSDictionary *)metaDataDictionary { return _metaDataDictionary; } - (void)finalizeMetaData { if (_final) { return; } _final = YES; _metaDataDictionary = [_metaDataDictionary copy]; } - (NSDictionary<NSString *, id> *)dictionaryDescription { NSMutableDictionary *d = [[NSMutableDictionary alloc] initWithCapacity:_metaDataDictionary.count]; [_metaDataDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) { d[key] = obj; return; } if ([obj isKindOfClass:[NSData class]]) { const NSUInteger length = [(NSData *)obj length]; if (length <= 256) { d[key] = [(NSData *)obj base64EncodedStringWithOptions:0]; } else { d[key] = [NSString stringWithFormat:@"NSData: %lu bytes", (unsigned long)length]; } return; } // other types, just skip }]; return d; } @end // Helper macros for coding & printing object; saves us from key & value name typos. #define OBJECT_FIELD(field, fieldUpper, type) \ - (nullable type *)field \ { \ return _metaDataDictionary[@#field]; \ } \ - (void)set##fieldUpper:(nullable type *)field \ { \ if (field == nil) { \ [(NSMutableDictionary *)_metaDataDictionary removeObjectForKey:@#field]; \ } else { \ ((NSMutableDictionary *)_metaDataDictionary)[@#field] = [field copy]; \ } \ } \ - (BOOL)has##fieldUpper \ { \ return _metaDataDictionary[@#field] != nil; \ } \ #define PRIMITIVE_FIELD(field, fieldUpper, type, getter) \ - (type)field \ { \ return [_metaDataDictionary[@#field] getter]; \ } \ - (void)set##fieldUpper:(type)field \ { \ ((NSMutableDictionary *)_metaDataDictionary)[@#field] = @(field); \ } \ - (BOOL)has##fieldUpper \ { \ return _metaDataDictionary[@#field] != nil; \ } \ @implementation TNLAttemptMetaData (HTTP) // See TNLAttemptMetadata_Project.h for list of fields. HTTP_FIELDS() @end #undef OBJECT_FIELD #undef PRIMITIVE_FIELD NS_ASSUME_NONNULL_END