Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ra1028 committed Jul 29, 2018
0 parents commit b3bc03b
Show file tree
Hide file tree
Showing 27 changed files with 2,999 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.DS_Store
*/build/*
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
profile
*.moved-aside
DerivedData
.idea/
*.hmap
*.xccheckout
*.xcuserstate
1 change: 1 addition & 0 deletions .swift-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4.1
15 changes: 15 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
env:
global:
- LC_CTYPE=en_US.UTF-8
matrix:
include:
- os: osx
language: objective-c
osx_image: xcode9.4
script:
- set -o pipefail
- xcodebuild build-for-testing test-without-building -scheme DifferenceKit -configuration Release -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 8' ENABLE_TESTABILITY=YES | xcpretty - c
- xcodebuild build-for-testing test-without-building -scheme DifferenceKit -configuration Release -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV' ENABLE_TESTABILITY=YES | xcpretty -c

notifications:
email: false
21 changes: 21 additions & 0 deletions Configurations/DifferenceKit.xcconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
SWIFT_VERSION = 4.1

IPHONEOS_DEPLOYMENT_TARGET = 9.0
TVOS_DEPLOYMENT_TARGET = 9.0

SDKROOT =
SUPPORTED_PLATFORMS = iphoneos iphonesimulator appletvos appletvsimulator
TARGETED_DEVICE_FAMILY = 1,2,3
VALID_ARCHS[sdk=iphoneos*] = arm64 armv7 armv7s
VALID_ARCHS[sdk=iphonesimulator*] = i386 x86_64
VALID_ARCHS[sdk=appletv*] = arm64
VALID_ARCHS[sdk=appletvsimulator*] = x86_64

CODE_SIGN_IDENTITY =
CODE_SIGN_STYLE = Manual
INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks
SKIP_INSTALL = YES
DYLIB_COMPATIBILITY_VERSION = 1
DYLIB_CURRENT_VERSION = 1
DYLIB_INSTALL_NAME_BASE = @rpath
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/Frameworks @loader_path/../Frameworks
542 changes: 542 additions & 0 deletions DifferenceKit.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http:https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B2DF86D210E2C12004D2D40"
BuildableName = "DifferenceKit.framework"
BlueprintName = "DifferenceKit"
ReferencedContainer = "container:DifferenceKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B2DF876210E2C12004D2D40"
BuildableName = "DifferenceKitTests.xctest"
BlueprintName = "DifferenceKitTests"
ReferencedContainer = "container:DifferenceKit.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B2DF86D210E2C12004D2D40"
BuildableName = "DifferenceKit.framework"
BlueprintName = "DifferenceKit"
ReferencedContainer = "container:DifferenceKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B2DF86D210E2C12004D2D40"
BuildableName = "DifferenceKit.framework"
BlueprintName = "DifferenceKit"
ReferencedContainer = "container:DifferenceKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "6B2DF86D210E2C12004D2D40"
BuildableName = "DifferenceKit.framework"
BlueprintName = "DifferenceKit"
ReferencedContainer = "container:DifferenceKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
62 changes: 62 additions & 0 deletions DifferenceKit/AnyDifferentiable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/// A type-erased differentiable value.
///
/// The `AnyDifferentiable` type hides the specific underlying types.
/// `DifferenceIdentifier` type is erased by `AnyHashable`.
/// The comparisons of whether has updated is forwards to an underlying differentiable value.
///
/// You can store mixed-type elements in collection that require `Differentiable` conformance by
/// wrapping mixed-type elements in `AnyDifferentiable`:
///
/// extension String: Differentiable {}
/// extension Int: Differentiable {}
///
/// let source: [AnyDifferentiable] = [
/// AnyDifferentiable("ABC"),
/// AnyDifferentiable(100)
/// ]
/// let target: [AnyDifferentiable] = [
/// AnyDifferentiable("ABC"),
/// AnyDifferentiable(100),
/// AnyDifferentiable(200)
/// ]
///
/// let changeset = StagedChangeset(source: source, target: target)
/// print(changeset.isEmpty) // prints "false"
public struct AnyDifferentiable: Differentiable {
/// The value wrapped by this instance.
public let base: Any
/// A type-erased identifier value for differentiation.
public let differenceIdentifier: AnyHashable

private let isUpdatedFrom: (AnyDifferentiable) -> Bool

/// Creates a type-erased differentiable value that wraps the given instance.
///
/// - Parameters:
/// - base: A differentiable value to wrap.
public init<D: Differentiable>(_ base: D) {
self.base = base
self.differenceIdentifier = AnyHashable(base.differenceIdentifier)

self.isUpdatedFrom = { source in
guard let sourceBase = source.base as? D else { return false }
return base.isUpdated(from: sourceBase)
}
}

/// Indicate whether `base` has updated from given source value.
///
/// - Parameters:
/// - source: A source value to be compared.
///
/// - Returns: A Boolean value indicating whether `base` has updated from given source value.
public func isUpdated(from source: AnyDifferentiable) -> Bool {
return isUpdatedFrom(source)
}
}

extension AnyDifferentiable: CustomDebugStringConvertible {
public var debugDescription: String {
return "AnyDifferentiable(\(String(reflecting: base))"
}
}
129 changes: 129 additions & 0 deletions DifferenceKit/Changeset.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/// A set of changes in the sectioned collection.
///
/// Changes to the section of the linear collection should be empty.
///
/// Notice that the value of the changes represents offsets of collection not index.
/// Since offsets are unordered, order is ignored when comparing two `Changeset`s.
public struct Changeset<Collection: Swift.Collection> {
/// The collection after changed.
public var data: Collection

/// The offsets of deleted sections.
public var sectionDeleted: [Int]
/// The offsets of inserted sections.
public var sectionInserted: [Int]
/// The offsets of updated sections.
public var sectionUpdated: [Int]
/// The pairs of source and target offset of moved sections.
public var sectionMoved: [(source: Int, target: Int)]

/// The paths of deleted elements.
public var elementDeleted: [ElementPath]
/// The paths of inserted elements.
public var elementInserted: [ElementPath]
/// The paths of updated elements.
public var elementUpdated: [ElementPath]
/// The pairs of source and target path of moved elements.
public var elementMoved: [(source: ElementPath, target: ElementPath)]

/// The number of all changes.
public var changesCount: Int {
return sectionDeleted.count
+ sectionInserted.count
+ sectionUpdated.count
+ sectionMoved.count
+ elementDeleted.count
+ elementInserted.count
+ elementUpdated.count
+ elementMoved.count
}

/// A Boolean value indicating whether has changes.
public var hasChanges: Bool {
return changesCount > 0
}

/// Creates a new `Changeset`.
///
/// - Parameters:
/// - data: The collection after changed.
/// - sectionDeleted: The offsets of deleted sections.
/// - sectionInserted: The offsets of inserted sections.
/// - sectionUpdated: The offsets of updated sections.
/// - sectionMoved: The pairs of source and target offset of moved sections.
/// - elementDeleted: The paths of deleted elements.
/// - elementInserted: The paths of inserted elements.
/// - elementUpdated: The paths of updated elements.
/// - elementMoved: The pairs of source and target path of moved elements.
public init(
data: Collection,
sectionDeleted: [Int] = [],
sectionInserted: [Int] = [],
sectionUpdated: [Int] = [],
sectionMoved: [(source: Int, target: Int)] = [],
elementDeleted: [ElementPath] = [],
elementInserted: [ElementPath] = [],
elementUpdated: [ElementPath] = [],
elementMoved: [(source: ElementPath, target: ElementPath)] = []
) {
self.data = data
self.sectionDeleted = sectionDeleted
self.sectionInserted = sectionInserted
self.sectionUpdated = sectionUpdated
self.sectionMoved = sectionMoved
self.elementDeleted = elementDeleted
self.elementInserted = elementInserted
self.elementUpdated = elementUpdated
self.elementMoved = elementMoved
}
}

extension Changeset: Equatable where Collection: Equatable {
public static func == (lhs: Changeset, rhs: Changeset) -> Bool {
return lhs.data == rhs.data
&& Set(lhs.sectionDeleted) == Set(rhs.sectionDeleted)
&& Set(lhs.sectionInserted) == Set(rhs.sectionInserted)
&& Set(lhs.sectionUpdated) == Set(rhs.sectionUpdated)
&& Set(lhs.sectionMoved.map(HashablePair.init)) == Set(rhs.sectionMoved.map(HashablePair.init))
&& Set(lhs.elementDeleted) == Set(rhs.elementDeleted)
&& Set(lhs.elementInserted) == Set(rhs.elementInserted)
&& Set(lhs.elementUpdated) == Set(rhs.elementUpdated)
&& Set(lhs.elementMoved.map(HashablePair.init)) == Set(rhs.elementMoved.map(HashablePair.init))
}
}

extension Changeset: CustomDebugStringConvertible {
public var debugDescription: String {
guard !data.isEmpty || hasChanges else {
return "Changeset(data: [])"
}

var description = """
Changeset(
data: \(data.isEmpty ? "[]" : "[\n \(data.map { "\($0)" }.joined(separator: ",\n").split(separator: "\n").joined(separator: "\n "))\n ]")
"""

func appendDescription<T>(name: String, elements: [T]) {
guard !elements.isEmpty else { return }

description += ",\n \(name): [\n \(elements.map { "\($0)" }.joined(separator: ",\n").split(separator: "\n").joined(separator: "\n "))\n ]"
}

appendDescription(name: "sectionDeleted", elements: sectionDeleted)
appendDescription(name: "sectionInserted", elements: sectionInserted)
appendDescription(name: "sectionUpdated", elements: sectionUpdated)
appendDescription(name: "sectionMoved", elements: sectionMoved)
appendDescription(name: "elementDeleted", elements: elementDeleted)
appendDescription(name: "elementInserted", elements: elementInserted)
appendDescription(name: "elementUpdated", elements: elementUpdated)
appendDescription(name: "elementMoved", elements: elementMoved)

description += "\n)"
return description
}
}

private struct HashablePair<H: Hashable>: Hashable {
let first: H
let second: H
}
Loading

0 comments on commit b3bc03b

Please sign in to comment.