Skip to content

Commit

Permalink
Replace uses of the Runtime library with stdlib (#370)
Browse files Browse the repository at this point in the history
This should allow us to remove the Runtime dependency eventually, which seems to be unstable, especially across different platforms and Swift versions.

Seems to resolve in one instance #367. There are a few other places where `typeInfo` is still used, I'll clean that up in a follow-up PR.

* Replace uses of the Runtime library with stdlib

* Remove irrelevant Runtime library imports

* Add TokamakCoreBenchmark target
  • Loading branch information
MaxDesiatov committed Jan 24, 2021
1 parent 9549282 commit e04b793
Show file tree
Hide file tree
Showing 15 changed files with 66 additions and 46 deletions.
7 changes: 7 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ let package = Package(
"TokamakCore",
]
),
.target(
name: "TokamakCoreBenchmark",
dependencies: [
"Benchmark",
"TokamakCore",
]
),
.target(
name: "TokamakStaticHTMLBenchmark",
dependencies: [
Expand Down
3 changes: 1 addition & 2 deletions Sources/TokamakCore/App/App.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Tokamak contributors
// Copyright 2020-2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -16,7 +16,6 @@
//

import CombineShim
import Runtime

/// Provides the ability to set the title of the Scene.
public protocol _TitledApp {
Expand Down
11 changes: 2 additions & 9 deletions Sources/TokamakCore/App/_AnyScene.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Tokamak contributors
// Copyright 2020-2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -15,8 +15,6 @@
// Created by Carson Katri on 7/19/20.
//

import Runtime

public struct _AnyScene: Scene {
/** The result type of `bodyClosure` allowing to disambiguate between scenes that
produce other scenes or scenes that only produce containing views.
Expand Down Expand Up @@ -63,13 +61,8 @@ public struct _AnyScene: Scene {
// swiftlint:disable:next force_cast
bodyClosure = { .scene(_AnyScene(($0 as! S).body)) }
}
// FIXME: no idea if using `mangledName` is reliable, but seems to be the only way to get
// a name of a type constructor in runtime. Should definitely check if these are different
// across modules, otherwise can cause problems with scenes with same names in different
// modules.

// swiftlint:disable:next force_try
typeConstructorName = try! typeInfo(of: type).mangledName
typeConstructorName = TokamakCore.typeConstructorName(type)
}
}

Expand Down
4 changes: 1 addition & 3 deletions Sources/TokamakCore/DynamicProperty.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Tokamak contributors
// Copyright 2020-2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -15,8 +15,6 @@
// Created by Carson Katri on 7/17/20.
//

import Runtime

public protocol DynamicProperty {
mutating func update()
}
Expand Down
3 changes: 1 addition & 2 deletions Sources/TokamakCore/MountedViews/MountedApp.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2020 Tokamak contributors
// Copyright 2018-2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -16,7 +16,6 @@
//

import CombineShim
import Runtime

// This is very similar to `MountedCompositeView`. However, the `mountedBody`
// is the computed content of the specified `Scene`, instead of having child
Expand Down
3 changes: 1 addition & 2 deletions Sources/TokamakCore/MountedViews/MountedCompositeView.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2020 Tokamak contributors
// Copyright 2018-2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -16,7 +16,6 @@
//

import CombineShim
import Runtime

final class MountedCompositeView<R: Renderer>: MountedCompositeElement<R> {
override func mount(
Expand Down
4 changes: 2 additions & 2 deletions Sources/TokamakCore/MountedViews/MountedElement.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2020 Tokamak contributors
// Copyright 2018-2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -18,7 +18,7 @@
import Runtime

/// The container for any of the possible `MountedElement` types
enum MountedElementKind {
private enum MountedElementKind {
case app(_AnyApp)
case scene(_AnyScene)
case view(AnyView)
Expand Down
4 changes: 1 addition & 3 deletions Sources/TokamakCore/MountedViews/MountedHostView.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2020 Tokamak contributors
// Copyright 2018-2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -15,8 +15,6 @@
// Created by Max Desiatov on 03/12/2018.
//

import Runtime

/* A representation of a `View`, which has a `body` of type `Never`, stored in the tree of mounted
views by `StackReconciler`.
*/
Expand Down
4 changes: 1 addition & 3 deletions Sources/TokamakCore/MountedViews/MountedScene.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Tokamak contributors
// Copyright 2020-2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import Runtime

final class MountedScene<R: Renderer>: MountedCompositeElement<R> {
let title: String?

Expand Down
26 changes: 26 additions & 0 deletions Sources/TokamakCore/Reflection/TypeInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/** Returns name of a given unapplied generic type. `Button<Text>` and
`Button<Image>` types are different, but when reconciling the tree of mounted views
they are treated the same, thus the `Button` part of the type (the type constructor)
is returned.
*/
public func typeConstructorName(_ type: Any.Type) -> String {
// FIXME: no idea if this calculation is reliable, but seems to be the only way to get
// a name of a type constructor in runtime. Should definitely check if these are different
// across modules, otherwise can cause problems with views with same names in different
// modules.
String(String(describing: type).prefix { $0 != "<" })
}
10 changes: 2 additions & 8 deletions Sources/TokamakCore/StackReconciler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ public final class StackReconciler<R: Renderer> {
}.store(in: &mountedApp.persistentSubscriptions)
}

func render<T>(
private func render<T>(
compositeElement: MountedCompositeElement<R>,
body bodyKeypath: ReferenceWritableKeyPath<MountedCompositeElement<R>, Any>,
result: KeyPath<MountedCompositeElement<R>, (Any) -> T>
Expand Down Expand Up @@ -265,14 +265,8 @@ public final class StackReconciler<R: Renderer> {
case let (mountedChild?, childBody):
let childBodyType = getElementType(childBody)

// FIXME: no idea if using `mangledName` is reliable, but seems to be the only way to get
// a name of a type constructor in runtime. Should definitely check if these are different
// across modules, otherwise can cause problems with views with same names in different
// modules.

// new child has the same type as existing child
// swiftlint:disable:next force_try
if try! mountedChild.typeConstructorName == typeInfo(of: childBodyType).mangledName {
if mountedChild.typeConstructorName == typeConstructorName(childBodyType) {
updateChild(mountedChild)
mountedChild.update(with: self)
} else {
Expand Down
12 changes: 2 additions & 10 deletions Sources/TokamakCore/Views/AnyView.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Tokamak contributors
// Copyright 2020-2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -15,8 +15,6 @@
// Created by Max Desiatov on 08/04/2020.
//

import Runtime

/// A type-erased view.
public struct AnyView: View {
/// The type of the underlying `view`.
Expand Down Expand Up @@ -48,13 +46,7 @@ public struct AnyView: View {
} else {
type = V.self

// FIXME: no idea if using `mangledName` is reliable, but seems to be the only way to get
// a name of a type constructor in runtime. Should definitely check if these are different
// across modules, otherwise can cause problems with views with same names in different
// modules.

// swiftlint:disable:next force_try
typeConstructorName = try! typeInfo(of: type).mangledName
typeConstructorName = TokamakCore.typeConstructorName(type)

bodyType = V.Body.self
self.view = view
Expand Down
16 changes: 16 additions & 0 deletions Sources/TokamakCoreBenchmark/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Benchmark
import Runtime
import TokamakCore

private let bigType = NavigationView<HStack<VStack<Button<Text>>>>.self

benchmark("mangledName Runtime") {
// swiftlint:disable:next force_try
_ = try! typeInfo(of: bigType).mangledName
}

benchmark("typeConstructorName TokamakCore") {
_ = typeConstructorName(bigType)
}

Benchmark.main()
3 changes: 1 addition & 2 deletions Sources/TokamakStaticHTML/Modifiers/ModifiedContent.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Tokamak contributors
// Copyright 2020-2021 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import Runtime
import TokamakCore

private protocol AnyModifiedContent {
Expand Down
2 changes: 2 additions & 0 deletions benchmark.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@

set -eux

swift build -c release --product TokamakCoreBenchmark
./.build/release/TokamakCoreBenchmark
swift build -c release --product TokamakStaticHTMLBenchmark
./.build/release/TokamakStaticHTMLBenchmark

0 comments on commit e04b793

Please sign in to comment.