Convert protocol hierarchy to class hierarchy

This has no value unto itself, but is necessary for adding default
arguments to the ConstraintDescriptionRelatable methods, which we'll
need to instrument in source locations.
This commit is contained in:
Akiva Leffert 2015-10-12 01:53:46 -04:00
parent cd49354220
commit 104ce8895c
2 changed files with 193 additions and 142 deletions

View File

@ -106,138 +106,231 @@ extension View : RelationTarget {
}
}
extension ConstraintItem : RelationTarget {
public var constraintItem : ConstraintItem {
return self
}
}
/**
Used to expose the final API of a `ConstraintDescription` which allows getting a constraint from it
*/
public protocol ConstraintDescriptionFinalizable: class {
public class ConstraintDescriptionFinalizable {
var constraint: Constraint { get }
private let backing : ConstraintDescription
internal init(_ backing : ConstraintDescription) {
self.backing = backing
}
public var constraint: Constraint {
return backing.constraint
}
}
/**
Used to expose priority APIs
*/
public protocol ConstraintDescriptionPriortizable: ConstraintDescriptionFinalizable {
public class ConstraintDescriptionPriortizable: ConstraintDescriptionFinalizable {
func priority(priority: FloatConvertible) -> ConstraintDescriptionFinalizable
func priorityRequired() -> ConstraintDescriptionFinalizable
func priorityHigh() -> ConstraintDescriptionFinalizable
func priorityMedium() -> ConstraintDescriptionFinalizable
func priorityLow() -> ConstraintDescriptionFinalizable
public func priority(priority: FloatConvertible) -> ConstraintDescriptionFinalizable {
return ConstraintDescriptionFinalizable(self.backing.priority(priority))
}
public func priorityRequired() -> ConstraintDescriptionFinalizable {
return ConstraintDescriptionFinalizable(self.backing.priorityRequired())
}
public func priorityHigh() -> ConstraintDescriptionFinalizable {
return ConstraintDescriptionFinalizable(self.backing.priorityHigh())
}
public func priorityMedium() -> ConstraintDescriptionFinalizable {
return ConstraintDescriptionFinalizable(self.backing.priorityMedium())
}
public func priorityLow() -> ConstraintDescriptionFinalizable {
return ConstraintDescriptionFinalizable(self.backing.priorityLow())
}
}
/**
Used to expose multiplier & constant APIs
*/
public protocol ConstraintDescriptionEditable: ConstraintDescriptionPriortizable {
public class ConstraintDescriptionEditable: ConstraintDescriptionPriortizable {
func multipliedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable
public func multipliedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.multipliedBy(amount))
}
func dividedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable
func offset(amount: FloatConvertible) -> ConstraintDescriptionEditable
func offset(amount: CGPoint) -> ConstraintDescriptionEditable
func offset(amount: CGSize) -> ConstraintDescriptionEditable
func offset(amount: EdgeInsets) -> ConstraintDescriptionEditable
public func dividedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable {
return self.multipliedBy(1 / amount.floatValue)
}
func inset(amount: FloatConvertible) -> ConstraintDescriptionEditable
func inset(amount: EdgeInsets) -> ConstraintDescriptionEditable
public func offset(amount : FloatConvertible) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.offset(amount))
}
public func offset(amount: CGPoint) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.offset(amount))
}
public func offset(amount: CGSize) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.offset(amount))
}
public func offset(amount: EdgeInsets) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.offset(amount))
}
public func inset(amount: FloatConvertible) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.inset(amount))
}
public func inset(amount: EdgeInsets) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.inset(amount))
}
}
/**
Used to expose relation APIs
*/
public protocol ConstraintDescriptionRelatable: class {
public class ConstraintDescriptionRelatable {
private let backing : ConstraintDescription
func equalTo(other: ConstraintItem) -> ConstraintDescriptionEditable
func equalTo(other: RelationTarget) -> ConstraintDescriptionEditable
@available(iOS 7.0, *)
func equalTo(other: LayoutSupport) -> ConstraintDescriptionEditable
init(_ backing : ConstraintDescription) {
self.backing = backing
}
func lessThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable
func lessThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable
@available(iOS 7.0, *)
func lessThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable
public func equalTo(other: RelationTarget) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .Equal))
}
public func equalTo(other: LayoutSupport) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .Equal))
}
func greaterThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable
func greaterThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable
@available(iOS 7.0, *)
func greaterThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable
public func lessThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .LessThanOrEqualTo))
}
public func lessThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .LessThanOrEqualTo))
}
public func greaterThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .GreaterThanOrEqualTo))
}
public func greaterThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable {
return ConstraintDescriptionEditable(self.backing.constrainTo(other, relation : .GreaterThanOrEqualTo))
}
}
/**
Used to expose chaining APIs
*/
public protocol ConstraintDescriptionExtendable: ConstraintDescriptionRelatable {
public class ConstraintDescriptionExtendable: ConstraintDescriptionRelatable {
var left: ConstraintDescriptionExtendable { get }
var top: ConstraintDescriptionExtendable { get }
var bottom: ConstraintDescriptionExtendable { get }
var right: ConstraintDescriptionExtendable { get }
var leading: ConstraintDescriptionExtendable { get }
var trailing: ConstraintDescriptionExtendable { get }
var width: ConstraintDescriptionExtendable { get }
var height: ConstraintDescriptionExtendable { get }
var centerX: ConstraintDescriptionExtendable { get }
var centerY: ConstraintDescriptionExtendable { get }
var baseline: ConstraintDescriptionExtendable { get }
public var left: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.left)
}
public var top: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.top)
}
public var bottom: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.bottom)
}
public var right: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.right)
}
public var leading: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.leading)
}
public var trailing: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.trailing)
}
public var width: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.width)
}
public var height: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.height)
}
public var centerX: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.centerX)
}
public var centerY: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.centerY)
}
public var baseline: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.baseline)
}
@available(iOS 8.0, *)
var firstBaseline: ConstraintDescriptionExtendable { get }
public var firstBaseline: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.firstBaseline)
}
@available(iOS 8.0, *)
var leftMargin: ConstraintDescriptionExtendable { get }
public var leftMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.leftMargin)
}
@available(iOS 8.0, *)
var rightMargin: ConstraintDescriptionExtendable { get }
public var rightMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.rightMargin)
}
@available(iOS 8.0, *)
var topMargin: ConstraintDescriptionExtendable { get }
public var topMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.topMargin)
}
@available(iOS 8.0, *)
var bottomMargin: ConstraintDescriptionExtendable { get }
public var bottomMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.bottomMargin)
}
@available(iOS 8.0, *)
var leadingMargin: ConstraintDescriptionExtendable { get }
public var leadingMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.leadingMargin)
}
@available(iOS 8.0, *)
var trailingMargin: ConstraintDescriptionExtendable { get }
public var trailingMargin: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.trailingMargin)
}
@available(iOS 8.0, *)
var centerXWithinMargins: ConstraintDescriptionExtendable { get }
public var centerXWithinMargins: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.centerXWithinMargins)
}
@available(iOS 8.0, *)
var centerYWithinMargins: ConstraintDescriptionExtendable { get }
public var centerYWithinMargins: ConstraintDescriptionExtendable {
return ConstraintDescriptionExtendable(self.backing.centerYWithinMargins)
}
}
/**
Used to internally manage building constraint
*/
internal class ConstraintDescription: ConstraintDescriptionExtendable, ConstraintDescriptionEditable, ConstraintDescriptionFinalizable {
internal class ConstraintDescription {
internal var left: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Left) }
internal var top: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Top) }
internal var right: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Right) }
internal var bottom: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Bottom) }
internal var leading: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Leading) }
internal var trailing: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Trailing) }
internal var width: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Width) }
internal var height: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Height) }
internal var centerX: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterX) }
internal var centerY: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterY) }
internal var baseline: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.Baseline) }
private var left: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Left) }
private var top: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Top) }
private var right: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Right) }
private var bottom: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Bottom) }
private var leading: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Leading) }
private var trailing: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Trailing) }
private var width: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Width) }
private var height: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Height) }
private var centerX: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterX) }
private var centerY: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterY) }
private var baseline: ConstraintDescription { return self.addConstraint(ConstraintAttributes.Baseline) }
@available(iOS 8.0, *)
internal var firstBaseline: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.FirstBaseline) }
private var firstBaseline: ConstraintDescription { return self.addConstraint(ConstraintAttributes.FirstBaseline) }
@available(iOS 8.0, *)
internal var leftMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.LeftMargin) }
private var leftMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.LeftMargin) }
@available(iOS 8.0, *)
internal var rightMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.RightMargin) }
private var rightMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.RightMargin) }
@available(iOS 8.0, *)
internal var topMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.TopMargin) }
private var topMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.TopMargin) }
@available(iOS 8.0, *)
internal var bottomMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.BottomMargin) }
private var bottomMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.BottomMargin) }
@available(iOS 8.0, *)
internal var leadingMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.LeadingMargin) }
private var leadingMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.LeadingMargin) }
@available(iOS 8.0, *)
internal var trailingMargin: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.TrailingMargin) }
private var trailingMargin: ConstraintDescription { return self.addConstraint(ConstraintAttributes.TrailingMargin) }
@available(iOS 8.0, *)
internal var centerXWithinMargins: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterXWithinMargins) }
private var centerXWithinMargins: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterXWithinMargins) }
@available(iOS 8.0, *)
internal var centerYWithinMargins: ConstraintDescriptionExtendable { return self.addConstraint(ConstraintAttributes.CenterYWithinMargins) }
private var centerYWithinMargins: ConstraintDescription { return self.addConstraint(ConstraintAttributes.CenterYWithinMargins) }
// MARK: initializer
@ -246,108 +339,69 @@ internal class ConstraintDescription: ConstraintDescriptionExtendable, Constrain
self.toItem = ConstraintItem(object: nil, attributes: ConstraintAttributes.None)
}
// MARK: equalTo
internal func equalTo(other: ConstraintItem) -> ConstraintDescriptionEditable {
return self.constrainTo(other, relation: .Equal)
}
internal func equalTo(other: RelationTarget) -> ConstraintDescriptionEditable {
return self.constrainTo(other, relation: .Equal)
}
@available(iOS 7.0, *)
internal func equalTo(other: LayoutSupport) -> ConstraintDescriptionEditable {
return self.constrainTo(other, relation: .Equal)
}
// MARK: lessThanOrEqualTo
internal func lessThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable {
return self.constrainTo(other, relation: .LessThanOrEqualTo)
}
internal func lessThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable {
return self.constrainTo(other, relation: .LessThanOrEqualTo)
}
@available(iOS 7.0, *)
internal func lessThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable {
return self.constrainTo(other, relation: .LessThanOrEqualTo)
}
// MARK: greaterThanOrEqualTo
internal func greaterThanOrEqualTo(other: ConstraintItem) -> ConstraintDescriptionEditable {
return self.constrainTo(other, relation: .GreaterThanOrEqualTo)
}
internal func greaterThanOrEqualTo(other: RelationTarget) -> ConstraintDescriptionEditable {
return self.constrainTo(other, relation: .GreaterThanOrEqualTo)
}
@available(iOS 7.0, *)
internal func greaterThanOrEqualTo(other: LayoutSupport) -> ConstraintDescriptionEditable {
return self.constrainTo(other, relation: .GreaterThanOrEqualTo)
}
// MARK: multiplier
internal func multipliedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable {
private func multipliedBy(amount: FloatConvertible) -> ConstraintDescription {
self.multiplier = amount.floatValue
return self
}
internal func dividedBy(amount: FloatConvertible) -> ConstraintDescriptionEditable {
private func dividedBy(amount: FloatConvertible) -> ConstraintDescription {
self.multiplier = 1.0 / amount.floatValue;
return self
}
// MARK: offset
internal func offset(amount: FloatConvertible) -> ConstraintDescriptionEditable {
private func offset(amount: FloatConvertible) -> ConstraintDescription {
self.constant = amount.floatValue
return self
}
internal func offset(amount: CGPoint) -> ConstraintDescriptionEditable {
private func offset(amount: CGPoint) -> ConstraintDescription {
self.constant = amount
return self
}
internal func offset(amount: CGSize) -> ConstraintDescriptionEditable {
private func offset(amount: CGSize) -> ConstraintDescription {
self.constant = amount
return self
}
internal func offset(amount: EdgeInsets) -> ConstraintDescriptionEditable {
private func offset(amount: EdgeInsets) -> ConstraintDescription {
self.constant = amount
return self
}
// MARK: inset
internal func inset(amount: FloatConvertible) -> ConstraintDescriptionEditable {
private func inset(amount: FloatConvertible) -> ConstraintDescription {
let value = CGFloat(amount.floatValue)
self.constant = EdgeInsets(top: value, left: value, bottom: -value, right: -value)
return self
}
internal func inset(amount: EdgeInsets) -> ConstraintDescriptionEditable {
private func inset(amount: EdgeInsets) -> ConstraintDescription {
self.constant = EdgeInsets(top: amount.top, left: amount.left, bottom: -amount.bottom, right: -amount.right)
return self
}
// MARK: priority
internal func priority(priority: FloatConvertible) -> ConstraintDescriptionFinalizable {
private func priority(priority: FloatConvertible) -> ConstraintDescription {
self.priority = priority.floatValue
return self
}
internal func priorityRequired() -> ConstraintDescriptionFinalizable {
private func priorityRequired() -> ConstraintDescription {
return self.priority(1000.0)
}
internal func priorityHigh() -> ConstraintDescriptionFinalizable {
private func priorityHigh() -> ConstraintDescription {
return self.priority(750.0)
}
internal func priorityMedium() -> ConstraintDescriptionFinalizable {
private func priorityMedium() -> ConstraintDescription {
#if os(iOS) || os(tvOS)
return self.priority(500.0)
#else
return self.priority(501.0)
#endif
}
internal func priorityLow() -> ConstraintDescriptionFinalizable {
private func priorityLow() -> ConstraintDescription {
return self.priority(250.0)
}
@ -416,35 +470,32 @@ internal class ConstraintDescription: ConstraintDescriptionExtendable, Constrain
return self
}
private func constrainTo(other: ConstraintItem, relation: ConstraintRelation) -> ConstraintDescription {
if other.attributes != ConstraintAttributes.None {
let toLayoutAttributes = other.attributes.layoutAttributes
private func constrainTo(other: RelationTarget, relation: ConstraintRelation) -> ConstraintDescription {
if let constant = other as? FloatConvertible {
self.constant = constant.floatValue
}
let item = other.constraintItem
if item.attributes != ConstraintAttributes.None {
let toLayoutAttributes = item.attributes.layoutAttributes
if toLayoutAttributes.count > 1 {
let fromLayoutAttributes = self.fromItem.attributes.layoutAttributes
if toLayoutAttributes != fromLayoutAttributes {
NSException(name: "Invalid Constraint", reason: "Cannot constrain to multiple non identical attributes", userInfo: nil).raise()
return self
}
other.attributes = ConstraintAttributes.None
item.attributes = ConstraintAttributes.None
}
}
self.toItem = other
self.toItem = item
self.relation = relation
return self
}
private func constrainTo(other: RelationTarget, relation: ConstraintRelation) -> ConstraintDescription {
return constrainTo(other.constraintItem, relation: relation)
}
@available(iOS 7.0, *)
private func constrainTo(other: LayoutSupport, relation: ConstraintRelation) -> ConstraintDescription {
return constrainTo(ConstraintItem(object: self, attributes: ConstraintAttributes.None), relation: relation)
}
private func constrainTo(other: FloatConvertible, relation: ConstraintRelation) -> ConstraintDescription {
self.constant = other.floatValue
return constrainTo(ConstraintItem(object: nil, attributes: ConstraintAttributes.None), relation: relation)
return constrainTo(ConstraintItem(object: other, attributes: ConstraintAttributes.None), relation: relation, location: location)
}
}

View File

@ -129,11 +129,11 @@ public class ConstraintMaker {
internal let view: View
internal var constraintDescriptions = [ConstraintDescription]()
internal func makeConstraintDescription(attributes: ConstraintAttributes) -> ConstraintDescription {
internal func makeConstraintDescription(attributes: ConstraintAttributes) -> ConstraintDescriptionExtendable {
let item = ConstraintItem(object: self.view, attributes: attributes)
let constraintDescription = ConstraintDescription(fromItem: item)
self.constraintDescriptions.append(constraintDescription)
return constraintDescription
return ConstraintDescriptionExtendable(constraintDescription)
}
internal class func prepareConstraints(view view: View, file: String = "Unknown", line: UInt = 0, @noescape closure: (make: ConstraintMaker) -> Void) -> [Constraint] {