mirror of
				https://github.com/SoPat712/YTLitePlus.git
				synced 2025-10-31 04:44:14 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			377 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
			
		
		
	
	
			377 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
| //
 | |
| //  FLEXPropertyAttributes.m
 | |
| //  FLEX
 | |
| //
 | |
| //  Derived from MirrorKit.
 | |
| //  Created by Tanner on 7/5/15.
 | |
| //  Copyright (c) 2020 FLEX Team. All rights reserved.
 | |
| //
 | |
| 
 | |
| #import "FLEXPropertyAttributes.h"
 | |
| #import "FLEXRuntimeUtility.h"
 | |
| #import "NSString+ObjcRuntime.h"
 | |
| #import "NSDictionary+ObjcRuntime.h"
 | |
| 
 | |
| 
 | |
| #pragma mark FLEXPropertyAttributes
 | |
| 
 | |
| @interface FLEXPropertyAttributes ()
 | |
| 
 | |
| @property (nonatomic) NSString *backingIvar;
 | |
| @property (nonatomic) NSString *typeEncoding;
 | |
| @property (nonatomic) NSString *oldTypeEncoding;
 | |
| @property (nonatomic) SEL customGetter;
 | |
| @property (nonatomic) SEL customSetter;
 | |
| @property (nonatomic) BOOL isReadOnly;
 | |
| @property (nonatomic) BOOL isCopy;
 | |
| @property (nonatomic) BOOL isRetained;
 | |
| @property (nonatomic) BOOL isNonatomic;
 | |
| @property (nonatomic) BOOL isDynamic;
 | |
| @property (nonatomic) BOOL isWeak;
 | |
| @property (nonatomic) BOOL isGarbageCollectable;
 | |
| 
 | |
| - (NSString *)buildFullDeclaration;
 | |
| 
 | |
| @end
 | |
| 
 | |
| @implementation FLEXPropertyAttributes
 | |
| @synthesize list = _list;
 | |
| 
 | |
| #pragma mark Initializers
 | |
| 
 | |
| + (instancetype)attributesForProperty:(objc_property_t)property {
 | |
|     return [self attributesFromDictionary:[NSDictionary attributesDictionaryForProperty:property]];
 | |
| }
 | |
| 
 | |
| + (instancetype)attributesFromDictionary:(NSDictionary *)attributes {
 | |
|     return [[self alloc] initWithAttributesDictionary:attributes];
 | |
| }
 | |
| 
 | |
| - (id)initWithAttributesDictionary:(NSDictionary *)attributes {
 | |
|     NSParameterAssert(attributes);
 | |
|     
 | |
|     self = [super init];
 | |
|     if (self) {
 | |
|         _dictionary           = attributes;
 | |
|         _string               = attributes.propertyAttributesString;
 | |
|         _count                = attributes.count;
 | |
|         _typeEncoding         = attributes[kFLEXPropertyAttributeKeyTypeEncoding];
 | |
|         _backingIvar          = attributes[kFLEXPropertyAttributeKeyBackingIvarName];
 | |
|         _oldTypeEncoding      = attributes[kFLEXPropertyAttributeKeyOldStyleTypeEncoding];
 | |
|         _customGetterString   = attributes[kFLEXPropertyAttributeKeyCustomGetter];
 | |
|         _customSetterString   = attributes[kFLEXPropertyAttributeKeyCustomSetter];
 | |
|         _customGetter         = NSSelectorFromString(_customGetterString);
 | |
|         _customSetter         = NSSelectorFromString(_customSetterString);
 | |
|         _isReadOnly           = attributes[kFLEXPropertyAttributeKeyReadOnly] != nil;
 | |
|         _isCopy               = attributes[kFLEXPropertyAttributeKeyCopy] != nil;
 | |
|         _isRetained           = attributes[kFLEXPropertyAttributeKeyRetain] != nil;
 | |
|         _isNonatomic          = attributes[kFLEXPropertyAttributeKeyNonAtomic] != nil;
 | |
|         _isWeak               = attributes[kFLEXPropertyAttributeKeyWeak] != nil;
 | |
|         _isGarbageCollectable = attributes[kFLEXPropertyAttributeKeyGarbageCollectable] != nil;
 | |
| 
 | |
|         _fullDeclaration = [self buildFullDeclaration];
 | |
|     }
 | |
|     
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| #pragma mark Misc
 | |
| 
 | |
| - (NSString *)description {
 | |
|     return [NSString
 | |
|         stringWithFormat:@"<%@ \"%@\", ivar=%@, readonly=%d, nonatomic=%d, getter=%@, setter=%@>",
 | |
|         NSStringFromClass(self.class),
 | |
|         self.string,
 | |
|         self.backingIvar ?: @"none",
 | |
|         self.isReadOnly,
 | |
|         self.isNonatomic,
 | |
|         NSStringFromSelector(self.customGetter) ?: @"none",
 | |
|         NSStringFromSelector(self.customSetter) ?: @"none"
 | |
|     ];
 | |
| }
 | |
| 
 | |
| - (objc_property_attribute_t *)copyAttributesList:(unsigned int *)attributesCount {
 | |
|     NSDictionary *attrs = self.string.propertyAttributes;
 | |
|     objc_property_attribute_t *propertyAttributes = malloc(attrs.count * sizeof(objc_property_attribute_t));
 | |
| 
 | |
|     if (attributesCount) {
 | |
|         *attributesCount = (unsigned int)attrs.count;
 | |
|     }
 | |
|     
 | |
|     NSUInteger i = 0;
 | |
|     for (NSString *key in attrs.allKeys) {
 | |
|         FLEXPropertyAttribute c = (FLEXPropertyAttribute)[key characterAtIndex:0];
 | |
|         switch (c) {
 | |
|             case FLEXPropertyAttributeTypeEncoding: {
 | |
|                 objc_property_attribute_t pa = {
 | |
|                     kFLEXPropertyAttributeKeyTypeEncoding.UTF8String,
 | |
|                     self.typeEncoding.UTF8String
 | |
|                 };
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|             case FLEXPropertyAttributeBackingIvarName: {
 | |
|                 objc_property_attribute_t pa = {
 | |
|                     kFLEXPropertyAttributeKeyBackingIvarName.UTF8String,
 | |
|                     self.backingIvar.UTF8String
 | |
|                 };
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|             case FLEXPropertyAttributeCopy: {
 | |
|                 objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyCopy.UTF8String, ""};
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|             case FLEXPropertyAttributeCustomGetter: {
 | |
|                 objc_property_attribute_t pa = {
 | |
|                     kFLEXPropertyAttributeKeyCustomGetter.UTF8String,
 | |
|                     NSStringFromSelector(self.customGetter).UTF8String ?: ""
 | |
|                 };
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|             case FLEXPropertyAttributeCustomSetter: {
 | |
|                 objc_property_attribute_t pa = {
 | |
|                     kFLEXPropertyAttributeKeyCustomSetter.UTF8String,
 | |
|                     NSStringFromSelector(self.customSetter).UTF8String ?: ""
 | |
|                 };
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|             case FLEXPropertyAttributeDynamic: {
 | |
|                 objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyDynamic.UTF8String, ""};
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|             case FLEXPropertyAttributeGarbageCollectible: {
 | |
|                 objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyGarbageCollectable.UTF8String, ""};
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|             case FLEXPropertyAttributeNonAtomic: {
 | |
|                 objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyNonAtomic.UTF8String, ""};
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|             case FLEXPropertyAttributeOldTypeEncoding: {
 | |
|                 objc_property_attribute_t pa = {
 | |
|                     kFLEXPropertyAttributeKeyOldStyleTypeEncoding.UTF8String,
 | |
|                     self.oldTypeEncoding.UTF8String ?: ""
 | |
|                 };
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|             case FLEXPropertyAttributeReadOnly: {
 | |
|                 objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyReadOnly.UTF8String, ""};
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|             case FLEXPropertyAttributeRetain: {
 | |
|                 objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyRetain.UTF8String, ""};
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|             case FLEXPropertyAttributeWeak: {
 | |
|                 objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyWeak.UTF8String, ""};
 | |
|                 propertyAttributes[i] = pa;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         i++;
 | |
|     }
 | |
|     
 | |
|     return propertyAttributes;
 | |
| }
 | |
| 
 | |
| - (objc_property_attribute_t *)list {
 | |
|     if (!_list) {
 | |
|         _list = [self copyAttributesList:nil];
 | |
|     }
 | |
| 
 | |
|     return _list;
 | |
| }
 | |
| 
 | |
| - (NSString *)buildFullDeclaration {
 | |
|     NSMutableString *decl = [NSMutableString new];
 | |
| 
 | |
|     [decl appendFormat:@"%@, ", _isNonatomic ? @"nonatomic" : @"atomic"];
 | |
|     [decl appendFormat:@"%@, ", _isReadOnly ? @"readonly" : @"readwrite"];
 | |
| 
 | |
|     BOOL noExplicitMemorySemantics = YES;
 | |
|     if (_isCopy) { noExplicitMemorySemantics = NO;
 | |
|         [decl appendString:@"copy, "];
 | |
|     }
 | |
|     if (_isRetained) { noExplicitMemorySemantics = NO;
 | |
|         [decl appendString:@"strong, "];
 | |
|     }
 | |
|     if (_isWeak) { noExplicitMemorySemantics = NO;
 | |
|         [decl appendString:@"weak, "];
 | |
|     }
 | |
| 
 | |
|     if ([_typeEncoding hasPrefix:@"@"] && noExplicitMemorySemantics) {
 | |
|         // *probably* strong if this is an object; strong is the default.
 | |
|         [decl appendString:@"strong, "];
 | |
|     } else if (noExplicitMemorySemantics) {
 | |
|         // *probably* assign if this is not an object
 | |
|         [decl appendString:@"assign, "];
 | |
|     }
 | |
| 
 | |
|     if (_customGetter) {
 | |
|         [decl appendFormat:@"getter=%@, ", NSStringFromSelector(_customGetter)];
 | |
|     }
 | |
|     if (_customSetter) {
 | |
|         [decl appendFormat:@"setter=%@, ", NSStringFromSelector(_customSetter)];
 | |
|     }
 | |
| 
 | |
|     [decl deleteCharactersInRange:NSMakeRange(decl.length-2, 2)];
 | |
|     return decl.copy;
 | |
| }
 | |
| 
 | |
| - (void)dealloc {
 | |
|     if (_list) {
 | |
|         free(_list);
 | |
|         _list = nil;
 | |
|     }
 | |
| }
 | |
| 
 | |
| #pragma mark Copying
 | |
| 
 | |
| - (id)copyWithZone:(NSZone *)zone {
 | |
|     return [[FLEXPropertyAttributes class] attributesFromDictionary:self.dictionary];
 | |
| }
 | |
| 
 | |
| - (id)mutableCopyWithZone:(NSZone *)zone {
 | |
|     return [[FLEXMutablePropertyAttributes class] attributesFromDictionary:self.dictionary];
 | |
| }
 | |
| 
 | |
| @end
 | |
| 
 | |
| 
 | |
| 
 | |
| #pragma mark FLEXMutablePropertyAttributes
 | |
| 
 | |
| @interface FLEXMutablePropertyAttributes ()
 | |
| @property (nonatomic) BOOL countDelta;
 | |
| @property (nonatomic) BOOL stringDelta;
 | |
| @property (nonatomic) BOOL dictDelta;
 | |
| @property (nonatomic) BOOL listDelta;
 | |
| @property (nonatomic) BOOL declDelta;
 | |
| @end
 | |
| 
 | |
| #define PropertyWithDeltaFlag(type, name, Name) @dynamic name; \
 | |
| - (void)set ## Name:(type)name { \
 | |
|     if (name != _ ## name) { \
 | |
|         _countDelta = _stringDelta = _dictDelta = _listDelta = _declDelta = YES; \
 | |
|         _ ## name = name; \
 | |
|     } \
 | |
| }
 | |
| 
 | |
| @implementation FLEXMutablePropertyAttributes
 | |
| 
 | |
| PropertyWithDeltaFlag(NSString *, backingIvar, BackingIvar);
 | |
| PropertyWithDeltaFlag(NSString *, typeEncoding, TypeEncoding);
 | |
| PropertyWithDeltaFlag(NSString *, oldTypeEncoding, OldTypeEncoding);
 | |
| PropertyWithDeltaFlag(SEL, customGetter, CustomGetter);
 | |
| PropertyWithDeltaFlag(SEL, customSetter, CustomSetter);
 | |
| PropertyWithDeltaFlag(BOOL, isReadOnly, IsReadOnly);
 | |
| PropertyWithDeltaFlag(BOOL, isCopy, IsCopy);
 | |
| PropertyWithDeltaFlag(BOOL, isRetained, IsRetained);
 | |
| PropertyWithDeltaFlag(BOOL, isNonatomic, IsNonatomic);
 | |
| PropertyWithDeltaFlag(BOOL, isDynamic, IsDynamic);
 | |
| PropertyWithDeltaFlag(BOOL, isWeak, IsWeak);
 | |
| PropertyWithDeltaFlag(BOOL, isGarbageCollectable, IsGarbageCollectable);
 | |
| 
 | |
| + (instancetype)attributes {
 | |
|     return [self new];
 | |
| }
 | |
| 
 | |
| - (void)setTypeEncodingChar:(char)type {
 | |
|     self.typeEncoding = [NSString stringWithFormat:@"%c", type];
 | |
| }
 | |
| 
 | |
| - (NSUInteger)count {
 | |
|     // Recalculate attribute count after mutations
 | |
|     if (self.countDelta) {
 | |
|         self.countDelta = NO;
 | |
|         _count = self.dictionary.count;
 | |
|     }
 | |
| 
 | |
|     return _count;
 | |
| }
 | |
| 
 | |
| - (objc_property_attribute_t *)list {
 | |
|     // Regenerate list after mutations
 | |
|     if (self.listDelta) {
 | |
|         self.listDelta = NO;
 | |
|         if (_list) {
 | |
|             free(_list);
 | |
|             _list = nil;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Super will generate the list if it isn't set
 | |
|     return super.list;
 | |
| }
 | |
| 
 | |
| - (NSString *)string {
 | |
|     // Regenerate string after mutations
 | |
|     if (self.stringDelta || !_string) {
 | |
|         self.stringDelta = NO;
 | |
|         _string = self.dictionary.propertyAttributesString;
 | |
|     }
 | |
| 
 | |
|     return _string;
 | |
| }
 | |
| 
 | |
| - (NSDictionary *)dictionary {
 | |
|     // Regenerate dictionary after mutations
 | |
|     if (self.dictDelta || !_dictionary) {
 | |
|         // _stringa nd _dictionary depend on each other,
 | |
|         // so we must generate ONE by hand using our properties.
 | |
|         // We arbitrarily choose to generate the dictionary.
 | |
|         NSMutableDictionary *attrs = [NSMutableDictionary new];
 | |
|         if (self.typeEncoding)
 | |
|             attrs[kFLEXPropertyAttributeKeyTypeEncoding]         = self.typeEncoding;
 | |
|         if (self.backingIvar)
 | |
|             attrs[kFLEXPropertyAttributeKeyBackingIvarName]      = self.backingIvar;
 | |
|         if (self.oldTypeEncoding)
 | |
|             attrs[kFLEXPropertyAttributeKeyOldStyleTypeEncoding] = self.oldTypeEncoding;
 | |
|         if (self.customGetter)
 | |
|             attrs[kFLEXPropertyAttributeKeyCustomGetter]         = NSStringFromSelector(self.customGetter);
 | |
|         if (self.customSetter)
 | |
|             attrs[kFLEXPropertyAttributeKeyCustomSetter]         = NSStringFromSelector(self.customSetter);
 | |
| 
 | |
|         if (self.isReadOnly)           attrs[kFLEXPropertyAttributeKeyReadOnly] = @YES;
 | |
|         if (self.isCopy)               attrs[kFLEXPropertyAttributeKeyCopy] = @YES;
 | |
|         if (self.isRetained)           attrs[kFLEXPropertyAttributeKeyRetain] = @YES;
 | |
|         if (self.isNonatomic)          attrs[kFLEXPropertyAttributeKeyNonAtomic] = @YES;
 | |
|         if (self.isDynamic)            attrs[kFLEXPropertyAttributeKeyDynamic] = @YES;
 | |
|         if (self.isWeak)               attrs[kFLEXPropertyAttributeKeyWeak] = @YES;
 | |
|         if (self.isGarbageCollectable) attrs[kFLEXPropertyAttributeKeyGarbageCollectable] = @YES;
 | |
| 
 | |
|         _dictionary = attrs.copy;
 | |
|     }
 | |
| 
 | |
|     return _dictionary;
 | |
| }
 | |
| 
 | |
| - (NSString *)fullDeclaration {
 | |
|     if (self.declDelta || !_fullDeclaration) {
 | |
|         _declDelta = NO;
 | |
|         _fullDeclaration = [self buildFullDeclaration];
 | |
|     }
 | |
| 
 | |
|     return _fullDeclaration;
 | |
| }
 | |
| 
 | |
| - (NSString *)customGetterString {
 | |
|     return _customGetter ? NSStringFromSelector(_customGetter) : nil;
 | |
| }
 | |
| 
 | |
| - (NSString *)customSetterString {
 | |
|     return _customSetter ? NSStringFromSelector(_customSetter) : nil;
 | |
| }
 | |
| 
 | |
| @end
 | 
