123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- //
- // FLEXClassBuilder.m
- // FLEX
- //
- // Derived from MirrorKit.
- // Created by Tanner on 7/3/15.
- // Copyright (c) 2020 FLEX Team. All rights reserved.
- //
- #import "FLEXClassBuilder.h"
- #import "FLEXProperty.h"
- #import "FLEXMethodBase.h"
- #import "FLEXProtocol.h"
- #import <objc/runtime.h>
- #pragma mark FLEXClassBuilder
- @interface FLEXClassBuilder ()
- @property (nonatomic) NSString *name;
- @end
- @implementation FLEXClassBuilder
- - (id)init {
- [NSException
- raise:NSInternalInconsistencyException
- format:@"Class instance should not be created with -init"
- ];
- return nil;
- }
- #pragma mark Initializers
- + (instancetype)allocateClass:(NSString *)name {
- return [self allocateClass:name superclass:NSObject.class];
- }
- + (instancetype)allocateClass:(NSString *)name superclass:(Class)superclass {
- return [self allocateClass:name superclass:superclass extraBytes:0];
- }
- + (instancetype)allocateClass:(NSString *)name superclass:(Class)superclass extraBytes:(size_t)bytes {
- NSParameterAssert(name);
- return [[self alloc] initWithClass:objc_allocateClassPair(superclass, name.UTF8String, bytes)];
- }
- + (instancetype)allocateRootClass:(NSString *)name {
- NSParameterAssert(name);
- return [[self alloc] initWithClass:objc_allocateClassPair(Nil, name.UTF8String, 0)];
- }
- + (instancetype)builderForClass:(Class)cls {
- return [[self alloc] initWithClass:cls];
- }
- - (id)initWithClass:(Class)cls {
- NSParameterAssert(cls);
-
- self = [super init];
- if (self) {
- _workingClass = cls;
- _name = NSStringFromClass(_workingClass);
- }
-
- return self;
- }
- - (NSString *)description {
- return [NSString stringWithFormat:@"<%@ name=%@, registered=%d>",
- NSStringFromClass(self.class), self.name, self.isRegistered];
- }
- #pragma mark Building
- - (NSArray *)addMethods:(NSArray *)methods {
- NSParameterAssert(methods.count);
-
- NSMutableArray *failed = [NSMutableArray new];
- for (FLEXMethodBase *m in methods) {
- if (!class_addMethod(self.workingClass, m.selector, m.implementation, m.typeEncoding.UTF8String)) {
- [failed addObject:m];
- }
- }
-
- return failed;
- }
- - (NSArray *)addProperties:(NSArray *)properties {
- NSParameterAssert(properties.count);
-
- NSMutableArray *failed = [NSMutableArray new];
- for (FLEXProperty *p in properties) {
- unsigned int pcount;
- objc_property_attribute_t *attributes = [p copyAttributesList:&pcount];
- if (!class_addProperty(self.workingClass, p.name.UTF8String, attributes, pcount)) {
- [failed addObject:p];
- }
- free(attributes);
- }
-
- return failed;
- }
- - (NSArray *)addProtocols:(NSArray *)protocols {
- NSParameterAssert(protocols.count);
-
- NSMutableArray *failed = [NSMutableArray new];
- for (FLEXProtocol *p in protocols) {
- if (!class_addProtocol(self.workingClass, p.objc_protocol)) {
- [failed addObject:p];
- }
- }
-
- return failed;
- }
- - (NSArray *)addIvars:(NSArray *)ivars {
- NSParameterAssert(ivars.count);
-
- NSMutableArray *failed = [NSMutableArray new];
- for (FLEXIvarBuilder *ivar in ivars) {
- if (!class_addIvar(self.workingClass, ivar.name.UTF8String, ivar.size, ivar.alignment, ivar.encoding.UTF8String)) {
- [failed addObject:ivar];
- }
- }
-
- return failed;
- }
- - (Class)registerClass {
- if (self.isRegistered) {
- [NSException raise:NSInternalInconsistencyException format:@"Class is already registered"];
- }
-
- objc_registerClassPair(self.workingClass);
- return self.workingClass;
- }
- - (BOOL)isRegistered {
- return objc_lookUpClass(self.name.UTF8String) != nil;
- }
- @end
- #pragma mark FLEXIvarBuilder
- @implementation FLEXIvarBuilder
- + (instancetype)name:(NSString *)name size:(size_t)size alignment:(uint8_t)alignment typeEncoding:(NSString *)encoding {
- return [[self alloc] initWithName:name size:size alignment:alignment typeEncoding:encoding];
- }
- - (id)initWithName:(NSString *)name size:(size_t)size alignment:(uint8_t)alignment typeEncoding:(NSString *)encoding {
- NSParameterAssert(name); NSParameterAssert(encoding);
- NSParameterAssert(size > 0); NSParameterAssert(alignment > 0);
-
- self = [super init];
- if (self) {
- _name = name;
- _encoding = encoding;
- _size = size;
- _alignment = alignment;
- }
-
- return self;
- }
- @end
|