Explicitly convert an enum to an int (#19537)
[google-protobuf.git] / objectivec / GPBWellKnownTypes.m
blobd758702ce3bebf23c40b45a270bd47ada18e1573
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2015 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
8 // Importing sources here to force the linker to include our category methods in
9 // the static library. If these were compiled separately, the category methods
10 // below would be stripped by the linker.
12 #import "GPBWellKnownTypes.h"
14 #import "GPBUtilities.h"
15 #import "GPBUtilities_PackagePrivate.h"
17 NSString *const GPBWellKnownTypesErrorDomain = GPBNSStringifySymbol(GPBWellKnownTypesErrorDomain);
19 static NSString *kTypePrefixGoogleApisCom = @"type.googleapis.com/";
21 static NSTimeInterval TimeIntervalFromSecondsAndNanos(int64_t seconds, int32_t nanos) {
22   return seconds + (NSTimeInterval)nanos / 1e9;
25 static int32_t SecondsAndNanosFromTimeInterval(NSTimeInterval time, int64_t *outSeconds,
26                                                BOOL nanosMustBePositive) {
27   NSTimeInterval seconds;
28   NSTimeInterval nanos = modf(time, &seconds);
30   if (nanosMustBePositive && (nanos < 0)) {
31     // Per Timestamp.proto, nanos is non-negative and "Negative second values with
32     // fractions must still have non-negative nanos values that count forward in
33     // time. Must be from 0 to 999,999,999 inclusive."
34     --seconds;
35     nanos = 1.0 + nanos;
36   }
38   nanos *= 1e9;
39   *outSeconds = (int64_t)seconds;
40   return (int32_t)nanos;
43 static NSString *BuildTypeURL(NSString *typeURLPrefix, NSString *fullName) {
44   if (typeURLPrefix.length == 0) {
45     return fullName;
46   }
48   if ([typeURLPrefix hasSuffix:@"/"]) {
49     return [typeURLPrefix stringByAppendingString:fullName];
50   }
52   return [NSString stringWithFormat:@"%@/%@", typeURLPrefix, fullName];
55 static NSString *ParseTypeFromURL(NSString *typeURLString) {
56   NSRange range = [typeURLString rangeOfString:@"/" options:NSBackwardsSearch];
57   if ((range.location == NSNotFound) || (NSMaxRange(range) == typeURLString.length)) {
58     return nil;
59   }
60   NSString *result = [typeURLString substringFromIndex:range.location + 1];
61   return result;
64 #pragma mark - GPBTimestamp
66 @implementation GPBTimestamp (GBPWellKnownTypes)
68 - (instancetype)initWithDate:(NSDate *)date {
69   return [self initWithTimeIntervalSince1970:date.timeIntervalSince1970];
72 - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
73   if ((self = [super init])) {
74     int64_t seconds;
75     int32_t nanos = SecondsAndNanosFromTimeInterval(timeIntervalSince1970, &seconds, YES);
76     self.seconds = seconds;
77     self.nanos = nanos;
78   }
79   return self;
82 - (NSDate *)date {
83   return [NSDate dateWithTimeIntervalSince1970:self.timeIntervalSince1970];
86 - (void)setDate:(NSDate *)date {
87   self.timeIntervalSince1970 = date.timeIntervalSince1970;
90 - (NSTimeInterval)timeIntervalSince1970 {
91   return TimeIntervalFromSecondsAndNanos(self.seconds, self.nanos);
94 - (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
95   int64_t seconds;
96   int32_t nanos = SecondsAndNanosFromTimeInterval(timeIntervalSince1970, &seconds, YES);
97   self.seconds = seconds;
98   self.nanos = nanos;
101 @end
103 #pragma mark - GPBDuration
105 @implementation GPBDuration (GBPWellKnownTypes)
107 - (instancetype)initWithTimeInterval:(NSTimeInterval)timeInterval {
108   if ((self = [super init])) {
109     int64_t seconds;
110     int32_t nanos = SecondsAndNanosFromTimeInterval(timeInterval, &seconds, NO);
111     self.seconds = seconds;
112     self.nanos = nanos;
113   }
114   return self;
117 - (NSTimeInterval)timeInterval {
118   return TimeIntervalFromSecondsAndNanos(self.seconds, self.nanos);
121 - (void)setTimeInterval:(NSTimeInterval)timeInterval {
122   int64_t seconds;
123   int32_t nanos = SecondsAndNanosFromTimeInterval(timeInterval, &seconds, NO);
124   self.seconds = seconds;
125   self.nanos = nanos;
128 @end
130 #pragma mark - GPBAny
132 @implementation GPBAny (GBPWellKnownTypes)
134 + (instancetype)anyWithMessage:(GPBMessage *)message error:(NSError **)errorPtr {
135   return [self anyWithMessage:message typeURLPrefix:kTypePrefixGoogleApisCom error:errorPtr];
138 + (instancetype)anyWithMessage:(GPBMessage *)message
139                  typeURLPrefix:(NSString *)typeURLPrefix
140                          error:(NSError **)errorPtr {
141   return [[[self alloc] initWithMessage:message typeURLPrefix:typeURLPrefix
142                                   error:errorPtr] autorelease];
145 - (instancetype)initWithMessage:(GPBMessage *)message error:(NSError **)errorPtr {
146   return [self initWithMessage:message typeURLPrefix:kTypePrefixGoogleApisCom error:errorPtr];
149 - (instancetype)initWithMessage:(GPBMessage *)message
150                   typeURLPrefix:(NSString *)typeURLPrefix
151                           error:(NSError **)errorPtr {
152   self = [self init];
153   if (self) {
154     if (![self packWithMessage:message typeURLPrefix:typeURLPrefix error:errorPtr]) {
155       [self release];
156       self = nil;
157     }
158   }
159   return self;
162 - (BOOL)packWithMessage:(GPBMessage *)message error:(NSError **)errorPtr {
163   return [self packWithMessage:message typeURLPrefix:kTypePrefixGoogleApisCom error:errorPtr];
166 - (BOOL)packWithMessage:(GPBMessage *)message
167           typeURLPrefix:(NSString *)typeURLPrefix
168                   error:(NSError **)errorPtr {
169   NSString *fullName = [message descriptor].fullName;
170   if (fullName.length == 0) {
171     if (errorPtr) {
172       *errorPtr = [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
173                                       code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
174                                   userInfo:nil];
175     }
176     return NO;
177   }
178   if (errorPtr) {
179     *errorPtr = nil;
180   }
181   self.typeURL = BuildTypeURL(typeURLPrefix, fullName);
182   self.value = message.data;
183   return YES;
186 - (GPBMessage *)unpackMessageClass:(Class)messageClass error:(NSError **)errorPtr {
187   return [self unpackMessageClass:messageClass extensionRegistry:nil error:errorPtr];
190 - (nullable GPBMessage *)unpackMessageClass:(Class)messageClass
191                           extensionRegistry:(nullable id<GPBExtensionRegistry>)extensionRegistry
192                                       error:(NSError **)errorPtr {
193   NSString *fullName = [messageClass descriptor].fullName;
194   if (fullName.length == 0) {
195     if (errorPtr) {
196       *errorPtr = [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
197                                       code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
198                                   userInfo:nil];
199     }
200     return nil;
201   }
203   NSString *expectedFullName = ParseTypeFromURL(self.typeURL);
204   if ((expectedFullName == nil) || ![expectedFullName isEqual:fullName]) {
205     if (errorPtr) {
206       *errorPtr = [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
207                                       code:GPBWellKnownTypesErrorCodeTypeURLMismatch
208                                   userInfo:nil];
209     }
210     return nil;
211   }
213   return [messageClass parseFromData:self.value extensionRegistry:extensionRegistry error:errorPtr];
216 @end