aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/Source/Util
diff options
context:
space:
mode:
authorGravatar Gil <mcg@google.com>2017-10-03 08:55:22 -0700
committerGravatar GitHub <noreply@github.com>2017-10-03 08:55:22 -0700
commitbde743ed25166a0b320ae157bfb1d68064f531c9 (patch)
tree4dd7525d9df32fa5dbdb721d4b0d4f9b87f5e884 /Firestore/Source/Util
parentbf550507ffa8beee149383a5bf1e2363bccefbb4 (diff)
Release 4.3.0 (#327)
Initial release of Firestore at 0.8.0 Bump FirebaseCommunity to 0.1.3
Diffstat (limited to 'Firestore/Source/Util')
-rw-r--r--Firestore/Source/Util/FSTAssert.h77
-rw-r--r--Firestore/Source/Util/FSTAsyncQueryListener.h48
-rw-r--r--Firestore/Source/Util/FSTAsyncQueryListener.m50
-rw-r--r--Firestore/Source/Util/FSTClasses.h40
-rw-r--r--Firestore/Source/Util/FSTComparison.h66
-rw-r--r--Firestore/Source/Util/FSTComparison.m175
-rw-r--r--Firestore/Source/Util/FSTDispatchQueue.h58
-rw-r--r--Firestore/Source/Util/FSTDispatchQueue.m75
-rw-r--r--Firestore/Source/Util/FSTLogger.h34
-rw-r--r--Firestore/Source/Util/FSTLogger.m40
-rw-r--r--Firestore/Source/Util/FSTUsageValidation.h45
-rw-r--r--Firestore/Source/Util/FSTUsageValidation.m30
-rw-r--r--Firestore/Source/Util/FSTUtil.h31
-rw-r--r--Firestore/Source/Util/FSTUtil.m44
14 files changed, 813 insertions, 0 deletions
diff --git a/Firestore/Source/Util/FSTAssert.h b/Firestore/Source/Util/FSTAssert.h
new file mode 100644
index 0000000..77bbb1d
--- /dev/null
+++ b/Firestore/Source/Util/FSTAssert.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+// Fails the current Objective-C method if the given condition is false.
+//
+// Unlike NSAssert, this macro is never compiled out if assertions are disabled.
+#define FSTAssert(condition, format, ...) \
+ do { \
+ if (!(condition)) { \
+ FSTFail((format), ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+// Fails the current C function if the given condition is false.
+//
+// Unlike NSCAssert, this macro is never compiled out if assertions are disabled.
+#define FSTCAssert(condition, format, ...) \
+ do { \
+ if (!(condition)) { \
+ FSTCFail((format), ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+// Unconditionally fails the current Objective-C method.
+//
+// This macro fails by calling [[NSAssertionHandler currentHandler] handleFailureInMethod]. It
+// also calls abort(3) in order to make this macro appear to never return, even though the call
+// to handleFailureInMethod itself never returns.
+#define FSTFail(format, ...) \
+ do { \
+ NSString *_file = [NSString stringWithUTF8String:__FILE__]; \
+ NSString *_description = [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
+ [[NSAssertionHandler currentHandler] \
+ handleFailureInMethod:_cmd \
+ object:self \
+ file:_file \
+ lineNumber:__LINE__ \
+ description:@"FIRESTORE INTERNAL ASSERTION FAILED: %@", _description]; \
+ abort(); \
+ } while (0)
+
+// Unconditionally fails the current C function.
+//
+// This macro fails by calling [[NSAssertionHandler currentHandler] handleFailureInFunction]. It
+// also calls abort(3) in order to make this macro appear to never return, even though the call
+// to handleFailureInFunction itself never returns.
+#define FSTCFail(format, ...) \
+ do { \
+ NSString *_file = [NSString stringWithUTF8String:__FILE__]; \
+ NSString *_function = [NSString stringWithUTF8String:__PRETTY_FUNCTION__]; \
+ NSString *_description = [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
+ [[NSAssertionHandler currentHandler] \
+ handleFailureInFunction:_function \
+ file:_file \
+ lineNumber:__LINE__ \
+ description:@"FIRESTORE INTERNAL ASSERTION FAILED: %@", _description]; \
+ abort(); \
+ } while (0)
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTAsyncQueryListener.h b/Firestore/Source/Util/FSTAsyncQueryListener.h
new file mode 100644
index 0000000..0ff1551
--- /dev/null
+++ b/Firestore/Source/Util/FSTAsyncQueryListener.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FSTViewSnapshot.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class FSTDispatchQueue;
+@class FSTQueryListener;
+
+/**
+ * A wrapper class around FSTQueryListener that dispatches events asynchronously.
+ */
+@interface FSTAsyncQueryListener : NSObject
+
+- (instancetype)initWithDispatchQueue:(FSTDispatchQueue *)dispatchQueue
+ snapshotHandler:(FSTViewSnapshotHandler)snapshotHandler
+ NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ * Synchronously mutes the listener and raise no further events. This method is thread safe can be
+ * called from any queue.
+ */
+- (void)mute;
+
+/** Creates an asynchronous version of the provided snapshot handler. */
+- (FSTViewSnapshotHandler)asyncSnapshotHandler;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTAsyncQueryListener.m b/Firestore/Source/Util/FSTAsyncQueryListener.m
new file mode 100644
index 0000000..31951e1
--- /dev/null
+++ b/Firestore/Source/Util/FSTAsyncQueryListener.m
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FSTAsyncQueryListener.h"
+
+#import "FSTDispatchQueue.h"
+
+@implementation FSTAsyncQueryListener {
+ volatile BOOL _muted;
+ FSTViewSnapshotHandler _snapshotHandler;
+ FSTDispatchQueue *_dispatchQueue;
+}
+
+- (instancetype)initWithDispatchQueue:(FSTDispatchQueue *)dispatchQueue
+ snapshotHandler:(FSTViewSnapshotHandler)snapshotHandler {
+ if (self = [super init]) {
+ _dispatchQueue = dispatchQueue;
+ _snapshotHandler = snapshotHandler;
+ }
+ return self;
+}
+
+- (FSTViewSnapshotHandler)asyncSnapshotHandler {
+ return ^(FSTViewSnapshot *_Nullable snapshot, NSError *_Nullable error) {
+ [_dispatchQueue dispatchAsync:^{
+ if (!_muted) {
+ _snapshotHandler(snapshot, error);
+ }
+ }];
+ };
+}
+
+- (void)mute {
+ _muted = true;
+}
+
+@end
diff --git a/Firestore/Source/Util/FSTClasses.h b/Firestore/Source/Util/FSTClasses.h
new file mode 100644
index 0000000..77dca12
--- /dev/null
+++ b/Firestore/Source/Util/FSTClasses.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+// A convenience macro for unimplemented methods. Use as follows:
+//
+// @throw FSTAbstractMethodException(); // NOLINT
+#define FSTAbstractMethodException() \
+ [NSException exceptionWithName:NSInternalInconsistencyException \
+ reason:[NSString stringWithFormat:@"You must override %s in a subclass", \
+ __func__] \
+ userInfo:nil];
+
+// Declare a weak pointer to the given variable
+#define FSTWeakify(var) __weak typeof(var) fstWeakPointerTo##var = var;
+
+// Declare a strong pointer to a variable that's been FSTWeakified. This creates a shadow of the
+// original.
+#define FSTStrongify(var) \
+ _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\"") \
+ __strong typeof(var) var = fstWeakPointerTo##var; \
+ _Pragma("clang diagnostic pop")
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTComparison.h b/Firestore/Source/Util/FSTComparison.h
new file mode 100644
index 0000000..e6e57e6
--- /dev/null
+++ b/Firestore/Source/Util/FSTComparison.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Compares two NSStrings. */
+NSComparisonResult FSTCompareStrings(NSString *left, NSString *right);
+
+/** Compares two BOOLs. */
+NSComparisonResult FSTCompareBools(BOOL left, BOOL right);
+
+/** Compares two integers. */
+NSComparisonResult FSTCompareInts(int left, int right);
+
+/** Compares two int32_t. */
+NSComparisonResult FSTCompareInt32s(int32_t left, int32_t right);
+
+/** Compares two int64_t. */
+NSComparisonResult FSTCompareInt64s(int64_t left, int64_t right);
+
+/** Compares two NSUIntegers. */
+NSComparisonResult FSTCompareUIntegers(NSUInteger left, NSUInteger right);
+
+/** Compares two doubles (using Firestore semantics for NaN). */
+NSComparisonResult FSTCompareDoubles(double left, double right);
+
+/** Compares a double and an int64_t. */
+NSComparisonResult FSTCompareMixed(double doubleValue, int64_t longValue);
+
+/** Compare two NSData byte sequences. */
+NSComparisonResult FSTCompareBytes(NSData *left, NSData *right);
+
+/** A simple NSComparator for comparing NSNumber instances. */
+extern const NSComparator FSTNumberComparator;
+
+/** A simple NSComparator for comparing NSString instances. */
+extern const NSComparator FSTStringComparator;
+
+/**
+ * Compares the bitwise representation of two doubles, but normalizes NaN values. This is
+ * similar to what the backend and android clients do, including comparing -0.0 as not equal to 0.0.
+ */
+BOOL FSTDoubleBitwiseEquals(double left, double right);
+
+/**
+ * Computes a bitwise hash of a double, but normalizes NaN values, suitable for use when using
+ * FSTDoublesAreBitwiseEqual for equality.
+ */
+NSUInteger FSTDoubleBitwiseHash(double d);
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTComparison.m b/Firestore/Source/Util/FSTComparison.m
new file mode 100644
index 0000000..e4f4ccb
--- /dev/null
+++ b/Firestore/Source/Util/FSTComparison.m
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FSTComparison.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+union DoubleBits {
+ double d;
+ uint64_t bits;
+};
+
+const NSComparator FSTNumberComparator = ^NSComparisonResult(NSNumber *left, NSNumber *right) {
+ return [left compare:right];
+};
+
+const NSComparator FSTStringComparator = ^NSComparisonResult(NSString *left, NSString *right) {
+ return FSTCompareStrings(left, right);
+};
+
+NSComparisonResult FSTCompareStrings(NSString *left, NSString *right) {
+ // NOTE: NSLiteralSearch is necessary to compare the raw character codes. By default,
+ // precomposed characters are considered equivalent to their decomposed equivalents.
+ return [left compare:right options:NSLiteralSearch];
+}
+
+NSComparisonResult FSTCompareBools(BOOL left, BOOL right) {
+ if (!left) {
+ return right ? NSOrderedAscending : NSOrderedSame;
+ } else {
+ return right ? NSOrderedSame : NSOrderedDescending;
+ }
+}
+
+NSComparisonResult FSTCompareInts(int left, int right) {
+ if (left > right) {
+ return NSOrderedDescending;
+ }
+ if (right > left) {
+ return NSOrderedAscending;
+ }
+ return NSOrderedSame;
+}
+
+NSComparisonResult FSTCompareInt32s(int32_t left, int32_t right) {
+ if (left > right) {
+ return NSOrderedDescending;
+ }
+ if (right > left) {
+ return NSOrderedAscending;
+ }
+ return NSOrderedSame;
+}
+
+NSComparisonResult FSTCompareInt64s(int64_t left, int64_t right) {
+ if (left > right) {
+ return NSOrderedDescending;
+ }
+ if (right > left) {
+ return NSOrderedAscending;
+ }
+ return NSOrderedSame;
+}
+
+NSComparisonResult FSTCompareUIntegers(NSUInteger left, NSUInteger right) {
+ if (left > right) {
+ return NSOrderedDescending;
+ }
+ if (right > left) {
+ return NSOrderedAscending;
+ }
+ return NSOrderedSame;
+}
+
+NSComparisonResult FSTCompareDoubles(double left, double right) {
+ // NaN sorts equal to itself and before any other number.
+ if (left < right) {
+ return NSOrderedAscending;
+ } else if (left > right) {
+ return NSOrderedDescending;
+ } else if (left == right) {
+ return NSOrderedSame;
+ } else {
+ // One or both left and right is NaN.
+ if (isnan(left)) {
+ return isnan(right) ? NSOrderedSame : NSOrderedAscending;
+ } else {
+ return NSOrderedDescending;
+ }
+ }
+}
+
+static const double LONG_MIN_VALUE_AS_DOUBLE = (double)LLONG_MIN;
+static const double LONG_MAX_VALUE_AS_DOUBLE = (double)LLONG_MAX;
+
+NSComparisonResult FSTCompareMixed(double doubleValue, int64_t longValue) {
+ // LLONG_MIN has an exact representation as double, so to check for a value outside the range
+ // representable by long, we have to check for strictly less than LLONG_MIN. Note that this also
+ // handles negative infinity.
+ if (doubleValue < LONG_MIN_VALUE_AS_DOUBLE) {
+ return NSOrderedAscending;
+ }
+
+ // LLONG_MAX has no exact representation as double (casting as we've done makes 2^63, which is
+ // larger than LLONG_MAX), so consider any value greater than or equal to the threshold to be out
+ // of range. This also handles positive infinity.
+ if (doubleValue >= LONG_MAX_VALUE_AS_DOUBLE) {
+ return NSOrderedDescending;
+ }
+
+ // In Firestore NaN is defined to compare before all other numbers.
+ if (isnan(doubleValue)) {
+ return NSOrderedAscending;
+ }
+
+ int64_t doubleAsLong = (int64_t)doubleValue;
+ NSComparisonResult cmp = FSTCompareInt64s(doubleAsLong, longValue);
+ if (cmp != NSOrderedSame) {
+ return cmp;
+ }
+
+ // At this point the long representations are equal but this could be due to rounding.
+ double longAsDouble = (double)longValue;
+ return FSTCompareDoubles(doubleValue, longAsDouble);
+}
+
+NSComparisonResult FSTCompareBytes(NSData *left, NSData *right) {
+ NSUInteger minLength = MIN(left.length, right.length);
+ int result = memcmp(left.bytes, right.bytes, minLength);
+ if (result < 0) {
+ return NSOrderedAscending;
+ } else if (result > 0) {
+ return NSOrderedDescending;
+ } else if (left.length < right.length) {
+ return NSOrderedAscending;
+ } else if (left.length > right.length) {
+ return NSOrderedDescending;
+ } else {
+ return NSOrderedSame;
+ }
+}
+
+/** Helper to normalize a double and then return the raw bits as a uint64_t. */
+uint64_t FSTDoubleBits(double d) {
+ if (isnan(d)) {
+ d = NAN;
+ }
+ union DoubleBits converter = {.d = d};
+ return converter.bits;
+}
+
+BOOL FSTDoubleBitwiseEquals(double left, double right) {
+ return FSTDoubleBits(left) == FSTDoubleBits(right);
+}
+
+NSUInteger FSTDoubleBitwiseHash(double d) {
+ uint64_t bits = FSTDoubleBits(d);
+ // Note that x ^ (x >> 32) works fine for both 32 and 64 bit definitions of NSUInteger
+ return (((NSUInteger)bits) ^ (NSUInteger)(bits >> 32));
+}
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTDispatchQueue.h b/Firestore/Source/Util/FSTDispatchQueue.h
new file mode 100644
index 0000000..da6b3fe
--- /dev/null
+++ b/Firestore/Source/Util/FSTDispatchQueue.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FSTDispatchQueue : NSObject
+
+/** Creates and returns an FSTDispatchQueue wrapping the specified dispatch_queue_t. */
++ (instancetype)queueWith:(dispatch_queue_t)dispatchQueue;
+
+- (instancetype)init __attribute__((unavailable("Use static constructor method.")));
+
+/**
+ * Asserts that we are already running on this queue (actually, we can only verify that the
+ * queue's label is the same, but hopefully that's good enough.)
+ */
+- (void)verifyIsCurrentQueue;
+
+/**
+ * Same as dispatch_async() except it asserts that we're not already on the queue, since this
+ * generally indicates a bug (and can lead to re-ordering of operations, etc).
+ *
+ * @param block The block to run.
+ */
+- (void)dispatchAsync:(void (^)())block;
+
+/**
+ * Unlike dispatchAsync: this method does not require you to dispatch to a different queue than
+ * the current one (thus it is equivalent to a raw dispatch_async()).
+ *
+ * This is useful, e.g. for dispatching to the user's queue directly from user API call (in which
+ * case we don't know if we're already on the user's queue or not).
+ *
+ * @param block The block to run.
+ */
+- (void)dispatchAsyncAllowingSameQueue:(void (^)())block;
+
+/** The underlying wrapped dispatch_queue_t */
+@property(nonatomic, strong, readonly) dispatch_queue_t queue;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTDispatchQueue.m b/Firestore/Source/Util/FSTDispatchQueue.m
new file mode 100644
index 0000000..8d55d28
--- /dev/null
+++ b/Firestore/Source/Util/FSTDispatchQueue.m
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "FSTAssert.h"
+#import "FSTDispatchQueue.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FSTDispatchQueue ()
+- (instancetype)initWithQueue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER;
+@end
+
+@implementation FSTDispatchQueue
+
++ (instancetype)queueWith:(dispatch_queue_t)dispatchQueue {
+ return [[FSTDispatchQueue alloc] initWithQueue:dispatchQueue];
+}
+
+- (instancetype)initWithQueue:(dispatch_queue_t)queue {
+ if (self = [super init]) {
+ _queue = queue;
+ }
+ return self;
+}
+
+- (void)verifyIsCurrentQueue {
+ FSTAssert([self onTargetQueue],
+ @"We are running on the wrong dispatch queue. Expected '%@' Actual: '%@'",
+ [self targetQueueLabel], [self currentQueueLabel]);
+}
+
+- (void)dispatchAsync:(void (^)())block {
+ FSTAssert(![self onTargetQueue],
+ @"dispatchAsync called when we are already running on target dispatch queue '%@'",
+ [self targetQueueLabel]);
+
+ dispatch_async(self.queue, block);
+}
+
+- (void)dispatchAsyncAllowingSameQueue:(void (^)())block {
+ dispatch_async(self.queue, block);
+}
+
+#pragma mark - Private Methods
+
+- (NSString *)currentQueueLabel {
+ return [NSString stringWithUTF8String:dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)];
+}
+
+- (NSString *)targetQueueLabel {
+ return [NSString stringWithUTF8String:dispatch_queue_get_label(self.queue)];
+}
+
+- (BOOL)onTargetQueue {
+ return [[self currentQueueLabel] isEqualToString:[self targetQueueLabel]];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTLogger.h b/Firestore/Source/Util/FSTLogger.h
new file mode 100644
index 0000000..699570a
--- /dev/null
+++ b/Firestore/Source/Util/FSTLogger.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Logs to NSLog if [FIRFirestore isLoggingEnabled] is YES. */
+void FSTLog(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2);
+
+void FSTWarn(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTLogger.m b/Firestore/Source/Util/FSTLogger.m
new file mode 100644
index 0000000..396c788
--- /dev/null
+++ b/Firestore/Source/Util/FSTLogger.m
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FSTLogger.h"
+
+#import "FIRFirestore+Internal.h"
+#import "FIRLogger.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+void FSTLog(NSString *format, ...) {
+ if ([FIRFirestore isLoggingEnabled]) {
+ va_list args;
+ va_start(args, format);
+ FIRLogBasic(FIRLoggerLevelDebug, kFIRLoggerFirestore, @"I-FST000001", format, args);
+ va_end(args);
+ }
+}
+
+void FSTWarn(NSString *format, ...) {
+ va_list args;
+ va_start(args, format);
+ FIRLogBasic(FIRLoggerLevelWarning, kFIRLoggerFirestore, @"I-FST000001", format, args);
+ va_end(args);
+}
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTUsageValidation.h b/Firestore/Source/Util/FSTUsageValidation.h
new file mode 100644
index 0000000..a80dafa
--- /dev/null
+++ b/Firestore/Source/Util/FSTUsageValidation.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Helper for creating a general exception for invalid usage of an API. */
+NSException *FSTInvalidUsage(NSString *exceptionName, NSString *format, ...);
+
+/**
+ * Macro to throw exceptions in response to API usage errors. Avoids the lint warning you usually
+ * get when using @throw and (unlike a function) doesn't trigger warnings about not all codepaths
+ * returning a value.
+ *
+ * Exceptions should only be used for programmer errors made by consumers of the SDK, e.g.
+ * invalid method arguments.
+ *
+ * For recoverable runtime errors, use NSError**.
+ * For internal programming errors, use FSTFail().
+ */
+#define FSTThrowInvalidUsage(exceptionName, format, ...) \
+ do { \
+ @throw FSTInvalidUsage(exceptionName, format, ##__VA_ARGS__); \
+ } while (0)
+
+#define FSTThrowInvalidArgument(format, ...) \
+ do { \
+ @throw FSTInvalidUsage(@"FIRInvalidArgumentException", format, ##__VA_ARGS__); \
+ } while (0)
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTUsageValidation.m b/Firestore/Source/Util/FSTUsageValidation.m
new file mode 100644
index 0000000..82128f4
--- /dev/null
+++ b/Firestore/Source/Util/FSTUsageValidation.m
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+NSException *FSTInvalidUsage(NSString *exceptionName, NSString *format, ...) {
+ va_list arg_list;
+ va_start(arg_list, format);
+ NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list];
+ va_end(arg_list);
+
+ return [[NSException alloc] initWithName:exceptionName reason:formattedString userInfo:nil];
+}
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTUtil.h b/Firestore/Source/Util/FSTUtil.h
new file mode 100644
index 0000000..3985d10
--- /dev/null
+++ b/Firestore/Source/Util/FSTUtil.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FSTUtil : NSObject
+
+/** Generates a random double between 0 and 1. */
++ (double)randomDouble;
+
+/** Generates a random ID suitable for use as a document ID. */
++ (NSString *)autoID;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/Util/FSTUtil.m b/Firestore/Source/Util/FSTUtil.m
new file mode 100644
index 0000000..d14c429
--- /dev/null
+++ b/Firestore/Source/Util/FSTUtil.m
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FSTUtil.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+static const double kArc4RandomMax = 0x100000000;
+
+static const int kAutoIDLength = 20;
+static NSString *const kAutoIDAlphabet =
+ @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+@implementation FSTUtil
+
++ (double)randomDouble {
+ return ((double)arc4random() / kArc4RandomMax);
+}
+
++ (NSString *)autoID {
+ unichar autoID[kAutoIDLength];
+ for (int i = 0; i < kAutoIDLength; i++) {
+ uint32_t randIndex = arc4random_uniform((uint32_t)kAutoIDAlphabet.length);
+ autoID[i] = [kAutoIDAlphabet characterAtIndex:randIndex];
+ }
+ return [NSString stringWithCharacters:autoID length:kAutoIDLength];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END