added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / RLMUtil.hpp
1 ////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2014 Realm Inc.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 ////////////////////////////////////////////////////////////////////////////
18
19 #import <Realm/RLMConstants.h>
20 #import <Realm/RLMOptionalBase.h>
21 #import <objc/runtime.h>
22
23 #import <realm/array.hpp>
24 #import <realm/binary_data.hpp>
25 #import <realm/string_data.hpp>
26 #import <realm/timestamp.hpp>
27 #import <realm/util/file.hpp>
28
29 namespace realm {
30     class Mixed;
31 }
32
33 @class RLMObjectSchema;
34 @class RLMProperty;
35
36 namespace realm {
37     class RealmFileException;
38 }
39
40 __attribute__((format(NSString, 1, 2)))
41 NSException *RLMException(NSString *fmt, ...);
42 NSException *RLMException(std::exception const& exception);
43
44 NSError *RLMMakeError(RLMError code, std::exception const& exception);
45 NSError *RLMMakeError(RLMError code, const realm::util::File::AccessError&);
46 NSError *RLMMakeError(RLMError code, const realm::RealmFileException&);
47 NSError *RLMMakeError(std::system_error const& exception);
48
49 void RLMSetErrorOrThrow(NSError *error, NSError **outError);
50
51 // returns if the object can be inserted as the given type
52 BOOL RLMIsObjectValidForProperty(id obj, RLMProperty *prop);
53 // throw an exception if the object is not a valid value for the property
54 void RLMValidateValueForProperty(id obj, RLMObjectSchema *objectSchema,
55                                  RLMProperty *prop, bool validateObjects=false);
56 BOOL RLMValidateValue(id value, RLMPropertyType type, bool optional, bool array,
57                       NSString *objectClassName);
58
59 void RLMThrowTypeError(id obj, RLMObjectSchema *objectSchema, RLMProperty *prop);
60
61 // gets default values for the given schema (+defaultPropertyValues)
62 // merges with native property defaults if Swift class
63 NSDictionary *RLMDefaultValuesForObjectSchema(RLMObjectSchema *objectSchema);
64
65 BOOL RLMIsDebuggerAttached();
66 BOOL RLMIsRunningInPlayground();
67
68 // C version of isKindOfClass
69 static inline BOOL RLMIsKindOfClass(Class class1, Class class2) {
70     while (class1) {
71         if (class1 == class2) return YES;
72         class1 = class_getSuperclass(class1);
73     }
74     return NO;
75 }
76
77 template<typename T>
78 static inline T *RLMDynamicCast(__unsafe_unretained id obj) {
79     if ([obj isKindOfClass:[T class]]) {
80         return obj;
81     }
82     return nil;
83 }
84
85 template<typename T>
86 static inline T RLMCoerceToNil(__unsafe_unretained T obj) {
87     if (static_cast<id>(obj) == NSNull.null) {
88         return nil;
89     }
90     else if (__unsafe_unretained auto optional = RLMDynamicCast<RLMOptionalBase>(obj)) {
91         return RLMCoerceToNil(optional.underlyingValue);
92     }
93     return obj;
94 }
95
96 // String conversion utilities
97 static inline NSString * RLMStringDataToNSString(realm::StringData stringData) {
98     static_assert(sizeof(NSUInteger) >= sizeof(size_t),
99                   "Need runtime overflow check for size_t to NSUInteger conversion");
100     if (stringData.is_null()) {
101         return nil;
102     }
103     else {
104         return [[NSString alloc] initWithBytes:stringData.data()
105                                         length:stringData.size()
106                                       encoding:NSUTF8StringEncoding];
107     }
108 }
109
110 static inline realm::StringData RLMStringDataWithNSString(__unsafe_unretained NSString *const string) {
111     static_assert(sizeof(size_t) >= sizeof(NSUInteger),
112                   "Need runtime overflow check for NSUInteger to size_t conversion");
113     return realm::StringData(string.UTF8String,
114                              [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
115 }
116
117 // Binary conversion utilities
118 static inline NSData *RLMBinaryDataToNSData(realm::BinaryData binaryData) {
119     return binaryData ? [NSData dataWithBytes:binaryData.data() length:binaryData.size()] : nil;
120 }
121
122 static inline realm::BinaryData RLMBinaryDataForNSData(__unsafe_unretained NSData *const data) {
123     // this is necessary to ensure that the empty NSData isn't treated by core as the null realm::BinaryData
124     // because data.bytes == 0 when data.length == 0
125     // the casting bit ensures that we create a data with a non-null pointer
126     auto bytes = static_cast<const char *>(data.bytes) ?: static_cast<char *>((__bridge void *)data);
127     return realm::BinaryData(bytes, data.length);
128 }
129
130 // Date conversion utilities
131 // These use the reference date and shift the seconds rather than just getting
132 // the time interval since the epoch directly to avoid losing sub-second precision
133 static inline NSDate *RLMTimestampToNSDate(realm::Timestamp ts) NS_RETURNS_RETAINED {
134     if (ts.is_null())
135         return nil;
136     auto timeInterval = ts.get_seconds() - NSTimeIntervalSince1970 + ts.get_nanoseconds() / 1'000'000'000.0;
137     return [[NSDate alloc] initWithTimeIntervalSinceReferenceDate:timeInterval];
138 }
139
140 static inline realm::Timestamp RLMTimestampForNSDate(__unsafe_unretained NSDate *const date) {
141     if (!date)
142         return {};
143     auto timeInterval = date.timeIntervalSinceReferenceDate;
144     if (isnan(timeInterval))
145         return {0, 0}; // Arbitrary choice
146
147     // Clamp dates that we can't represent as a Timestamp to the maximum value
148     if (timeInterval >= std::numeric_limits<int64_t>::max() - NSTimeIntervalSince1970)
149         return {std::numeric_limits<int64_t>::max(), 1'000'000'000 - 1};
150     if (timeInterval - NSTimeIntervalSince1970 < std::numeric_limits<int64_t>::min())
151         return {std::numeric_limits<int64_t>::min(), -1'000'000'000 + 1};
152
153     auto seconds = static_cast<int64_t>(timeInterval);
154     auto nanoseconds = static_cast<int32_t>((timeInterval - seconds) * 1'000'000'000.0);
155     seconds += static_cast<int64_t>(NSTimeIntervalSince1970);
156
157     // Seconds and nanoseconds have to have the same sign
158     if (nanoseconds < 0 && seconds > 0) {
159         nanoseconds += 1'000'000'000;
160         --seconds;
161     }
162     return {seconds, nanoseconds};
163 }
164
165 static inline NSUInteger RLMConvertNotFound(size_t index) {
166     return index == realm::not_found ? NSNotFound : index;
167 }
168
169 id RLMMixedToObjc(realm::Mixed const& value);
170
171 // Given a bundle identifier, return the base directory on the disk within which Realm database and support files should
172 // be stored.
173 NSString *RLMDefaultDirectoryForBundleIdentifier(NSString *bundleIdentifier);