Skip to content

Commit

Permalink
Change the symbol generation algorithm. Rename the struct.
Browse files Browse the repository at this point in the history
  • Loading branch information
andersio committed Apr 9, 2019
1 parent 86da5eb commit 73f6360
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 167 deletions.
16 changes: 8 additions & 8 deletions Bento.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@
65E3ECAC2113591500869DF3 /* FocusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E3ECAB2113591500869DF3 /* FocusableView.swift */; };
65E3ECAE2113594600869DF3 /* BentoCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E3ECAD2113594600869DF3 /* BentoCollectionView.swift */; };
65E3ECB02113598700869DF3 /* UIKit+BentoCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E3ECAF2113598700869DF3 /* UIKit+BentoCollectionView.swift */; };
65E4D8B8225D0AC100CA7CB3 /* ReusabilityHintCombiner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E4D8B7225D0AC100CA7CB3 /* ReusabilityHintCombiner.swift */; };
65E4D8BA225D11C700CA7CB3 /* ReusabilityHintCombinerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E4D8B9225D11C700CA7CB3 /* ReusabilityHintCombinerTests.swift */; };
65E4D8B8225D0AC100CA7CB3 /* ReusabilityHint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E4D8B7225D0AC100CA7CB3 /* ReusabilityHint.swift */; };
65E4D8BA225D11C700CA7CB3 /* ReusabilityHintTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E4D8B9225D11C700CA7CB3 /* ReusabilityHintTests.swift */; };
740921B620ACDDDA00B59F5C /* IfTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 740921B520ACDDDA00B59F5C /* IfTests.swift */; };
740921B820ACE5EC00B59F5C /* ConcatenationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 740921B720ACE5EC00B59F5C /* ConcatenationTests.swift */; };
74208FA12083B1F00062CC8D /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 74208FA22083B1F00062CC8D /* Nimble.framework */; };
Expand Down Expand Up @@ -211,8 +211,8 @@
65E3ECAB2113591500869DF3 /* FocusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FocusableView.swift; sourceTree = "<group>"; };
65E3ECAD2113594600869DF3 /* BentoCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BentoCollectionView.swift; sourceTree = "<group>"; };
65E3ECAF2113598700869DF3 /* UIKit+BentoCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIKit+BentoCollectionView.swift"; sourceTree = "<group>"; };
65E4D8B7225D0AC100CA7CB3 /* ReusabilityHintCombiner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReusabilityHintCombiner.swift; sourceTree = "<group>"; };
65E4D8B9225D11C700CA7CB3 /* ReusabilityHintCombinerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReusabilityHintCombinerTests.swift; sourceTree = "<group>"; };
65E4D8B7225D0AC100CA7CB3 /* ReusabilityHint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReusabilityHint.swift; sourceTree = "<group>"; };
65E4D8B9225D11C700CA7CB3 /* ReusabilityHintTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReusabilityHintTests.swift; sourceTree = "<group>"; };
740921B520ACDDDA00B59F5C /* IfTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IfTests.swift; sourceTree = "<group>"; };
740921B720ACE5EC00B59F5C /* ConcatenationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcatenationTests.swift; sourceTree = "<group>"; };
74208FA22083B1F00062CC8D /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -435,7 +435,7 @@
65E3ECA521133C9400869DF3 /* UIKit+CollectionViewFocus.swift */,
582D9986217F87B100C67B0D /* ComponentLifecycleAware.swift */,
65020C312203186400DC8F42 /* NativeView.swift */,
65E4D8B7225D0AC100CA7CB3 /* ReusabilityHintCombiner.swift */,
65E4D8B7225D0AC100CA7CB3 /* ReusabilityHint.swift */,
);
path = Renderable;
sourceTree = "<group>";
Expand All @@ -453,7 +453,7 @@
5830C5E621F22DDC0029044B /* ComponentLifecycleAware.swift */,
651E75BF221005E300130866 /* UIKitContainerDiffApplicationTests.swift */,
58FC4421207CF29F00DA3614 /* Info.plist */,
65E4D8B9225D11C700CA7CB3 /* ReusabilityHintCombinerTests.swift */,
65E4D8B9225D11C700CA7CB3 /* ReusabilityHintTests.swift */,
);
path = BentoTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -741,7 +741,7 @@
9AF4786C2120CA7500F87E21 /* BentoReusableView.swift in Sources */,
61B64BB6208745730092082C /* CollectionViewContainerCell.swift in Sources */,
65E3ECA2211317EA00869DF3 /* FocusCoordinator.swift in Sources */,
65E4D8B8225D0AC100CA7CB3 /* ReusabilityHintCombiner.swift in Sources */,
65E4D8B8225D0AC100CA7CB3 /* ReusabilityHint.swift in Sources */,
65E3ECAE2113594600869DF3 /* BentoCollectionView.swift in Sources */,
65E3ECAC2113591500869DF3 /* FocusableView.swift in Sources */,
A9509880661501C40B50E453 /* TableViewHeaderFooterView.swift in Sources */,
Expand All @@ -760,7 +760,7 @@
58D27BA721B83B2700DC9600 /* DeletableTests.swift in Sources */,
653D460B2256665000CF3E4C /* AdapterStoreTests.swift in Sources */,
58FC4429207CF2BB00DA3614 /* TestRenderable.swift in Sources */,
65E4D8BA225D11C700CA7CB3 /* ReusabilityHintCombinerTests.swift in Sources */,
65E4D8BA225D11C700CA7CB3 /* ReusabilityHintTests.swift in Sources */,
5830C5E721F22DDC0029044B /* ComponentLifecycleAware.swift in Sources */,
740921B620ACDDDA00B59F5C /* IfTests.swift in Sources */,
740921B820ACE5EC00B59F5C /* ConcatenationTests.swift in Sources */,
Expand Down
10 changes: 5 additions & 5 deletions Bento/Renderable/AnyRenderable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public struct AnyRenderable: Renderable {
base.render(in: view)
}

public func makeReusabilityHint(using combiner: inout ReusabilityHintCombiner) {
base.makeReusabilityHint(using: &combiner)
public func makeReusabilityHint(_ hint: inout ReusabilityHint) {
base.makeReusabilityHint(&hint)
}

func cast<T>(to type: T.Type) -> T? {
Expand Down Expand Up @@ -86,8 +86,8 @@ class AnyRenderableBox<Base: Renderable>: AnyRenderableBoxBase {
base.render(in: view as! Base.View)
}

override func makeReusabilityHint(using combiner: inout ReusabilityHintCombiner) {
base.makeReusabilityHint(using: &combiner)
override func makeReusabilityHint(_ hint: inout ReusabilityHint) {
base.makeReusabilityHint(&hint)
}

override func cast<T>(to type: T.Type) -> T? {
Expand All @@ -108,6 +108,6 @@ class AnyRenderableBoxBase {
return AnyRenderable(self)
}
func render(in view: UIView) { fatalError() }
func makeReusabilityHint(using combiner: inout ReusabilityHintCombiner) { fatalError() }
func makeReusabilityHint(_ hint: inout ReusabilityHint) { fatalError() }
func cast<T>(to type: T.Type) -> T? { fatalError() }
}
23 changes: 12 additions & 11 deletions Bento/Renderable/Renderable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ public protocol Renderable {
/// // Logic to recreate the view hierarchy if types and orders of components do not match
/// }
///
/// func makeReusabilityHint(using combiner: inout ReusabilityHintCombiner) {
/// children.forEach { combiner.combine($0) }
/// func makeReusabilityHint(_ hint: inout ReusabilityHint) {
/// children.forEach { hint.combine($0) }
/// }
/// }
///
Expand All @@ -51,7 +51,7 @@ public protocol Renderable {
/// CompositeComponent(children: [C(), B(), A()])
/// ```
///
/// - important: The order of `combiner.combine(_:)` matters.
/// - important: The order of `ReusabilityHint.combine(_:)` matters.
///
/// - important: Bento always considers the component type for view reusability. So components need not combine
/// its own type again.
Expand All @@ -60,12 +60,13 @@ public protocol Renderable {
/// or dynamic view hierarchies.
///
/// - parameters:
/// - combiner: The combiner to concatenate all relevant information that affects reusability.
func makeReusabilityHint(using combiner: inout ReusabilityHintCombiner)
/// - hint: An opaque structure which may be fed with all relevant information of which Bento should take account
/// when considering view reusability.
func makeReusabilityHint(_ hint: inout ReusabilityHint)
}

public extension Renderable {
func makeReusabilityHint(using combiner: inout ReusabilityHintCombiner) {}
func makeReusabilityHint(_ hint: inout ReusabilityHint) {}

func asAnyRenderable() -> AnyRenderable {
return AnyRenderable(self)
Expand Down Expand Up @@ -99,13 +100,13 @@ internal extension Renderable {
?? type(of: self)
}

var reusabilityHintCombiner: ReusabilityHintCombiner {
var combiner = ReusabilityHintCombiner(root: self)
makeReusabilityHint(using: &combiner)
return combiner
var reusabilityHint: ReusabilityHint {
var hint = ReusabilityHint(root: self)
makeReusabilityHint(&hint)
return hint
}

var reuseIdentifier: String {
return reusabilityHintCombiner.generate()
return reusabilityHint.generate()
}
}
60 changes: 60 additions & 0 deletions Bento/Renderable/ReusabilityHint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
public struct ReusabilityHint {
internal enum Mark: Equatable {
case node(Any.Type)
case begin
case end

static func == (lhs: Mark, rhs: Mark) -> Bool {
switch (lhs, rhs) {
case let (.node(lhs), .node(rhs)):
return lhs == rhs
case (.begin, .begin), (.end, end):
return true
default:
return false
}
}
}

internal var marks: [Mark]

internal init<R: Renderable>(root: R) {
marks = [.node(root.componentType), .begin]
}

public mutating func combine<R: Renderable>(_ component: R) {
marks.append(.node(component.componentType))
marks.append(.begin)
component.makeReusabilityHint(&self)
marks.append(.end)
}

func generate() -> String {
// NOTE: It isn't quite important that we generate a very clean symbol. It only needs to be consistently
// reproduced.
var symbol = marks.reduce(into: "") { buffer, mark in
switch mark {
case let .node(type):
buffer += fullyQualifiedTypeName(of: type)
case .begin:
buffer += "["
case .end:
buffer += "]"
}
}

// NOTE: Since the root node opens with a `begin` mark, we should balance it with an `end` mark.
symbol += "]"
return symbol
}

func isCompatible(with other: ReusabilityHint) -> Bool {
return marks == other.marks
}
}

func fullyQualifiedTypeName(of type: Any.Type) -> String {
/// NOTE: `String.init(reflecting:)` gives the fully qualified type name.
// Tests would catch unexpeced type name printing behavior due to Swift runtime changes.
return String(reflecting: type)
}
27 changes: 0 additions & 27 deletions Bento/Renderable/ReusabilityHintCombiner.swift

This file was deleted.

2 changes: 1 addition & 1 deletion Bento/Views/BentoReusableView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ extension BentoReusableView {

if let oldComponent = oldComponent,
let view = containedView,
oldComponent.reusabilityHintCombiner.isCompatible(with: component.reusabilityHintCombiner) {
oldComponent.reusabilityHint.isCompatible(with: component.reusabilityHint) {
renderingView = view
} else {
renderingView = component.viewType.generate()
Expand Down
115 changes: 0 additions & 115 deletions BentoTests/ReusabilityHintCombinerTests.swift

This file was deleted.

Loading

0 comments on commit 73f6360

Please sign in to comment.