Update Cocoapods.
This commit is contained in:
parent
24b0c88968
commit
71a3d8c660
@ -49,16 +49,16 @@ PODS:
|
||||
- Mantle (2.1.0):
|
||||
- Mantle/extobjc (= 2.1.0)
|
||||
- Mantle/extobjc (2.1.0)
|
||||
- PromiseKit (6.5.2):
|
||||
- PromiseKit/CorePromise (= 6.5.2)
|
||||
- PromiseKit/Foundation (= 6.5.2)
|
||||
- PromiseKit/UIKit (= 6.5.2)
|
||||
- PromiseKit/CorePromise (6.5.2)
|
||||
- PromiseKit/Foundation (6.5.2):
|
||||
- PromiseKit (6.5.3):
|
||||
- PromiseKit/CorePromise (= 6.5.3)
|
||||
- PromiseKit/Foundation (= 6.5.3)
|
||||
- PromiseKit/UIKit (= 6.5.3)
|
||||
- PromiseKit/CorePromise (6.5.3)
|
||||
- PromiseKit/Foundation (6.5.3):
|
||||
- PromiseKit/CorePromise
|
||||
- PromiseKit/UIKit (6.5.2):
|
||||
- PromiseKit/UIKit (6.5.3):
|
||||
- PromiseKit/CorePromise
|
||||
- PureLayout (3.0.2)
|
||||
- PureLayout (3.1.4)
|
||||
- Reachability (3.2)
|
||||
- SAMKeychain (1.5.3)
|
||||
- SignalCoreKit (1.0.0):
|
||||
@ -119,8 +119,8 @@ PODS:
|
||||
- SQLCipher/common (3.4.2)
|
||||
- SQLCipher/standard (3.4.2):
|
||||
- SQLCipher/common
|
||||
- SSZipArchive (2.1.3)
|
||||
- SwiftProtobuf (1.1.2)
|
||||
- SSZipArchive (2.1.4)
|
||||
- SwiftProtobuf (1.2.0)
|
||||
- YapDatabase/SQLCipher (3.1.1):
|
||||
- YapDatabase/SQLCipher/Core (= 3.1.1)
|
||||
- YapDatabase/SQLCipher/Extensions (= 3.1.1)
|
||||
@ -265,10 +265,10 @@ CHECKOUT OPTIONS:
|
||||
:commit: 3e0c2371d125f2d3db26daa498d5d436961b1795
|
||||
:git: https://github.com/signalapp/HKDFKit.git
|
||||
SignalCoreKit:
|
||||
:commit: b60dc7d58dfc93ca6eafbb3ea5300c6d67ebc69a
|
||||
:commit: a84ec7ed6c13b079a7e03cb09c79b5452086d1e7
|
||||
:git: https://github.com/signalapp/SignalCoreKit.git
|
||||
SignalMetadataKit:
|
||||
:commit: 8a586363921b4546bea99b07c06bf5c93eab7973
|
||||
:commit: 56f28fc3a6e35d548d034ef7d0009f233ca0aa62
|
||||
:git: https://github.com/signalapp/SignalMetadataKit
|
||||
SocketRocket:
|
||||
:commit: 9f9563a83cd8960503074aa8de72206f83fb7a69
|
||||
@ -289,8 +289,8 @@ SPEC CHECKSUMS:
|
||||
HKDFKit: 3b6dbbb9d59c221cc6c52c3aa915700cbf24e376
|
||||
libPhoneNumber-iOS: e444379ac18bbfbdefad571da735b2cd7e096caa
|
||||
Mantle: 2fa750afa478cd625a94230fbf1c13462f29395b
|
||||
PromiseKit: 27c1601bfb73405871b805bcb8cf7e55c4dad3db
|
||||
PureLayout: 4d550abe49a94f24c2808b9b95db9131685fe4cd
|
||||
PromiseKit: c609029bdd801f792551a504c695c7d3098b42cd
|
||||
PureLayout: f08c01b8dec00bb14a1fefa3de4c7d9c265df85e
|
||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
||||
SignalCoreKit: c2d8132cdedb95d35eb2f8ae7eac0957695d0a8b
|
||||
@ -298,8 +298,8 @@ SPEC CHECKSUMS:
|
||||
SignalServiceKit: 80d774c32b22567682f63c36bf9da265d82083bb
|
||||
SocketRocket: dbb1554b8fc288ef8ef370d6285aeca7361be31e
|
||||
SQLCipher: f9fcf29b2e59ced7defc2a2bdd0ebe79b40d4990
|
||||
SSZipArchive: 51a800ebb77f95a8329b6ced1faaff394b47f509
|
||||
SwiftProtobuf: 7147b8ec19c8c0694a45155d989ea9e6dedaf51f
|
||||
SSZipArchive: 41455d4b8d2b6ab93990820b50dc697c2554a322
|
||||
SwiftProtobuf: 91a9856079044ef4ec762b2344c763cd9e5a73c1
|
||||
YapDatabase: b418a4baa6906e8028748938f9159807fd039af4
|
||||
YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -59,6 +59,11 @@ For Carthage, SwiftPM, etc., or for instructions when using older Swifts or
|
||||
Xcodes, see our [Installation Guide]. We
|
||||
recommend [Carthage](https://github.com/Carthage/Carthage).
|
||||
|
||||
# PromiseKit is Thousands of Hours of Work
|
||||
|
||||
This project is a labor of love: to the pursuit of making quality, reusable, compartmentalized software that has general use
|
||||
to the wider development community. It is a widely used project where every change, fix and plan can have serious repercussions to its users and thus must be carefully considered. If you use PromiseKit in your apps, please consider supporting its development with a donation to [my patreon](https://www.patreon.com/mxcl). Thank you.
|
||||
|
||||
# Documentation
|
||||
|
||||
* Handbook
|
||||
|
||||
@ -5,7 +5,7 @@ enum Sealant<R> {
|
||||
case resolved(R)
|
||||
}
|
||||
|
||||
class Handlers<R> {
|
||||
final class Handlers<R> {
|
||||
var bodies: [(R) -> Void] = []
|
||||
func append(_ item: @escaping(R) -> Void) { bodies.append(item) }
|
||||
}
|
||||
@ -17,7 +17,7 @@ class Box<T> {
|
||||
func seal(_: T) {}
|
||||
}
|
||||
|
||||
class SealedBox<T>: Box<T> {
|
||||
final class SealedBox<T>: Box<T> {
|
||||
let value: T
|
||||
|
||||
init(value: T) {
|
||||
@ -29,7 +29,7 @@ class SealedBox<T>: Box<T> {
|
||||
}
|
||||
}
|
||||
|
||||
class EmptyBox<T>: Box<T> {
|
||||
final class EmptyBox<T>: Box<T> {
|
||||
private var sealant = Sealant<T>.pending(.init())
|
||||
private let barrier = DispatchQueue(label: "org.promisekit.barrier", attributes: .concurrent)
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import Dispatch
|
||||
A `Guarantee` is a functional abstraction around an asynchronous operation that cannot error.
|
||||
- See: `Thenable`
|
||||
*/
|
||||
public class Guarantee<T>: Thenable {
|
||||
public final class Guarantee<T>: Thenable {
|
||||
let box: Box<T>
|
||||
|
||||
fileprivate init(box: SealedBox<T>) {
|
||||
|
||||
@ -5,7 +5,7 @@ import Dispatch
|
||||
A `Promise` is a functional abstraction around a failable asynchronous operation.
|
||||
- See: `Thenable`
|
||||
*/
|
||||
public class Promise<T>: Thenable, CatchMixin {
|
||||
public final class Promise<T>: Thenable, CatchMixin {
|
||||
let box: Box<Result<T>>
|
||||
|
||||
fileprivate init(box: SealedBox<Result<T>>) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/// An object for resolving promises
|
||||
public class Resolver<T> {
|
||||
public final class Resolver<T> {
|
||||
let box: Box<Result<T>>
|
||||
|
||||
init(_ box: Box<Result<T>>) {
|
||||
|
||||
@ -69,6 +69,29 @@ PL__ASSUME_NONNULL_BEGIN
|
||||
|
||||
#endif /* PL__PureLayout_MinBaseSDK_iOS_8_0 */
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#pragma mark Pin Edges to SafeArea
|
||||
|
||||
/** Pins the given edge of the view to the same edge of its superview anchor/edge. */
|
||||
- (NSLayoutConstraint *)API_AVAILABLE(ios(9.0), tvos(9.0))autoPinEdgeToSuperviewSafeArea:(ALEdge)edge;
|
||||
|
||||
/** Pins the given edge of the view to the same edge of its superview anchor/edge with an inset. */
|
||||
- (NSLayoutConstraint *)API_AVAILABLE(ios(9.0), tvos(9.0))autoPinEdgeToSuperviewSafeArea:(ALEdge)edge withInset:(CGFloat)inset;
|
||||
|
||||
/** Pins the given edge of the view to the same edge of its superview anchor/edge with an inset as a maximum or minimum. */
|
||||
- (NSLayoutConstraint *)API_AVAILABLE(ios(9.0), tvos(9.0))autoPinEdgeToSuperviewSafeArea:(ALEdge)edge withInset:(CGFloat)inset relation:(NSLayoutRelation)relation;
|
||||
|
||||
/** Pins the edges of the view to the edges of its superview anchors/edge. */
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)API_AVAILABLE(ios(9.0), tvos(9.0))autoPinEdgesToSuperviewSafeArea;
|
||||
|
||||
/** Pins the edges of the view to the edges of its superview anchors/edges with the given edge insets. */
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)API_AVAILABLE(ios(9.0), tvos(9.0))autoPinEdgesToSuperviewSafeAreaWithInsets:(ALEdgeInsets)insets;
|
||||
|
||||
/** Pins 3 of the 4 edges of the view to the edges of its superview anchor/edge with the given edge insets, excluding one edge. */
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)API_AVAILABLE(ios(9.0), tvos(9.0))autoPinEdgesToSuperviewSafeAreaWithInsets:(ALEdgeInsets)insets excludingEdge:(ALEdge)edge;
|
||||
|
||||
#endif /* TARGET_OS_IPHONE */
|
||||
|
||||
#pragma mark Pin Edges to Superview
|
||||
|
||||
@ -95,12 +118,18 @@ PL__ASSUME_NONNULL_BEGIN
|
||||
/** Pins the given edge of the view to the corresponding margin of its superview. Available in iOS 8.0 and later. */
|
||||
- (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge;
|
||||
|
||||
/** Pins the given edge of a view to the corresponding margin of its superview with an inset.*/
|
||||
- (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge withInset:(CGFloat)inset;
|
||||
|
||||
/** Pins the given edge of the view to the corresponding margin of its superview as a maximum or minimum. Available in iOS 8.0 and later. */
|
||||
- (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge relation:(NSLayoutRelation)relation;
|
||||
|
||||
/** Pins the edges of the view to the margins of its superview. Available in iOS 8.0 and later. */
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewMargins;
|
||||
|
||||
/** Pins the edges of the view to the margins of its superview with the given edge insets. Available in iOS 8.0 and later.*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewMarginsWithInsets:(ALEdgeInsets)insets;
|
||||
|
||||
/** Pins 3 of the 4 edges of the view to the margins of its superview excluding one edge. Available in iOS 8.0 and later. */
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewMarginsExcludingEdge:(ALEdge)edge;
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoCenterInSuperview
|
||||
{
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
[constraints addObject:[self autoAlignAxisToSuperviewAxis:ALAxisHorizontal]];
|
||||
[constraints addObject:[self autoAlignAxisToSuperviewAxis:ALAxisVertical]];
|
||||
return constraints;
|
||||
@ -109,7 +109,7 @@
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoCenterInSuperviewMargins
|
||||
{
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
[constraints addObject:[self autoAlignAxisToSuperviewMarginAxis:ALAxisHorizontal]];
|
||||
[constraints addObject:[self autoAlignAxisToSuperviewMarginAxis:ALAxisVertical]];
|
||||
return constraints;
|
||||
@ -133,6 +133,234 @@
|
||||
#endif /* PL__PureLayout_MinBaseSDK_iOS_8_0 */
|
||||
|
||||
|
||||
#pragma mark Pin Edges to SafeArea
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
/**
|
||||
Pins the given edge of the view to the same edge of its superview anchor.
|
||||
|
||||
@param edge The edge of this view and its superview to pin.
|
||||
@return The constraint added.
|
||||
*/
|
||||
- (NSLayoutConstraint *)autoPinEdgeToSuperviewSafeArea:(ALEdge)edge
|
||||
{
|
||||
return [self autoPinEdgeToSuperviewSafeArea:edge withInset:0.0];
|
||||
}
|
||||
|
||||
/**
|
||||
Pins the given edge of the view to the same edge of its superview anchor with an inset.
|
||||
|
||||
@param edge The edge of this view and its superview to pin.
|
||||
@param inset The amount to inset this view's edge from the superview's edge.
|
||||
@return The constraint added.
|
||||
*/
|
||||
- (NSLayoutConstraint *)autoPinEdgeToSuperviewSafeArea:(ALEdge)edge withInset:(CGFloat)inset
|
||||
{
|
||||
return [self autoPinEdgeToSuperviewSafeArea:edge withInset:inset relation:NSLayoutRelationEqual];
|
||||
}
|
||||
|
||||
/**
|
||||
Pins the given edge of the view to the same edge of its superview anchor/edge with an inset as a maximum or minimum.
|
||||
|
||||
@param edge The edge of this view and its superview to pin.
|
||||
@param inset The amount to inset this view's edge from the superview's edge.
|
||||
@param relation Whether the inset should be at least, at most, or exactly equal to the given value.
|
||||
@return The constraint added.
|
||||
*/
|
||||
- (NSLayoutConstraint *)autoPinEdgeToSuperviewSafeArea:(ALEdge)edge withInset:(CGFloat)inset relation:(NSLayoutRelation)relation
|
||||
{
|
||||
#if PL__PureLayout_MinBaseSDK_iOS_9_0
|
||||
self.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
|
||||
ALView *superview = self.superview;
|
||||
NSAssert(superview, @"View's superview must not be nil.\nView: %@", self);
|
||||
NSLayoutConstraint *constraint = nil;
|
||||
NSLayoutYAxisAnchor *topAnchor;
|
||||
NSLayoutYAxisAnchor *bottomAnchor;
|
||||
NSLayoutXAxisAnchor *leftAnchor;
|
||||
NSLayoutXAxisAnchor *rightAnchor;
|
||||
NSLayoutXAxisAnchor *leadingAnchor;
|
||||
NSLayoutXAxisAnchor *trailingAnchor;
|
||||
|
||||
#if PL__PureLayout_MinBaseSDK_iOS_11_0 // only iOS/tvOS SDK 11.0 has @available syntax introduced
|
||||
if (@available(iOS 11.0, tvOS 11.0, *)) {
|
||||
topAnchor = superview.safeAreaLayoutGuide.topAnchor;
|
||||
bottomAnchor = superview.safeAreaLayoutGuide.bottomAnchor;
|
||||
leftAnchor = superview.safeAreaLayoutGuide.leftAnchor;
|
||||
rightAnchor = superview.safeAreaLayoutGuide.rightAnchor;
|
||||
leadingAnchor = superview.safeAreaLayoutGuide.leadingAnchor;
|
||||
trailingAnchor = superview.safeAreaLayoutGuide.trailingAnchor;
|
||||
} else if (@available(iOS 9.0, *)) {
|
||||
topAnchor = superview.topAnchor;
|
||||
bottomAnchor = superview.bottomAnchor;
|
||||
leftAnchor = superview.leftAnchor;
|
||||
rightAnchor = superview.rightAnchor;
|
||||
leadingAnchor = superview.leadingAnchor;
|
||||
trailingAnchor = superview.trailingAnchor;
|
||||
} else { // for targeting iOS 8 or below without anchor system
|
||||
return [self autoPinEdgeToSuperviewEdge:edge withInset:inset relation:relation];
|
||||
}
|
||||
#elif PL__PureLayout_MinBaseSDK_iOS_9_0 // fallback to older SDKs, when using Xcode 8.0, which only has iOS SDK 10.0
|
||||
if (PL__PureLayout_MinSysVer_iOS_9_0) {
|
||||
topAnchor = superview.topAnchor;
|
||||
bottomAnchor = superview.bottomAnchor;
|
||||
leftAnchor = superview.leftAnchor;
|
||||
rightAnchor = superview.rightAnchor;
|
||||
leadingAnchor = superview.leadingAnchor;
|
||||
trailingAnchor = superview.trailingAnchor;
|
||||
} else { // for targeting iOS 8 or below without anchor system
|
||||
return [self autoPinEdgeToSuperviewEdge:edge withInset:inset relation:relation];
|
||||
}
|
||||
#endif
|
||||
if (edge == ALEdgeBottom || edge == ALEdgeRight || edge == ALEdgeTrailing) {
|
||||
// The bottom, right, and trailing insets (and relations, if an inequality) are inverted to become offsets
|
||||
inset = -inset;
|
||||
}
|
||||
switch (edge) {
|
||||
case ALEdgeLeft:
|
||||
switch (relation) {
|
||||
case NSLayoutRelationEqual:
|
||||
constraint = [[self leftAnchor] constraintEqualToAnchor:leftAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationLessThanOrEqual:
|
||||
constraint = [[self leftAnchor] constraintLessThanOrEqualToAnchor:leftAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationGreaterThanOrEqual:
|
||||
constraint = [[self leftAnchor] constraintGreaterThanOrEqualToAnchor:leftAnchor constant:inset];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ALEdgeRight:
|
||||
switch (relation) {
|
||||
case NSLayoutRelationEqual:
|
||||
constraint = [[self rightAnchor] constraintEqualToAnchor:rightAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationLessThanOrEqual:
|
||||
constraint = [[self rightAnchor] constraintGreaterThanOrEqualToAnchor:rightAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationGreaterThanOrEqual:
|
||||
constraint = [[self rightAnchor] constraintLessThanOrEqualToAnchor:rightAnchor constant:inset];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ALEdgeTop:
|
||||
switch (relation) {
|
||||
case NSLayoutRelationEqual:
|
||||
constraint = [[self topAnchor] constraintEqualToAnchor:topAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationLessThanOrEqual:
|
||||
constraint = [[self topAnchor] constraintLessThanOrEqualToAnchor:topAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationGreaterThanOrEqual:
|
||||
constraint = [[self topAnchor] constraintGreaterThanOrEqualToAnchor:topAnchor constant:inset];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ALEdgeBottom:
|
||||
switch (relation) {
|
||||
case NSLayoutRelationEqual:
|
||||
constraint = [[self bottomAnchor] constraintEqualToAnchor:bottomAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationLessThanOrEqual:
|
||||
constraint = [[self bottomAnchor] constraintGreaterThanOrEqualToAnchor:bottomAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationGreaterThanOrEqual:
|
||||
constraint = [[self bottomAnchor] constraintLessThanOrEqualToAnchor:bottomAnchor constant:inset];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ALEdgeLeading:
|
||||
switch (relation) {
|
||||
case NSLayoutRelationEqual:
|
||||
constraint = [[self leadingAnchor] constraintEqualToAnchor:leadingAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationLessThanOrEqual:
|
||||
constraint = [[self leadingAnchor] constraintLessThanOrEqualToAnchor:leadingAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationGreaterThanOrEqual:
|
||||
constraint = [[self leadingAnchor] constraintGreaterThanOrEqualToAnchor:leadingAnchor constant:inset];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ALEdgeTrailing:
|
||||
switch (relation) {
|
||||
case NSLayoutRelationEqual:
|
||||
constraint = [[self trailingAnchor] constraintEqualToAnchor:trailingAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationLessThanOrEqual:
|
||||
constraint = [[self trailingAnchor] constraintGreaterThanOrEqualToAnchor:trailingAnchor constant:inset];
|
||||
break;
|
||||
case NSLayoutRelationGreaterThanOrEqual:
|
||||
constraint = [[self trailingAnchor] constraintLessThanOrEqualToAnchor:trailingAnchor constant:inset];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
constraint.active = YES;
|
||||
return constraint;
|
||||
#else
|
||||
return [self autoPinEdgeToSuperviewEdge:edge withInset:inset relation:relation];
|
||||
#endif /* PL__PureLayout_MinBaseSDK_iOS_9_0 */
|
||||
}
|
||||
|
||||
/**
|
||||
Pins the edges of the view to the edges of its superview anchor.
|
||||
|
||||
@return An array of constraints added, ordered counterclockwise from top.
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewSafeArea
|
||||
{
|
||||
return [self autoPinEdgesToSuperviewSafeAreaWithInsets:ALEdgeInsetsZero];
|
||||
}
|
||||
|
||||
/**
|
||||
Pins the edges of the view to the edges of its superview anchor with the given edge insets.
|
||||
The insets.left corresponds to a leading edge constraint, and insets.right corresponds to a trailing edge constraint.
|
||||
|
||||
@param insets The insets for this view's edges from its superview's edges.
|
||||
@return An array of constraints added, ordered counterclockwise from top.
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewSafeAreaWithInsets:(ALEdgeInsets)insets
|
||||
{
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewSafeArea:ALEdgeTop withInset:insets.top]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewSafeArea:ALEdgeLeading withInset:insets.left]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewSafeArea:ALEdgeBottom withInset:insets.bottom]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewSafeArea:ALEdgeTrailing withInset:insets.right]];
|
||||
return constraints;
|
||||
}
|
||||
|
||||
/**
|
||||
Pins 3 of the 4 edges of the view to the edges of its superview anchor with the given edge insets, excluding one edge.
|
||||
The insets.left corresponds to a leading edge constraint, and insets.right corresponds to a trailing edge constraint.
|
||||
|
||||
@param insets The insets for this view's edges from its superview's edges. The inset corresponding to the excluded edge
|
||||
will be ignored.
|
||||
@param edge The edge of this view to exclude in pinning to its superview anchor; this method will not apply any constraint to it.
|
||||
@return An array of constraints added, ordered counterclockwise from top.
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewSafeAreaWithInsets:(ALEdgeInsets)insets excludingEdge:(ALEdge)edge
|
||||
{
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
|
||||
if (edge != ALEdgeTop) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewSafeArea:ALEdgeTop withInset:insets.top]];
|
||||
}
|
||||
if (edge != ALEdgeLeading && edge != ALEdgeLeft) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewSafeArea:ALEdgeLeading withInset:insets.left]];
|
||||
}
|
||||
if (edge != ALEdgeBottom) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewSafeArea:ALEdgeBottom withInset:insets.bottom]];
|
||||
}
|
||||
if (edge != ALEdgeTrailing && edge != ALEdgeRight) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewSafeArea:ALEdgeTrailing withInset:insets.right]];
|
||||
}
|
||||
return constraints;
|
||||
}
|
||||
|
||||
#endif /* TARGET_OS_IPHONE */
|
||||
|
||||
#pragma mark Pin Edges to Superview
|
||||
|
||||
/**
|
||||
@ -186,7 +414,7 @@
|
||||
/**
|
||||
Pins the edges of the view to the edges of its superview.
|
||||
|
||||
@return An array of constraints added.
|
||||
@return An array of constraints added, ordered counterclockwise from top.
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewEdges
|
||||
{
|
||||
@ -198,11 +426,11 @@
|
||||
The insets.left corresponds to a leading edge constraint, and insets.right corresponds to a trailing edge constraint.
|
||||
|
||||
@param insets The insets for this view's edges from its superview's edges.
|
||||
@return An array of constraints added.
|
||||
@return An array of constraints added, ordered counterclockwise from top.
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets
|
||||
{
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:insets.left]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]];
|
||||
@ -217,22 +445,42 @@
|
||||
@param insets The insets for this view's edges from its superview's edges. The inset corresponding to the excluded edge
|
||||
will be ignored.
|
||||
@param edge The edge of this view to exclude in pinning to its superview; this method will not apply any constraint to it.
|
||||
@return An array of constraints added.
|
||||
@return An array of constraints added, ordered counterclockwise from top.
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets excludingEdge:(ALEdge)edge
|
||||
{
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
if (edge != ALEdgeTop) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]];
|
||||
}
|
||||
if (edge != ALEdgeLeading && edge != ALEdgeLeft) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:insets.left]];
|
||||
}
|
||||
if (edge != ALEdgeBottom) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]];
|
||||
}
|
||||
if (edge != ALEdgeTrailing && edge != ALEdgeRight) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:insets.right]];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
switch (edge) {
|
||||
case ALEdgeLeft:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:insets.right]];
|
||||
break;
|
||||
case ALEdgeRight:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:insets.left]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]];
|
||||
break;
|
||||
case ALEdgeTop:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:insets.left]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:insets.right]];
|
||||
break;
|
||||
case ALEdgeBottom:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:insets.left]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:insets.right]];
|
||||
break;
|
||||
case ALEdgeLeading:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:insets.right]];
|
||||
break;
|
||||
case ALEdgeTrailing:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:insets.left]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]];
|
||||
break;
|
||||
}
|
||||
return constraints;
|
||||
}
|
||||
@ -250,6 +498,26 @@
|
||||
return [self autoPinEdgeToSuperviewMargin:edge relation:NSLayoutRelationEqual];
|
||||
}
|
||||
|
||||
/**
|
||||
Pins the given edge of the view to the corresponding margin of its superview with an inset.
|
||||
|
||||
@param edge The edge of this view to pin to the corresponding margin of its superview.
|
||||
@param @param inset The amount to inset this view's edge from the corresponding margin of its superview edge.
|
||||
@return The constraint added.
|
||||
*/
|
||||
- (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge withInset:(CGFloat)inset
|
||||
{
|
||||
self.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
ALView *superview = self.superview;
|
||||
NSAssert(superview, @"View's superview must not be nil.\nView: %@", self);
|
||||
if (edge == ALEdgeBottom || edge == ALEdgeRight || edge == ALEdgeTrailing) {
|
||||
// The bottom, right, and trailing insets (and relations, if an inequality) are inverted to become offsets
|
||||
inset = -inset;
|
||||
}
|
||||
ALMargin margin = [NSLayoutConstraint al_marginForEdge:edge];
|
||||
return [self autoConstrainAttribute:(ALAttribute)edge toAttribute:(ALAttribute)margin ofView:superview withOffset:inset];
|
||||
}
|
||||
|
||||
/**
|
||||
Pins the given edge of the view to the corresponding margin of its superview as a maximum or minimum.
|
||||
|
||||
@ -273,19 +541,31 @@
|
||||
ALMargin margin = [NSLayoutConstraint al_marginForEdge:edge];
|
||||
return [self autoConstrainAttribute:(ALAttribute)edge toAttribute:(ALAttribute)margin ofView:superview withOffset:0.0 relation:relation];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Pins the edges of the view to the margins of its superview.
|
||||
|
||||
@return An array of constraints added.
|
||||
@return An array of constraints added, ordered counterclockwise from top.
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewMargins
|
||||
{
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeLeading]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTrailing]];
|
||||
return [self autoPinEdgesToSuperviewMarginsWithInsets:ALEdgeInsetsZero];
|
||||
}
|
||||
|
||||
/**
|
||||
Pins the edges of the view to the edges of its corresponding margins of its superview with the given edge insets.
|
||||
The insets.left corresponds to a leading edge constraint, and insets.right corresponds to a trailing edge constraint.
|
||||
|
||||
@param insets The insets for this view's edges from its corresponding margin of its superview.
|
||||
@return An array of constraints added, ordered counterclockwise from top.
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewMarginsWithInsets:(ALEdgeInsets)insets
|
||||
{
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop withInset:insets.top]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeLeading withInset:insets.left]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom withInset:insets.bottom]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTrailing withInset:insets.right]];
|
||||
return constraints;
|
||||
}
|
||||
|
||||
@ -293,22 +573,42 @@
|
||||
Pins 3 of the 4 edges of the view to the margins of its superview, excluding one edge.
|
||||
|
||||
@param edge The edge of this view to exclude in pinning to its superview; this method will not apply any constraint to it.
|
||||
@return An array of constraints added.
|
||||
@return An array of constraints added, ordered counterclockwise from top.
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewMarginsExcludingEdge:(ALEdge)edge
|
||||
{
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
if (edge != ALEdgeTop) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop]];
|
||||
}
|
||||
if (edge != ALEdgeLeading && edge != ALEdgeLeft) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeLeading]];
|
||||
}
|
||||
if (edge != ALEdgeBottom) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom]];
|
||||
}
|
||||
if (edge != ALEdgeTrailing && edge != ALEdgeRight) {
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTrailing]];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
switch (edge) {
|
||||
case ALEdgeLeft:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeRight]];
|
||||
break;
|
||||
case ALEdgeRight:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeLeft]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom]];
|
||||
break;
|
||||
case ALEdgeTop:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeLeading]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTrailing]];
|
||||
break;
|
||||
case ALEdgeBottom:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeLeading]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTrailing]];
|
||||
break;
|
||||
case ALEdgeLeading:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTrailing]];
|
||||
break;
|
||||
case ALEdgeTrailing:
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeLeading]];
|
||||
[constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom]];
|
||||
break;
|
||||
}
|
||||
return constraints;
|
||||
}
|
||||
@ -360,7 +660,6 @@
|
||||
return [self autoConstrainAttribute:(ALAttribute)edge toAttribute:(ALAttribute)toEdge ofView:otherView withOffset:offset relation:relation];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Align Axes
|
||||
|
||||
/**
|
||||
@ -486,7 +785,7 @@
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoSetDimensionsToSize:(CGSize)size
|
||||
{
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
[constraints addObject:[self autoSetDimension:ALDimensionWidth toSize:size.width]];
|
||||
[constraints addObject:[self autoSetDimension:ALDimensionHeight toSize:size.height]];
|
||||
return constraints;
|
||||
@ -721,7 +1020,6 @@
|
||||
|
||||
#endif /* TARGET_OS_IPHONE */
|
||||
|
||||
|
||||
#pragma mark Internal Methods
|
||||
|
||||
/**
|
||||
|
||||
@ -121,7 +121,7 @@
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoAlignViewsToEdge:(ALEdge)edge
|
||||
{
|
||||
NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views.");
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
ALView *previousView = nil;
|
||||
for (id object in self) {
|
||||
if ([object isKindOfClass:[ALView class]]) {
|
||||
@ -146,7 +146,7 @@
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoAlignViewsToAxis:(ALAxis)axis
|
||||
{
|
||||
NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views.");
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
ALView *previousView = nil;
|
||||
for (id object in self) {
|
||||
if ([object isKindOfClass:[ALView class]]) {
|
||||
@ -171,7 +171,7 @@
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoMatchViewsDimension:(ALDimension)dimension
|
||||
{
|
||||
NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views.");
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
ALView *previousView = nil;
|
||||
for (id object in self) {
|
||||
if ([object isKindOfClass:[ALView class]]) {
|
||||
@ -197,7 +197,7 @@
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoSetViewsDimension:(ALDimension)dimension toSize:(CGFloat)size
|
||||
{
|
||||
NSAssert([self al_containsMinimumNumberOfViews:1], @"This array must contain at least 1 view.");
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
for (id object in self) {
|
||||
if ([object isKindOfClass:[ALView class]]) {
|
||||
ALView *view = (ALView *)object;
|
||||
@ -217,7 +217,7 @@
|
||||
*/
|
||||
- (PL__NSArray_of(NSLayoutConstraint *) *)autoSetViewsDimensionsToSize:(CGSize)size
|
||||
{
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
[constraints addObjectsFromArray:[self autoSetViewsDimension:ALDimensionWidth toSize:size.width]];
|
||||
[constraints addObjectsFromArray:[self autoSetViewsDimension:ALDimensionHeight toSize:size.height]];
|
||||
return constraints;
|
||||
@ -311,7 +311,7 @@
|
||||
CGFloat leadingSpacing = shouldSpaceInsets ? spacing : 0.0;
|
||||
CGFloat trailingSpacing = shouldSpaceInsets ? spacing : 0.0;
|
||||
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
ALView *previousView = nil;
|
||||
for (id object in self) {
|
||||
if ([object isKindOfClass:[ALView class]]) {
|
||||
@ -407,7 +407,7 @@
|
||||
#endif /* TARGET_OS_IPHONE */
|
||||
BOOL shouldFlipOrder = isRightToLeftLayout && (axis != ALAxisVertical); // imitate the effect of leading/trailing when distributing horizontally
|
||||
|
||||
__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new];
|
||||
PL__NSArray_of(ALView *) *views = [self al_copyViewsOnly];
|
||||
NSUInteger numberOfViews = [views count];
|
||||
ALView *commonSuperview = [views al_commonSuperviewOfViews];
|
||||
@ -493,7 +493,7 @@
|
||||
*/
|
||||
- (PL__NSArray_of(ALView *) *)al_copyViewsOnly
|
||||
{
|
||||
__NSMutableArray_of(ALView *) *viewsOnlyArray = [NSMutableArray arrayWithCapacity:[self count]];
|
||||
PL__NSMutableArray_of(ALView *) *viewsOnlyArray = [NSMutableArray arrayWithCapacity:[self count]];
|
||||
for (id object in self) {
|
||||
if ([object isKindOfClass:[ALView class]]) {
|
||||
[viewsOnlyArray addObject:object];
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
NOTE: Access to this variable is not synchronized (and should only be done on the main thread).
|
||||
*/
|
||||
static __NSMutableArray_of(__NSMutableArray_of(NSLayoutConstraint *) *) *_al_arraysOfCreatedConstraints = nil;
|
||||
static PL__NSMutableArray_of(PL__NSMutableArray_of(NSLayoutConstraint *) *) *_al_arraysOfCreatedConstraints = nil;
|
||||
|
||||
/**
|
||||
A global variable that is set to YES when installing a batch of constraints collected from a call to +[autoCreateAndInstallConstraints].
|
||||
@ -59,7 +59,7 @@ static BOOL _al_isInstallingCreatedConstraints = NO;
|
||||
/**
|
||||
Accessor for the global state that stores arrays of constraints created without being installed.
|
||||
*/
|
||||
+ (__NSMutableArray_of(__NSMutableArray_of(NSLayoutConstraint *) *) *)al_arraysOfCreatedConstraints
|
||||
+ (PL__NSMutableArray_of(PL__NSMutableArray_of(NSLayoutConstraint *) *) *)al_arraysOfCreatedConstraints
|
||||
{
|
||||
NSAssert([NSThread isMainThread], @"PureLayout is not thread safe, and must be used exclusively from the main thread.");
|
||||
if (!_al_arraysOfCreatedConstraints) {
|
||||
@ -71,7 +71,7 @@ static BOOL _al_isInstallingCreatedConstraints = NO;
|
||||
/**
|
||||
Accessor for the current mutable array of constraints created without being immediately installed.
|
||||
*/
|
||||
+ (__NSMutableArray_of(NSLayoutConstraint *) *)al_currentArrayOfCreatedConstraints
|
||||
+ (PL__NSMutableArray_of(NSLayoutConstraint *) *)al_currentArrayOfCreatedConstraints
|
||||
{
|
||||
return [[self al_arraysOfCreatedConstraints] lastObject];
|
||||
}
|
||||
@ -138,12 +138,12 @@ static BOOL _al_isInstallingCreatedConstraints = NO;
|
||||
constraints created by this library (even if automatic constraint installation is being prevented).
|
||||
NOTE: Access to this variable is not synchronized (and should only be done on the main thread).
|
||||
*/
|
||||
static __NSMutableArray_of(NSNumber *) *_al_globalConstraintPriorities = nil;
|
||||
static PL__NSMutableArray_of(NSNumber *) *_al_globalConstraintPriorities = nil;
|
||||
|
||||
/**
|
||||
Accessor for the global stack of layout priorities.
|
||||
*/
|
||||
+ (__NSMutableArray_of(NSNumber *) *)al_globalConstraintPriorities
|
||||
+ (PL__NSMutableArray_of(NSNumber *) *)al_globalConstraintPriorities
|
||||
{
|
||||
NSAssert([NSThread isMainThread], @"PureLayout is not thread safe, and must be used exclusively from the main thread.");
|
||||
if (!_al_globalConstraintPriorities) {
|
||||
@ -159,7 +159,7 @@ static __NSMutableArray_of(NSNumber *) *_al_globalConstraintPriorities = nil;
|
||||
*/
|
||||
+ (ALLayoutPriority)al_currentGlobalConstraintPriority
|
||||
{
|
||||
__NSMutableArray_of(NSNumber *) *globalConstraintPriorities = [self al_globalConstraintPriorities];
|
||||
PL__NSMutableArray_of(NSNumber *) *globalConstraintPriorities = [self al_globalConstraintPriorities];
|
||||
if ([globalConstraintPriorities count] == 0) {
|
||||
return ALLayoutPriorityRequired;
|
||||
}
|
||||
@ -207,12 +207,12 @@ static __NSMutableArray_of(NSNumber *) *_al_globalConstraintPriorities = nil;
|
||||
constraints created by this library (even if automatic constraint installation is being prevented).
|
||||
NOTE: Access to this variable is not synchronized (and should only be done on the main thread).
|
||||
*/
|
||||
static __NSMutableArray_of(NSString *) *_al_globalConstraintIdentifiers = nil;
|
||||
static PL__NSMutableArray_of(NSString *) *_al_globalConstraintIdentifiers = nil;
|
||||
|
||||
/**
|
||||
Accessor for the global state of constraint identifiers.
|
||||
*/
|
||||
+ (__NSMutableArray_of(NSString *) *)al_globalConstraintIdentifiers
|
||||
+ (PL__NSMutableArray_of(NSString *) *)al_globalConstraintIdentifiers
|
||||
{
|
||||
NSAssert([NSThread isMainThread], @"PureLayout is not thread safe, and must be used exclusively from the main thread.");
|
||||
if (!_al_globalConstraintIdentifiers) {
|
||||
@ -228,7 +228,7 @@ static __NSMutableArray_of(NSString *) *_al_globalConstraintIdentifiers = nil;
|
||||
*/
|
||||
+ (NSString *)al_currentGlobalConstraintIdentifier
|
||||
{
|
||||
__NSMutableArray_of(NSString *) *globalConstraintIdentifiers = [self al_globalConstraintIdentifiers];
|
||||
PL__NSMutableArray_of(NSString *) *globalConstraintIdentifiers = [self al_globalConstraintIdentifiers];
|
||||
if ([globalConstraintIdentifiers count] == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
|
||||
// Using generics with NSMutableArray is so common in the internal implementation of PureLayout that it gets a dedicated preprocessor macro for better readability.
|
||||
#define __NSMutableArray_of(type) PL__GENERICS(NSMutableArray, type)
|
||||
#define PL__NSMutableArray_of(type) PL__GENERICS(NSMutableArray, type)
|
||||
|
||||
PL__ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -68,11 +68,11 @@ static const CGFloat kMULTIPLIER_MIN_VALUE = (CGFloat)0.00001; // very small flo
|
||||
@interface NSLayoutConstraint (PureLayoutInternal)
|
||||
|
||||
+ (BOOL)al_preventAutomaticConstraintInstallation;
|
||||
+ (__NSMutableArray_of(NSLayoutConstraint *) *)al_currentArrayOfCreatedConstraints;
|
||||
+ (PL__NSMutableArray_of(NSLayoutConstraint *) *)al_currentArrayOfCreatedConstraints;
|
||||
+ (BOOL)al_isExecutingPriorityConstraintsBlock;
|
||||
+ (ALLayoutPriority)al_currentGlobalConstraintPriority;
|
||||
#if PL__PureLayout_MinBaseSDK_iOS_8_0 || PL__PureLayout_MinBaseSDK_OSX_10_10
|
||||
+ (NSString *)al_currentGlobalConstraintIdentifier;
|
||||
+ (nullable NSString *)al_currentGlobalConstraintIdentifier;
|
||||
#endif /* PL__PureLayout_MinBaseSDK_iOS_8_0 || PL__PureLayout_MinBaseSDK_OSX_10_10 */
|
||||
+ (void)al_applyGlobalStateToConstraint:(NSLayoutConstraint *)constraint;
|
||||
+ (NSLayoutAttribute)al_layoutAttributeForAttribute:(ALAttribute)attribute;
|
||||
|
||||
@ -29,14 +29,18 @@
|
||||
#define PureLayoutDefines_h
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// check the code in <Foundation/NSObjCRuntime.h> - <Availability.h>
|
||||
// Define some preprocessor macros to check for a minimum Base SDK. These are used to prevent compile-time errors in older versions of Xcode.
|
||||
#define PL__PureLayout_MinBaseSDK_iOS_8_0 (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_7_1)
|
||||
#define PL__PureLayout_MinBaseSDK_iOS_9_0 (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_8_4)
|
||||
#define PL__PureLayout_MinBaseSDK_iOS_11_0 (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3)
|
||||
#define PL__PureLayout_MinBaseSDK_OSX_10_10 (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MAX_ALLOWED > __MAC_10_9)
|
||||
|
||||
// Define some preprocessor macros to check for a minimum System Version. These are used to prevent runtime crashes on older versions of iOS/OS X.
|
||||
#define PL__PureLayout_MinSysVer_iOS_7_0 (TARGET_OS_IPHONE && floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1)
|
||||
#define PL__PureLayout_MinSysVer_iOS_8_0 (TARGET_OS_IPHONE && floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1)
|
||||
#define PL__PureLayout_MinSysVer_iOS_9_0 (TARGET_OS_IPHONE && floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_8_x_Max)
|
||||
#define PL__PureLayout_MinSysVer_iOS_10_0 (TARGET_OS_IPHONE && floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_9_x_Max)
|
||||
#define PL__PureLayout_MinSysVer_OSX_10_9 (!TARGET_OS_IPHONE && floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_8_4)
|
||||
|
||||
// Define some preprocessor macros that allow nullability annotations to be adopted in a backwards-compatible manner.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
# [](#)
|
||||
[](https://travis-ci.org/PureLayout/PureLayout) [](https://coveralls.io/r/PureLayout/PureLayout) [](http://cocoapods.org/pods/PureLayout) [](http://cocoapods.org/pods/PureLayout) [](LICENSE)
|
||||
[](https://travis-ci.org/PureLayout/PureLayout) [](http://cocoapods.org/pods/PureLayout) [](http://cocoapods.org/pods/PureLayout) [](LICENSE)
|
||||
|
||||
The ultimate API for iOS & OS X Auto Layout — impressively simple, immensely powerful. PureLayout extends `UIView`/`NSView`, `NSArray`, and `NSLayoutConstraint` with a comprehensive Auto Layout API that is modeled after Apple's own frameworks. PureLayout is a cross-platform Objective-C library that works (and looks!) great in Swift. It is fully backwards-compatible with all versions of iOS and OS X that support Auto Layout.
|
||||
|
||||
@ -110,6 +110,8 @@ Additionally, there is one generic attribute type, `ALAttribute`, which is effec
|
||||
- autoSetDimension(s)ToSize:
|
||||
- autoConstrainAttribute:toAttribute:ofView:(withOffset:|withMultiplier:)
|
||||
- autoPinTo(Top|Bottom)LayoutGuideOfViewController:withInset: // iOS only
|
||||
- autoPinEdgeToSuperviewSafeArea: // iOS 11.0+ only
|
||||
- autoPinEdgeToSuperviewSafeArea:withInset: // iOS 11.0+ only
|
||||
```
|
||||
|
||||
### [`NSArray`](PureLayout/PureLayout/NSArray%2BPureLayout.h)
|
||||
@ -144,16 +146,28 @@ Additionally, there is one generic attribute type, `ALAttribute`, which is effec
|
||||
### Sample Code (Swift)
|
||||
PureLayout dramatically simplifies writing Auto Layout code. Let's take a quick look at some examples, using PureLayout from Swift.
|
||||
|
||||
Initialize the view using PureLayout initializer:
|
||||
|
||||
```swift
|
||||
let view1 = UIView(forAutoLayout: ())
|
||||
```
|
||||
|
||||
If you need to use a different initializer (e.g. in `UIView` subclass), you can also use `configureForAutoLayout`:
|
||||
|
||||
```
|
||||
view1.configureForAutoLayout() // alternative to UIView.init(forAutoLayout: ())
|
||||
```
|
||||
|
||||
Here's a constraint between two views created (and automatically activated) using PureLayout:
|
||||
|
||||
```swift
|
||||
view1.autoPinEdge(.Top, toEdge: .Bottom, ofView: view2)
|
||||
view1.autoPinEdge(.top, toEdge: .bottom, ofView: view2)
|
||||
```
|
||||
|
||||
Without PureLayout, here's the equivalent code you'd have to write using Apple's Foundation API directly:
|
||||
|
||||
```swift
|
||||
NSLayoutConstraint(item: view1, attribute: .Top, relatedBy: .Equal, toItem: view2, attribute: .Bottom, multiplier: 1.0, constant: 0.0).active = true
|
||||
NSLayoutConstraint(item: view1, attribute: .top, relatedBy: .equal, toItem: view2, attribute: .bottom, multiplier: 1.0, constant: 0.0).active = true
|
||||
```
|
||||
|
||||
Many APIs of PureLayout create multiple constraints for you under the hood, letting you write highly readable layout code:
|
||||
@ -163,13 +177,19 @@ Many APIs of PureLayout create multiple constraints for you under the hood, lett
|
||||
logoImageView.autoCenterInSuperview()
|
||||
|
||||
// 4 constraints created & activated in one line!
|
||||
textContentView.autoPinEdgesToSuperviewEdgesWithInsets(UIEdgeInsets(top: 20.0, left: 5.0, bottom: 10.0, right: 5.0))
|
||||
textContentView.autoPinEdgesToSuperviewEdges(with insets: UIEdgeInsets(top: 20.0, left: 5.0, bottom: 10.0, right: 5.0))
|
||||
```
|
||||
|
||||
PureLayout always returns the constraints it creates so you have full control:
|
||||
|
||||
```swift
|
||||
let constraint = skinnyView.autoMatchDimension(.Height, toDimension: .Width, ofView: tallView)
|
||||
let constraint = skinnyView.autoMatchDimension(.height, toDimension: .width, ofView: tallView)
|
||||
```
|
||||
|
||||
PureLayout supports safearea with iOS 11.0+:
|
||||
|
||||
```swift
|
||||
view2.autoPinEdge(toSuperviewSafeArea: .top)
|
||||
```
|
||||
|
||||
PureLayout supports all Auto Layout features including inequalities, priorities, layout margins, identifiers, and much more. It's a comprehensive, developer-friendly way to use Auto Layout.
|
||||
|
||||
@ -412,7 +412,7 @@ BOOL _fileIsSymbolicLink(const unz_file_info *fileInfo);
|
||||
} else {
|
||||
[fileManager createDirectoryAtPath:fullPath.stringByDeletingLastPathComponent withIntermediateDirectories:YES attributes:directoryAttr error:&err];
|
||||
}
|
||||
if (nil != err) {
|
||||
if (err != nil) {
|
||||
if ([err.domain isEqualToString:NSCocoaErrorDomain] &&
|
||||
err.code == 640) {
|
||||
unzippingError = err;
|
||||
@ -430,7 +430,9 @@ BOOL _fileIsSymbolicLink(const unz_file_info *fileInfo);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fileIsSymbolicLink) {
|
||||
if (isDirectory && !fileIsSymbolicLink) {
|
||||
// nothing to read/write for a directory
|
||||
} else if (!fileIsSymbolicLink) {
|
||||
// ensure we are not creating stale file entries
|
||||
int readBytes = unzReadCurrentFile(zip, buffer, 4096);
|
||||
if (readBytes >= 0) {
|
||||
@ -720,29 +722,31 @@ BOOL _fileIsSymbolicLink(const unz_file_info *fileInfo);
|
||||
NSDirectoryEnumerator *dirEnumerator = [fileManager enumeratorAtPath:directoryPath];
|
||||
NSArray<NSString *> *allObjects = dirEnumerator.allObjects;
|
||||
NSUInteger total = allObjects.count, complete = 0;
|
||||
NSString *fileName;
|
||||
for (fileName in allObjects) {
|
||||
BOOL isDir;
|
||||
if (keepParentDirectory && !total) {
|
||||
allObjects = @[@""];
|
||||
total = 1;
|
||||
}
|
||||
for (__strong NSString *fileName in allObjects) {
|
||||
NSString *fullFilePath = [directoryPath stringByAppendingPathComponent:fileName];
|
||||
[fileManager fileExistsAtPath:fullFilePath isDirectory:&isDir];
|
||||
|
||||
if (keepParentDirectory)
|
||||
{
|
||||
if (keepParentDirectory) {
|
||||
fileName = [directoryPath.lastPathComponent stringByAppendingPathComponent:fileName];
|
||||
}
|
||||
|
||||
BOOL isDir;
|
||||
[fileManager fileExistsAtPath:fullFilePath isDirectory:&isDir];
|
||||
if (!isDir) {
|
||||
// file
|
||||
success &= [zipArchive writeFileAtPath:fullFilePath withFileName:fileName compressionLevel:compressionLevel password:password AES:aes];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([[NSFileManager defaultManager] subpathsOfDirectoryAtPath:fullFilePath error:nil].count == 0)
|
||||
{
|
||||
} else {
|
||||
// directory
|
||||
if (![fileManager enumeratorAtPath:fullFilePath].nextObject) {
|
||||
// empty directory
|
||||
success &= [zipArchive writeFolderAtPath:fullFilePath withFolderName:fileName withPassword:password];
|
||||
}
|
||||
}
|
||||
complete++;
|
||||
if (progressHandler) {
|
||||
complete++;
|
||||
progressHandler(complete, total);
|
||||
}
|
||||
}
|
||||
@ -866,7 +870,7 @@ BOOL _fileIsSymbolicLink(const unz_file_info *fileInfo);
|
||||
NSAssert((_zip != NULL), @"[SSZipArchive] Attempting to close an archive which was never opened");
|
||||
int error = zipClose(_zip, NULL);
|
||||
_zip = nil;
|
||||
return error == UNZ_OK;
|
||||
return error == ZIP_OK;
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
@ -84,6 +84,7 @@ void init_keys(const char *passwd, uint32_t *pkeys, const z_crc_t *pcrc_32_tab)
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
#ifndef NOCRYPT
|
||||
int cryptrand(unsigned char *buf, unsigned int len)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@ -140,5 +141,6 @@ int crypthead(const char *passwd, uint8_t *buf, int buf_size, uint32_t *pkeys,
|
||||
buf[n++] = (uint8_t)zencode(pkeys, pcrc_32_tab, verify2, t);
|
||||
return n;
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
@ -48,12 +48,14 @@ uint8_t update_keys(uint32_t *pkeys, const z_crc_t *pcrc_32_tab, int32_t c);
|
||||
/* Initialize the encryption keys and the random header according to the given password. */
|
||||
void init_keys(const char *passwd, uint32_t *pkeys, const z_crc_t *pcrc_32_tab);
|
||||
|
||||
#ifndef NOCRYPT
|
||||
/* Generate cryptographically secure random numbers */
|
||||
int cryptrand(unsigned char *buf, unsigned int len);
|
||||
|
||||
/* Create encryption header */
|
||||
int crypthead(const char *passwd, uint8_t *buf, int buf_size, uint32_t *pkeys,
|
||||
const z_crc_t *pcrc_32_tab, uint8_t verify1, uint8_t verify2);
|
||||
#endif
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
|
||||
@ -1269,6 +1269,13 @@ extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, in
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
zdecode(s->keys, s->pcrc_32_tab, source[i]);
|
||||
uint8_t expected = (s->cur_file_info.flag & (1 << 3)) ?
|
||||
s->cur_file_info.dos_date >> 8 :
|
||||
s->cur_file_info.crc >> 24;
|
||||
uint8_t actual = (uint8_t)source[11];
|
||||
if (expected != actual) {
|
||||
return UNZ_BADPASSWORD;
|
||||
}
|
||||
|
||||
s->pfile_in_zip_read->rest_read_compressed -= 12;
|
||||
s->pfile_in_zip_read->pos_in_zipfile += 12;
|
||||
@ -1344,7 +1351,7 @@ extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, uint32_t len)
|
||||
s->pfile_in_zip_read->stream.next_in);
|
||||
bytes_to_read -= bytes_not_read;
|
||||
if (bytes_not_read > 0)
|
||||
memcpy(s->pfile_in_zip_read->read_buffer, s->pfile_in_zip_read->stream.next_in, bytes_not_read);
|
||||
memmove(s->pfile_in_zip_read->read_buffer, s->pfile_in_zip_read->stream.next_in, bytes_not_read);
|
||||
if (s->pfile_in_zip_read->rest_read_compressed < bytes_to_read)
|
||||
bytes_to_read = (uint16_t)s->pfile_in_zip_read->rest_read_compressed;
|
||||
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SCKExampleTest : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation SCKExampleTest
|
||||
|
||||
- (void)testExample
|
||||
{
|
||||
XCTAssertTrue(YES);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -4,6 +4,33 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc
|
||||
public class SecretSessionKnownSenderError: NSObject, CustomNSError {
|
||||
@objc
|
||||
public static let kSenderRecipientIdKey = "kSenderRecipientIdKey"
|
||||
|
||||
@objc
|
||||
public static let kSenderDeviceIdKey = "kSenderDeviceIdKey"
|
||||
|
||||
public let senderRecipientId: String
|
||||
public let senderDeviceId: UInt32
|
||||
public let underlyingError: Error
|
||||
|
||||
init(senderRecipientId: String, senderDeviceId: UInt32, underlyingError: Error) {
|
||||
self.senderRecipientId = senderRecipientId
|
||||
self.senderDeviceId = senderDeviceId
|
||||
self.underlyingError = underlyingError
|
||||
}
|
||||
|
||||
public var errorUserInfo: [String: Any] {
|
||||
return [
|
||||
type(of: self).kSenderRecipientIdKey: self.senderRecipientId,
|
||||
type(of: self).kSenderDeviceIdKey: self.senderDeviceId,
|
||||
NSUnderlyingErrorKey: (underlyingError as NSError)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
public enum SMKSecretSessionCipherError: Int, Error {
|
||||
case selfSentMessage
|
||||
@ -245,97 +272,113 @@ public class SMKDecryptResult: NSObject {
|
||||
localDeviceId: Int32,
|
||||
protocolContext: Any?) throws -> SMKDecryptResult {
|
||||
|
||||
guard timestamp > 0 else {
|
||||
throw SMKError.assertionError(description: "\(logTag) invalid timestamp")
|
||||
}
|
||||
guard timestamp > 0 else {
|
||||
throw SMKError.assertionError(description: "\(logTag) invalid timestamp")
|
||||
}
|
||||
|
||||
// IdentityKeyPair ourIdentity = signalProtocolStore.getIdentityKeyPair();
|
||||
guard let ourIdentityKeyPair = identityStore.identityKeyPair(protocolContext) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Missing our identity key pair.")
|
||||
}
|
||||
// IdentityKeyPair ourIdentity = signalProtocolStore.getIdentityKeyPair();
|
||||
guard let ourIdentityKeyPair = identityStore.identityKeyPair(protocolContext) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Missing our identity key pair.")
|
||||
}
|
||||
|
||||
// UnidentifiedSenderMessage wrapper = new UnidentifiedSenderMessage(ciphertext);
|
||||
let wrapper = try SMKUnidentifiedSenderMessage.parse(dataAndPrefix: cipherTextData)
|
||||
// UnidentifiedSenderMessage wrapper = new UnidentifiedSenderMessage(ciphertext);
|
||||
let wrapper = try SMKUnidentifiedSenderMessage.parse(dataAndPrefix: cipherTextData)
|
||||
|
||||
// byte[] ephemeralSalt = ByteUtil.combine("UnidentifiedDelivery".getBytes(),
|
||||
// ourIdentity.getPublicKey().getPublicKey().serialize(), wrapper.getEphemeral().serialize());
|
||||
guard let prefixData = kUDPrefixString.data(using: String.Encoding.utf8) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Could not encode prefix.")
|
||||
}
|
||||
let ephemeralSalt = NSData.join([
|
||||
prefixData,
|
||||
try ourIdentityKeyPair.ecPublicKey().serialized,
|
||||
wrapper.ephemeralKey.serialized
|
||||
])
|
||||
// byte[] ephemeralSalt = ByteUtil.combine("UnidentifiedDelivery".getBytes(),
|
||||
// ourIdentity.getPublicKey().getPublicKey().serialize(), wrapper.getEphemeral().serialize());
|
||||
guard let prefixData = kUDPrefixString.data(using: String.Encoding.utf8) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Could not encode prefix.")
|
||||
}
|
||||
let ephemeralSalt = NSData.join([
|
||||
prefixData,
|
||||
try ourIdentityKeyPair.ecPublicKey().serialized,
|
||||
wrapper.ephemeralKey.serialized
|
||||
])
|
||||
|
||||
// EphemeralKeys ephemeralKeys = calculateEphemeralKeys(wrapper.getEphemeral(), ourIdentity.getPrivateKey(),
|
||||
// ephemeralSalt);
|
||||
let ephemeralKeys = try throwswrapped_calculateEphemeralKeys(ephemeralPublicKey: wrapper.ephemeralKey,
|
||||
ephemeralPrivateKey: ourIdentityKeyPair.ecPrivateKey(),
|
||||
salt: ephemeralSalt)
|
||||
// EphemeralKeys ephemeralKeys = calculateEphemeralKeys(wrapper.getEphemeral(), ourIdentity.getPrivateKey(),
|
||||
// ephemeralSalt);
|
||||
let ephemeralKeys = try throwswrapped_calculateEphemeralKeys(ephemeralPublicKey: wrapper.ephemeralKey,
|
||||
ephemeralPrivateKey: ourIdentityKeyPair.ecPrivateKey(),
|
||||
salt: ephemeralSalt)
|
||||
|
||||
// byte[] staticKeyBytes = decrypt(ephemeralKeys.cipherKey, ephemeralKeys.macKey, wrapper.getEncryptedStatic());
|
||||
let staticKeyBytes = try decrypt(cipherKey: ephemeralKeys.cipherKey,
|
||||
macKey: ephemeralKeys.macKey,
|
||||
cipherTextWithMac: wrapper.encryptedStatic)
|
||||
// byte[] staticKeyBytes = decrypt(ephemeralKeys.cipherKey, ephemeralKeys.macKey, wrapper.getEncryptedStatic());
|
||||
let staticKeyBytes = try decrypt(cipherKey: ephemeralKeys.cipherKey,
|
||||
macKey: ephemeralKeys.macKey,
|
||||
cipherTextWithMac: wrapper.encryptedStatic)
|
||||
|
||||
// ECPublicKey staticKey = Curve.decodePoint(staticKeyBytes, 0);
|
||||
let staticKey = try ECPublicKey(serializedKeyData: staticKeyBytes)
|
||||
// ECPublicKey staticKey = Curve.decodePoint(staticKeyBytes, 0);
|
||||
let staticKey = try ECPublicKey(serializedKeyData: staticKeyBytes)
|
||||
|
||||
// byte[] staticSalt = ByteUtil.combine(ephemeralKeys.chainKey, wrapper.getEncryptedStatic());
|
||||
let staticSalt = NSData.join([
|
||||
ephemeralKeys.chainKey,
|
||||
wrapper.encryptedStatic
|
||||
])
|
||||
// byte[] staticSalt = ByteUtil.combine(ephemeralKeys.chainKey, wrapper.getEncryptedStatic());
|
||||
let staticSalt = NSData.join([
|
||||
ephemeralKeys.chainKey,
|
||||
wrapper.encryptedStatic
|
||||
])
|
||||
|
||||
// StaticKeys staticKeys = calculateStaticKeys(staticKey, ourIdentity.getPrivateKey(), staticSalt);
|
||||
let staticKeys = try throwswrapped_calculateStaticKeys(staticPublicKey: staticKey,
|
||||
staticPrivateKey: ourIdentityKeyPair.ecPrivateKey(),
|
||||
salt: staticSalt)
|
||||
// StaticKeys staticKeys = calculateStaticKeys(staticKey, ourIdentity.getPrivateKey(), staticSalt);
|
||||
let staticKeys = try throwswrapped_calculateStaticKeys(staticPublicKey: staticKey,
|
||||
staticPrivateKey: ourIdentityKeyPair.ecPrivateKey(),
|
||||
salt: staticSalt)
|
||||
|
||||
// byte[] messageBytes = decrypt(staticKeys.cipherKey, staticKeys.macKey, wrapper.getEncryptedMessage());
|
||||
let messageBytes = try decrypt(cipherKey: staticKeys.cipherKey,
|
||||
macKey: staticKeys.macKey,
|
||||
cipherTextWithMac: wrapper.encryptedMessage)
|
||||
// byte[] messageBytes = decrypt(staticKeys.cipherKey, staticKeys.macKey, wrapper.getEncryptedMessage());
|
||||
let messageBytes = try decrypt(cipherKey: staticKeys.cipherKey,
|
||||
macKey: staticKeys.macKey,
|
||||
cipherTextWithMac: wrapper.encryptedMessage)
|
||||
|
||||
// content = new UnidentifiedSenderMessageContent(messageBytes);
|
||||
let messageContent = try SMKUnidentifiedSenderMessageContent.parse(data: messageBytes)
|
||||
// content = new UnidentifiedSenderMessageContent(messageBytes);
|
||||
let messageContent = try SMKUnidentifiedSenderMessageContent.parse(data: messageBytes)
|
||||
|
||||
guard messageContent.senderCertificate.senderRecipientId != localRecipientId ||
|
||||
messageContent.senderCertificate.senderDeviceId != localDeviceId else {
|
||||
let senderRecipientId = messageContent.senderCertificate.senderRecipientId
|
||||
let senderDeviceId = messageContent.senderCertificate.senderDeviceId
|
||||
|
||||
guard senderRecipientId != localRecipientId || senderDeviceId != localDeviceId else {
|
||||
Logger.info("Discarding self-sent message")
|
||||
throw SMKSecretSessionCipherError.selfSentMessage
|
||||
}
|
||||
}
|
||||
|
||||
// validator.validate(content.getSenderCertificate(), timestamp);
|
||||
// validator.validate(content.getSenderCertificate(), timestamp);
|
||||
|
||||
let wrapAsKnownSenderError = { (underlyingError: Error) in
|
||||
return SecretSessionKnownSenderError(senderRecipientId: senderRecipientId, senderDeviceId: senderDeviceId, underlyingError: underlyingError)
|
||||
}
|
||||
|
||||
do {
|
||||
try certificateValidator.throwswrapped_validate(senderCertificate: messageContent.senderCertificate,
|
||||
validationTime: timestamp)
|
||||
validationTime: timestamp)
|
||||
} catch {
|
||||
throw wrapAsKnownSenderError(error)
|
||||
}
|
||||
|
||||
// if (!MessageDigest.isEqual(content.getSenderCertificate().getKey().serialize(), staticKeyBytes)) {
|
||||
// throw new InvalidKeyException("Sender's certificate key does not match key used in message");
|
||||
// }
|
||||
//
|
||||
// NOTE: Constant time comparison.
|
||||
guard messageContent.senderCertificate.key.serialized.ows_constantTimeIsEqual(to: staticKeyBytes) else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Sender's certificate key does not match key used in message.")
|
||||
}
|
||||
// if (!MessageDigest.isEqual(content.getSenderCertificate().getKey().serialize(), staticKeyBytes)) {
|
||||
// throw new InvalidKeyException("Sender's certificate key does not match key used in message");
|
||||
// }
|
||||
//
|
||||
// NOTE: Constant time comparison.
|
||||
guard messageContent.senderCertificate.key.serialized.ows_constantTimeIsEqual(to: staticKeyBytes) else {
|
||||
let underlyingError = SMKError.assertionError(description: "\(logTag) Sender's certificate key does not match key used in message.")
|
||||
throw wrapAsKnownSenderError(underlyingError)
|
||||
}
|
||||
|
||||
let paddedMessagePlaintext = try throwswrapped_decrypt(messageContent: messageContent, protocolContext: protocolContext)
|
||||
let paddedMessagePlaintext: Data
|
||||
do {
|
||||
paddedMessagePlaintext = try throwswrapped_decrypt(messageContent: messageContent, protocolContext: protocolContext)
|
||||
} catch {
|
||||
throw wrapAsKnownSenderError(error)
|
||||
}
|
||||
|
||||
// return new Pair<>(new SignalProtocolAddress(content.getSenderCertificate().getSender(),
|
||||
// content.getSenderCertificate().getSenderDeviceId()),
|
||||
// decrypt(content));
|
||||
//
|
||||
// NOTE: We use the sender properties from the sender certificate, not from this class' properties.
|
||||
let senderRecipientId = messageContent.senderCertificate.senderRecipientId
|
||||
let senderDeviceId = messageContent.senderCertificate.senderDeviceId
|
||||
guard senderDeviceId >= 0 && senderDeviceId <= INT_MAX else {
|
||||
throw SMKError.assertionError(description: "\(logTag) Invalid senderDeviceId.")
|
||||
}
|
||||
return SMKDecryptResult(senderRecipientId: senderRecipientId,
|
||||
senderDeviceId: Int(senderDeviceId),
|
||||
paddedPayload: paddedMessagePlaintext,
|
||||
messageType: messageContent.messageType)
|
||||
// return new Pair<>(new SignalProtocolAddress(content.getSenderCertificate().getSender(),
|
||||
// content.getSenderCertificate().getSenderDeviceId()),
|
||||
// decrypt(content));
|
||||
//
|
||||
// NOTE: We use the sender properties from the sender certificate, not from this class' properties.
|
||||
guard senderDeviceId >= 0 && senderDeviceId <= INT_MAX else {
|
||||
let underlyingError = SMKError.assertionError(description: "\(logTag) Invalid senderDeviceId.")
|
||||
throw wrapAsKnownSenderError(underlyingError)
|
||||
}
|
||||
return SMKDecryptResult(senderRecipientId: senderRecipientId,
|
||||
senderDeviceId: Int(senderDeviceId),
|
||||
paddedPayload: paddedMessagePlaintext,
|
||||
messageType: messageContent.messageType)
|
||||
}
|
||||
|
||||
// MARK: - Encrypt
|
||||
|
||||
@ -128,8 +128,9 @@ class SMKSecretSessionCipherTest: XCTestCase {
|
||||
localDeviceId: bobMockClient.deviceId,
|
||||
protocolContext: nil)
|
||||
XCTFail("Decryption should have failed.")
|
||||
} catch _ as SMKCertificateError {
|
||||
} catch let knownSenderError as SecretSessionKnownSenderError {
|
||||
// Decryption is expected to fail.
|
||||
XCTAssert(knownSenderError.underlyingError is SMKCertificateError )
|
||||
} catch {
|
||||
XCTFail("Unexpected error: \(error)")
|
||||
}
|
||||
@ -187,8 +188,9 @@ class SMKSecretSessionCipherTest: XCTestCase {
|
||||
localDeviceId: bobMockClient.deviceId,
|
||||
protocolContext: nil)
|
||||
XCTFail("Decryption should have failed.")
|
||||
} catch _ as SMKCertificateError {
|
||||
} catch let knownSenderError as SecretSessionKnownSenderError {
|
||||
// Decryption is expected to fail.
|
||||
XCTAssert(knownSenderError.underlyingError is SMKCertificateError )
|
||||
} catch {
|
||||
XCTFail("Unexpected error: \(error)")
|
||||
}
|
||||
@ -240,16 +242,21 @@ class SMKSecretSessionCipherTest: XCTestCase {
|
||||
// }
|
||||
let certificateValidator = SMKCertificateDefaultValidator(trustRoot: try! trustRoot.ecPublicKey())
|
||||
do {
|
||||
try bobCipher.throwswrapped_decryptMessage(certificateValidator: certificateValidator,
|
||||
_ = try bobCipher.throwswrapped_decryptMessage(certificateValidator: certificateValidator,
|
||||
cipherTextData: ciphertext,
|
||||
timestamp: 31335,
|
||||
localRecipientId: bobMockClient.recipientId,
|
||||
localDeviceId: bobMockClient.deviceId,
|
||||
protocolContext: nil)
|
||||
XCTFail("Decryption should have failed.")
|
||||
} catch {
|
||||
} catch let knownSenderError as SecretSessionKnownSenderError {
|
||||
// Decryption is expected to fail.
|
||||
XCTAssertTrue(error is SMKError)
|
||||
guard case SMKError.assertionError = knownSenderError.underlyingError else {
|
||||
XCTFail("unexpected error: \(knownSenderError.underlyingError)")
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
XCTFail("unexpected error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,7 +294,7 @@ class SMKSecretSessionCipherTest: XCTestCase {
|
||||
key: try! serverKey.ecPublicKey(),
|
||||
signatureData: serverCertificateSignature)
|
||||
XCTAssertEqual(try! signedServerCertificate.toProto().certificate, unsignedServerCertificateData)
|
||||
let signedServerCertificateData = try! signedServerCertificate.serialized()
|
||||
_ = try! signedServerCertificate.serialized()
|
||||
|
||||
// byte[] senderCertificateBytes = SignalProtos.SenderCertificate.Certificate.newBuilder()
|
||||
// .setSender(sender)
|
||||
|
||||
@ -20,12 +20,16 @@ private let i_2166136261 = Int(bitPattern: 2166136261)
|
||||
private let i_16777619 = Int(16777619)
|
||||
#endif
|
||||
|
||||
fileprivate func serializeAnyJSON(for message: Message, typeURL: String) throws -> String {
|
||||
var visitor = try JSONEncodingVisitor(message: message)
|
||||
fileprivate func serializeAnyJSON(
|
||||
for message: Message,
|
||||
typeURL: String,
|
||||
options: JSONEncodingOptions
|
||||
) throws -> String {
|
||||
var visitor = try JSONEncodingVisitor(message: message, options: options)
|
||||
visitor.startObject()
|
||||
visitor.encodeField(name: "@type", stringValue: typeURL)
|
||||
if let m = message as? _CustomJSONCodable {
|
||||
let value = try m.encodedJSONString()
|
||||
let value = try m.encodedJSONString(options: options)
|
||||
visitor.encodeField(name: "value", jsonText: value)
|
||||
} else {
|
||||
try message.traverse(visitor: &visitor)
|
||||
@ -381,7 +385,7 @@ extension AnyMessageStorage {
|
||||
// * The protobuf field we were deserialized from.
|
||||
// The last case requires locating the type, deserializing
|
||||
// into an object, then reserializing back to JSON.
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
switch state {
|
||||
case .binary(let valueData):
|
||||
// Transcode by decoding the binary data to a message object
|
||||
@ -394,13 +398,13 @@ extension AnyMessageStorage {
|
||||
throw JSONEncodingError.anyTranscodeFailure
|
||||
}
|
||||
let m = try messageType.init(serializedData: valueData, partial: true)
|
||||
return try serializeAnyJSON(for: m, typeURL: _typeURL)
|
||||
return try serializeAnyJSON(for: m, typeURL: _typeURL, options: options)
|
||||
|
||||
case .message(let msg):
|
||||
// We should have been initialized with a typeURL, but
|
||||
// ensure it wasn't cleared.
|
||||
let url = !_typeURL.isEmpty ? _typeURL : buildTypeURL(forMessage: msg, typePrefix: defaultAnyTypeURLPrefix)
|
||||
return try serializeAnyJSON(for: msg, typeURL: url)
|
||||
return try serializeAnyJSON(for: msg, typeURL: url, options: options)
|
||||
|
||||
case .contentJSON(let contentJSON, _):
|
||||
var jsonEncoder = JSONEncoder()
|
||||
@ -409,6 +413,8 @@ extension AnyMessageStorage {
|
||||
jsonEncoder.putStringValue(value: _typeURL)
|
||||
if !contentJSON.isEmpty {
|
||||
jsonEncoder.append(staticText: ",")
|
||||
// NOTE: This doesn't really take `options` into account since it is
|
||||
// just reflecting out what was taken in originally.
|
||||
jsonEncoder.append(utf8Data: contentJSON)
|
||||
}
|
||||
jsonEncoder.endObject()
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
/// Allows WKTs to provide their custom JSON encodings.
|
||||
internal protocol _CustomJSONCodable {
|
||||
func encodedJSONString() throws -> String
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String
|
||||
mutating func decodeJSON(from: inout JSONDecoder) throws
|
||||
|
||||
/// Called when the JSON `null` literal is encountered in a position where
|
||||
|
||||
@ -131,8 +131,8 @@ extension Google_Protobuf_Any: _CustomJSONCodable {
|
||||
}
|
||||
}
|
||||
|
||||
internal func encodedJSONString() throws -> String {
|
||||
return try _storage.encodedJSONString()
|
||||
internal func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
return try _storage.encodedJSONString(options: options)
|
||||
}
|
||||
|
||||
internal mutating func decodeJSON(from decoder: inout JSONDecoder) throws {
|
||||
|
||||
@ -133,7 +133,7 @@ extension Google_Protobuf_Duration: _CustomJSONCodable {
|
||||
let s = try decoder.scanner.nextQuotedString()
|
||||
(seconds, nanos) = try parseDuration(text: s)
|
||||
}
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
if let formatted = formatDuration(seconds: seconds, nanos: nanos) {
|
||||
return "\"\(formatted)\""
|
||||
} else {
|
||||
|
||||
@ -159,7 +159,7 @@ extension Google_Protobuf_FieldMask: _CustomJSONCodable {
|
||||
}
|
||||
}
|
||||
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
// Note: Proto requires alphanumeric field names, so there
|
||||
// cannot be a ',' or '"' character to mess up this formatting.
|
||||
var jsonPaths = [String]()
|
||||
|
||||
@ -26,13 +26,13 @@ extension Google_Protobuf_ListValue: ExpressibleByArrayLiteral {
|
||||
}
|
||||
|
||||
extension Google_Protobuf_ListValue: _CustomJSONCodable {
|
||||
internal func encodedJSONString() throws -> String {
|
||||
internal func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
var jsonEncoder = JSONEncoder()
|
||||
jsonEncoder.append(text: "[")
|
||||
var separator: StaticString = ""
|
||||
for v in values {
|
||||
jsonEncoder.append(staticText: separator)
|
||||
try v.serializeJSONValue(to: &jsonEncoder)
|
||||
try v.serializeJSONValue(to: &jsonEncoder, options: options)
|
||||
separator = ","
|
||||
}
|
||||
jsonEncoder.append(text: "]")
|
||||
|
||||
@ -28,10 +28,10 @@ extension Google_Protobuf_Struct: ExpressibleByDictionaryLiteral {
|
||||
}
|
||||
|
||||
extension Google_Protobuf_Struct: _CustomJSONCodable {
|
||||
internal func encodedJSONString() throws -> String {
|
||||
internal func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
var jsonEncoder = JSONEncoder()
|
||||
jsonEncoder.startObject()
|
||||
var mapVisitor = JSONMapEncodingVisitor(encoder: jsonEncoder)
|
||||
var mapVisitor = JSONMapEncodingVisitor(encoder: jsonEncoder, options: options)
|
||||
for (k,v) in fields {
|
||||
try mapVisitor.visitSingularStringField(value: k, fieldNumber: 1)
|
||||
try mapVisitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
|
||||
@ -225,7 +225,7 @@ extension Google_Protobuf_Timestamp: _CustomJSONCodable {
|
||||
(seconds, nanos) = try parseTimestamp(s: s)
|
||||
}
|
||||
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
if let formatted = formatTimestamp(seconds: seconds, nanos: nanos) {
|
||||
return "\"\(formatted)\""
|
||||
} else {
|
||||
|
||||
@ -69,9 +69,9 @@ extension Google_Protobuf_Value: ExpressibleByNilLiteral {
|
||||
}
|
||||
|
||||
extension Google_Protobuf_Value: _CustomJSONCodable {
|
||||
internal func encodedJSONString() throws -> String {
|
||||
internal func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
var jsonEncoder = JSONEncoder()
|
||||
try serializeJSONValue(to: &jsonEncoder)
|
||||
try serializeJSONValue(to: &jsonEncoder, options: options)
|
||||
return jsonEncoder.stringResult
|
||||
}
|
||||
|
||||
@ -146,14 +146,17 @@ extension Google_Protobuf_Value {
|
||||
}
|
||||
|
||||
/// Writes out the JSON representation of the value to the given encoder.
|
||||
internal func serializeJSONValue(to encoder: inout JSONEncoder) throws {
|
||||
internal func serializeJSONValue(
|
||||
to encoder: inout JSONEncoder,
|
||||
options: JSONEncodingOptions
|
||||
) throws {
|
||||
switch kind {
|
||||
case .nullValue?: encoder.putNullValue()
|
||||
case .numberValue(let v)?: encoder.putDoubleValue(value: v)
|
||||
case .stringValue(let v)?: encoder.putStringValue(value: v)
|
||||
case .boolValue(let v)?: encoder.putBoolValue(value: v)
|
||||
case .structValue(let v)?: encoder.append(text: try v.jsonString())
|
||||
case .listValue(let v)?: encoder.append(text: try v.jsonString())
|
||||
case .structValue(let v)?: encoder.append(text: try v.jsonString(options: options))
|
||||
case .listValue(let v)?: encoder.append(text: try v.jsonString(options: options))
|
||||
case nil: throw JSONEncodingError.missingValue
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ extension Google_Protobuf_DoubleValue:
|
||||
self.init(floatLiteral)
|
||||
}
|
||||
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
var encoder = JSONEncoder()
|
||||
encoder.putDoubleValue(value: value)
|
||||
return encoder.stringResult
|
||||
@ -75,7 +75,7 @@ extension Google_Protobuf_FloatValue:
|
||||
self.init(floatLiteral)
|
||||
}
|
||||
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
var encoder = JSONEncoder()
|
||||
encoder.putFloatValue(value: value)
|
||||
return encoder.stringResult
|
||||
@ -103,7 +103,7 @@ extension Google_Protobuf_Int64Value:
|
||||
self.init(integerLiteral)
|
||||
}
|
||||
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
var encoder = JSONEncoder()
|
||||
encoder.putInt64(value: value)
|
||||
return encoder.stringResult
|
||||
@ -131,7 +131,7 @@ extension Google_Protobuf_UInt64Value:
|
||||
self.init(integerLiteral)
|
||||
}
|
||||
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
var encoder = JSONEncoder()
|
||||
encoder.putUInt64(value: value)
|
||||
return encoder.stringResult
|
||||
@ -159,7 +159,7 @@ extension Google_Protobuf_Int32Value:
|
||||
self.init(integerLiteral)
|
||||
}
|
||||
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
return String(value)
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@ extension Google_Protobuf_UInt32Value:
|
||||
self.init(integerLiteral)
|
||||
}
|
||||
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
return String(value)
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ extension Google_Protobuf_BoolValue:
|
||||
self.init(booleanLiteral)
|
||||
}
|
||||
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
return value ? "true" : "false"
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ extension Google_Protobuf_StringValue:
|
||||
self.init(unicodeScalarLiteral)
|
||||
}
|
||||
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
var encoder = JSONEncoder()
|
||||
encoder.putStringValue(value: value)
|
||||
return encoder.stringResult
|
||||
@ -269,7 +269,7 @@ extension Google_Protobuf_BytesValue: ProtobufWrapper, _CustomJSONCodable {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
func encodedJSONString() throws -> String {
|
||||
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
|
||||
var encoder = JSONEncoder()
|
||||
encoder.putBytesValue(value: value)
|
||||
return encoder.stringResult
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
// Sources/SwiftProtobuf/JSONEncodingOptions.swift - JSON encoding options
|
||||
//
|
||||
// Copyright (c) 2014 - 2018 Apple Inc. and the project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See LICENSE.txt for license information:
|
||||
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
///
|
||||
/// JSON encoding options
|
||||
///
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// Options for JSONEncoding.
|
||||
public struct JSONEncodingOptions {
|
||||
|
||||
/// Always print enums as ints. By default they are printed as strings.
|
||||
public var alwaysPrintEnumsAsInts: Bool = false
|
||||
|
||||
public init() {}
|
||||
}
|
||||
@ -19,6 +19,7 @@ internal struct JSONEncodingVisitor: Visitor {
|
||||
|
||||
private var encoder = JSONEncoder()
|
||||
private var nameMap: _NameMap
|
||||
private let options: JSONEncodingOptions
|
||||
|
||||
/// The JSON text produced by the visitor, as raw UTF8 bytes.
|
||||
var dataResult: Data {
|
||||
@ -32,21 +33,23 @@ internal struct JSONEncodingVisitor: Visitor {
|
||||
|
||||
/// Creates a new visitor for serializing a message of the given type to JSON
|
||||
/// format.
|
||||
init(type: Message.Type) throws {
|
||||
init(type: Message.Type, options: JSONEncodingOptions) throws {
|
||||
if let nameProviding = type as? _ProtoNameProviding.Type {
|
||||
self.nameMap = nameProviding._protobuf_nameMap
|
||||
} else {
|
||||
throw JSONEncodingError.missingFieldNames
|
||||
}
|
||||
self.options = options
|
||||
}
|
||||
|
||||
/// Creates a new visitor that serializes the given message to JSON format.
|
||||
init(message: Message) throws {
|
||||
init(message: Message, options: JSONEncodingOptions) throws {
|
||||
if let nameProviding = message as? _ProtoNameProviding {
|
||||
self.nameMap = type(of: nameProviding)._protobuf_nameMap
|
||||
} else {
|
||||
throw JSONEncodingError.missingFieldNames
|
||||
}
|
||||
self.options = options
|
||||
}
|
||||
|
||||
mutating func startArray() {
|
||||
@ -154,7 +157,7 @@ internal struct JSONEncodingVisitor: Visitor {
|
||||
|
||||
mutating func visitSingularEnumField<E: Enum>(value: E, fieldNumber: Int) throws {
|
||||
try startField(for: fieldNumber)
|
||||
if let n = value.name {
|
||||
if !options.alwaysPrintEnumsAsInts, let n = value.name {
|
||||
encoder.appendQuoted(name: n)
|
||||
} else {
|
||||
encoder.putEnumInt(value: value.rawValue)
|
||||
@ -163,7 +166,7 @@ internal struct JSONEncodingVisitor: Visitor {
|
||||
|
||||
mutating func visitSingularMessageField<M: Message>(value: M, fieldNumber: Int) throws {
|
||||
try startField(for: fieldNumber)
|
||||
let json = try value.jsonUTF8Data()
|
||||
let json = try value.jsonUTF8Data(options: options)
|
||||
encoder.append(utf8Data: json)
|
||||
}
|
||||
|
||||
@ -259,9 +262,10 @@ internal struct JSONEncodingVisitor: Visitor {
|
||||
}
|
||||
|
||||
mutating func visitRepeatedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
|
||||
let alwaysPrintEnumsAsInts = options.alwaysPrintEnumsAsInts
|
||||
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
|
||||
(encoder: inout JSONEncoder, v: E) throws in
|
||||
if let n = v.name {
|
||||
if !alwaysPrintEnumsAsInts, let n = v.name {
|
||||
encoder.appendQuoted(name: n)
|
||||
} else {
|
||||
encoder.putEnumInt(value: v.rawValue)
|
||||
@ -270,9 +274,10 @@ internal struct JSONEncodingVisitor: Visitor {
|
||||
}
|
||||
|
||||
mutating func visitRepeatedMessageField<M: Message>(value: [M], fieldNumber: Int) throws {
|
||||
let localOptions = options
|
||||
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
|
||||
(encoder: inout JSONEncoder, v: M) throws in
|
||||
let json = try v.jsonUTF8Data()
|
||||
let json = try v.jsonUTF8Data(options: localOptions)
|
||||
encoder.append(utf8Data: json)
|
||||
}
|
||||
}
|
||||
@ -289,7 +294,7 @@ internal struct JSONEncodingVisitor: Visitor {
|
||||
mutating func visitMapField<KeyType, ValueType: MapValueType>(fieldType: _ProtobufMap<KeyType, ValueType>.Type, value: _ProtobufMap<KeyType, ValueType>.BaseType, fieldNumber: Int) throws {
|
||||
try startField(for: fieldNumber)
|
||||
encoder.append(text: "{")
|
||||
var mapVisitor = JSONMapEncodingVisitor(encoder: encoder)
|
||||
var mapVisitor = JSONMapEncodingVisitor(encoder: encoder, options: options)
|
||||
for (k,v) in value {
|
||||
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &mapVisitor)
|
||||
try ValueType.visitSingular(value: v, fieldNumber: 2, with: &mapVisitor)
|
||||
@ -301,7 +306,7 @@ internal struct JSONEncodingVisitor: Visitor {
|
||||
mutating func visitMapField<KeyType, ValueType>(fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type, value: _ProtobufEnumMap<KeyType, ValueType>.BaseType, fieldNumber: Int) throws where ValueType.RawValue == Int {
|
||||
try startField(for: fieldNumber)
|
||||
encoder.append(text: "{")
|
||||
var mapVisitor = JSONMapEncodingVisitor(encoder: encoder)
|
||||
var mapVisitor = JSONMapEncodingVisitor(encoder: encoder, options: options)
|
||||
for (k, v) in value {
|
||||
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &mapVisitor)
|
||||
try mapVisitor.visitSingularEnumField(value: v, fieldNumber: 2)
|
||||
@ -313,7 +318,7 @@ internal struct JSONEncodingVisitor: Visitor {
|
||||
mutating func visitMapField<KeyType, ValueType>(fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type, value: _ProtobufMessageMap<KeyType, ValueType>.BaseType, fieldNumber: Int) throws {
|
||||
try startField(for: fieldNumber)
|
||||
encoder.append(text: "{")
|
||||
var mapVisitor = JSONMapEncodingVisitor(encoder: encoder)
|
||||
var mapVisitor = JSONMapEncodingVisitor(encoder: encoder, options: options)
|
||||
for (k,v) in value {
|
||||
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &mapVisitor)
|
||||
try mapVisitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
|
||||
@ -23,9 +23,11 @@ import Foundation
|
||||
internal struct JSONMapEncodingVisitor: SelectiveVisitor {
|
||||
private var separator: StaticString?
|
||||
internal var encoder: JSONEncoder
|
||||
private let options: JSONEncodingOptions
|
||||
|
||||
init(encoder: JSONEncoder) {
|
||||
init(encoder: JSONEncoder, options: JSONEncodingOptions) {
|
||||
self.encoder = encoder
|
||||
self.options = options
|
||||
}
|
||||
|
||||
private mutating func startKey() {
|
||||
@ -40,6 +42,13 @@ internal struct JSONMapEncodingVisitor: SelectiveVisitor {
|
||||
encoder.append(staticText: ":")
|
||||
}
|
||||
|
||||
mutating func visitSingularFloatField(value: Float, fieldNumber: Int) throws {
|
||||
// Doubles/Floats can never be map keys, only values
|
||||
assert(fieldNumber == 2)
|
||||
startValue()
|
||||
encoder.putFloatValue(value: value)
|
||||
}
|
||||
|
||||
mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
|
||||
// Doubles/Floats can never be map keys, only values
|
||||
assert(fieldNumber == 2)
|
||||
@ -86,6 +95,30 @@ internal struct JSONMapEncodingVisitor: SelectiveVisitor {
|
||||
encoder.putUInt64(value: value)
|
||||
}
|
||||
|
||||
mutating func visitSingularSInt32Field(value: Int32, fieldNumber: Int) throws {
|
||||
try visitSingularInt32Field(value: value, fieldNumber: fieldNumber)
|
||||
}
|
||||
|
||||
mutating func visitSingularSInt64Field(value: Int64, fieldNumber: Int) throws {
|
||||
try visitSingularInt64Field(value: value, fieldNumber: fieldNumber)
|
||||
}
|
||||
|
||||
mutating func visitSingularFixed32Field(value: UInt32, fieldNumber: Int) throws {
|
||||
try visitSingularUInt32Field(value: value, fieldNumber: fieldNumber)
|
||||
}
|
||||
|
||||
mutating func visitSingularFixed64Field(value: UInt64, fieldNumber: Int) throws {
|
||||
try visitSingularUInt64Field(value: value, fieldNumber: fieldNumber)
|
||||
}
|
||||
|
||||
mutating func visitSingularSFixed32Field(value: Int32, fieldNumber: Int) throws {
|
||||
try visitSingularInt32Field(value: value, fieldNumber: fieldNumber)
|
||||
}
|
||||
|
||||
mutating func visitSingularSFixed64Field(value: Int64, fieldNumber: Int) throws {
|
||||
try visitSingularInt64Field(value: value, fieldNumber: fieldNumber)
|
||||
}
|
||||
|
||||
mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
|
||||
if fieldNumber == 1 {
|
||||
startKey()
|
||||
@ -116,7 +149,7 @@ internal struct JSONMapEncodingVisitor: SelectiveVisitor {
|
||||
// Enums can only be map values, never keys
|
||||
assert(fieldNumber == 2)
|
||||
startValue()
|
||||
if let n = value.name {
|
||||
if !options.alwaysPrintEnumsAsInts, let n = value.name {
|
||||
encoder.putStringValue(value: String(describing: n))
|
||||
} else {
|
||||
encoder.putEnumInt(value: value.rawValue)
|
||||
@ -127,7 +160,7 @@ internal struct JSONMapEncodingVisitor: SelectiveVisitor {
|
||||
// Messages can only be map values, never keys
|
||||
assert(fieldNumber == 2)
|
||||
startValue()
|
||||
let json = try value.jsonString()
|
||||
let json = try value.jsonString(options: options)
|
||||
encoder.append(text: json)
|
||||
}
|
||||
|
||||
|
||||
@ -22,9 +22,13 @@ public extension Message {
|
||||
/// serializing to JSON.
|
||||
///
|
||||
/// - Returns: A string containing the JSON serialization of the message.
|
||||
/// - Parameters:
|
||||
/// - options: The JSONEncodingOptions to use.
|
||||
/// - Throws: `JSONEncodingError` if encoding fails.
|
||||
func jsonString() throws -> String {
|
||||
let data = try jsonUTF8Data()
|
||||
func jsonString(
|
||||
options: JSONEncodingOptions = JSONEncodingOptions()
|
||||
) throws -> String {
|
||||
let data = try jsonUTF8Data(options: options)
|
||||
return String(data: data, encoding: String.Encoding.utf8)!
|
||||
}
|
||||
|
||||
@ -34,14 +38,18 @@ public extension Message {
|
||||
/// serializing to JSON.
|
||||
///
|
||||
/// - Returns: A Data containing the JSON serialization of the message.
|
||||
/// - Parameters:
|
||||
/// - options: The JSONEncodingOptions to use.
|
||||
/// - Throws: `JSONEncodingError` if encoding fails.
|
||||
func jsonUTF8Data() throws -> Data {
|
||||
func jsonUTF8Data(
|
||||
options: JSONEncodingOptions = JSONEncodingOptions()
|
||||
) throws -> Data {
|
||||
if let m = self as? _CustomJSONCodable {
|
||||
let string = try m.encodedJSONString()
|
||||
let string = try m.encodedJSONString(options: options)
|
||||
let data = string.data(using: String.Encoding.utf8)! // Cannot fail!
|
||||
return data
|
||||
}
|
||||
var visitor = try JSONEncodingVisitor(message: self)
|
||||
var visitor = try JSONEncodingVisitor(message: self, options: options)
|
||||
visitor.startObject()
|
||||
try traverse(visitor: &visitor)
|
||||
visitor.endObject()
|
||||
|
||||
@ -22,10 +22,15 @@ public extension Message {
|
||||
/// serializing to JSON.
|
||||
///
|
||||
/// - Returns: A string containing the JSON serialization of the messages.
|
||||
/// - Parameter collection: The list of messages to encode.
|
||||
/// - Parameters:
|
||||
/// - collection: The list of messages to encode.
|
||||
/// - options: The JSONEncodingOptions to use.
|
||||
/// - Throws: `JSONEncodingError` if encoding fails.
|
||||
public static func jsonString<C: Collection>(from collection: C) throws -> String where C.Iterator.Element == Self {
|
||||
let data = try jsonUTF8Data(from: collection)
|
||||
public static func jsonString<C: Collection>(
|
||||
from collection: C,
|
||||
options: JSONEncodingOptions = JSONEncodingOptions()
|
||||
) throws -> String where C.Iterator.Element == Self {
|
||||
let data = try jsonUTF8Data(from: collection, options: options)
|
||||
return String(data: data, encoding: String.Encoding.utf8)!
|
||||
}
|
||||
|
||||
@ -35,10 +40,15 @@ public extension Message {
|
||||
/// serializing to JSON.
|
||||
///
|
||||
/// - Returns: A Data containing the JSON serialization of the messages.
|
||||
/// - Parameter collection: The list of messages to encode.
|
||||
/// - Parameters:
|
||||
/// - collection: The list of messages to encode.
|
||||
/// - options: The JSONEncodingOptions to use.
|
||||
/// - Throws: `JSONEncodingError` if encoding fails.
|
||||
public static func jsonUTF8Data<C: Collection>(from collection: C) throws -> Data where C.Iterator.Element == Self {
|
||||
var visitor = try JSONEncodingVisitor(type: Self.self)
|
||||
public static func jsonUTF8Data<C: Collection>(
|
||||
from collection: C,
|
||||
options: JSONEncodingOptions = JSONEncodingOptions()
|
||||
) throws -> Data where C.Iterator.Element == Self {
|
||||
var visitor = try JSONEncodingVisitor(type: Self.self, options: options)
|
||||
visitor.startArray()
|
||||
for message in collection {
|
||||
visitor.startObject()
|
||||
|
||||
@ -19,9 +19,9 @@ public struct Version {
|
||||
/// Major version.
|
||||
static public let major = 1
|
||||
/// Minor version.
|
||||
static public let minor = 1
|
||||
static public let minor = 2
|
||||
/// Revision number.
|
||||
static public let revision = 2
|
||||
static public let revision = 0
|
||||
|
||||
/// String form of the version number.
|
||||
static public let versionString = "\(major).\(minor).\(revision)"
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>6.5.2</string>
|
||||
<string>6.5.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.2</string>
|
||||
<string>3.1.4</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.1.3</string>
|
||||
<string>2.1.4</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive
|
||||
DEFINES_MODULE = YES
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
OTHER_LDFLAGS = -l"z"
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
|
||||
@ -39,7 +39,6 @@
|
||||
#import "OWSRecordTranscriptJob.h"
|
||||
#import "OWSVerificationStateSyncMessage.h"
|
||||
#import "OWSAttachmentDownloads.h"
|
||||
#import "OWSAttachmentsProcessor.h"
|
||||
#import "TSAttachment.h"
|
||||
#import "TSAttachmentPointer.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.1.2</string>
|
||||
<string>1.2.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user