Skip to content

Commit d84c066

Browse files
committed
Merge branch 'develop' of github.com:readium/swift-toolkit into feature/tts
2 parents c9642fb + 1dae131 commit d84c066

File tree

11 files changed

+108
-30
lines changed

11 files changed

+108
-30
lines changed

Sources/Navigator/EPUB/EPUBNavigatorViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ open class EPUBNavigatorViewController: UIViewController, VisualNavigator, Selec
504504

505505
let link = spreadView.focusedResource ?? spreadView.spread.leading
506506
let href = link.href
507-
let progression = spreadView.progression(in: href)
507+
let progression = min(max(spreadView.progression(in: href), 0.0), 1.0)
508508

509509
// The positions are not always available, for example a Readium WebPub doesn't have any
510510
// unless a Publication Positions Web Service is provided.

Sources/Navigator/EPUB/EPUBReflowableSpreadView.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,9 +321,11 @@ final class EPUBReflowableSpreadView: EPUBSpreadView {
321321

322322
// Called by the javascript code to notify that scrolling ended.
323323
private func progressionDidChange(_ body: Any) {
324-
guard spreadLoaded, let bodyString = body as? String, let newProgression = Double(bodyString) else {
324+
guard spreadLoaded, let bodyString = body as? String, var newProgression = Double(bodyString) else {
325325
return
326326
}
327+
newProgression = min(max(newProgression, 0.0), 1.0)
328+
327329
if previousProgression == nil {
328330
previousProgression = progression
329331
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//
2+
// Copyright 2022 Readium Foundation. All rights reserved.
3+
// Use of this source code is governed by the BSD-style license
4+
// available in the top-level LICENSE file of the project.
5+
//
6+
7+
import Foundation
8+
9+
/// Smart pointer protecting concurrent access to its memory to avoid data races.
10+
///
11+
/// This is also a property wrapper, which makes it easy to use as:
12+
/// ```
13+
/// @Atomic var data: Int
14+
/// ```
15+
///
16+
/// The property becomes read-only, to prevent a common error when modifying the property using its
17+
/// previous value. For example:
18+
/// ```
19+
/// data += 1
20+
/// ```
21+
/// This is not safe, because it's actually two operations: a read and a write. The value might have changed
22+
/// between the moment you read it and when you write the result of incrementing the value.
23+
///
24+
/// Instead, you must use `write()` to mutate the property:
25+
/// ```
26+
/// $data.write { value in
27+
/// value += 1
28+
/// }
29+
/// ```
30+
@propertyWrapper
31+
public final class Atomic<Value> {
32+
private var value: Value
33+
34+
/// Queue used to protect accesses to `value`.
35+
///
36+
/// We could use a serial queue but that would impact performances as concurrent reads would not be
37+
/// possible. To make sure we don't get data races, writes are done using a `.barrier` flag.
38+
private let queue = DispatchQueue(label: "org.readium.Atomic", attributes: .concurrent)
39+
40+
public init(wrappedValue value: Value) {
41+
self.value = value
42+
}
43+
44+
public var wrappedValue: Value {
45+
get { read() }
46+
set { fatalError("Use $property.write { $0 = ... } to mutate this property") }
47+
}
48+
49+
public var projectedValue: Atomic<Value> {
50+
return self
51+
}
52+
53+
/// Reads the current value synchronously.
54+
public func read() -> Value {
55+
queue.sync {
56+
value
57+
}
58+
}
59+
60+
/// Reads the current value asynchronously.
61+
public func read(completion: @escaping (Value) -> Void) {
62+
queue.async {
63+
completion(self.value)
64+
}
65+
}
66+
67+
/// Writes the value synchronously in a safe way.
68+
public func write(_ changes: (inout Value) -> Void) {
69+
// The `barrier` flag here guarantees that we will never have a
70+
// concurrent read on `value` while we are modifying it. This prevents
71+
// a data race.
72+
queue.sync(flags: .barrier) {
73+
changes(&value)
74+
}
75+
}
76+
}

Sources/Shared/Toolkit/HTTP/DefaultHTTPClient.swift

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -252,45 +252,39 @@ public final class DefaultHTTPClient: NSObject, HTTPClient, Loggable, URLSession
252252
// MARK: - Task Management
253253

254254
/// On-going tasks.
255-
private var tasks: [Task] = []
256-
257-
private func findTaskIndex(_ task: URLSessionTask) -> Int? {
258-
let i = tasks.firstIndex(where: { $0.task == task})
259-
if i == nil {
260-
log(.error, "Cannot find on-going HTTP task for \(task)")
261-
}
262-
return i
263-
}
264-
255+
@Atomic private var tasks: [Task] = []
256+
265257
private func start(_ task: Task) -> Cancellable {
266-
tasks.append(task)
258+
$tasks.write { $0.append(task) }
267259
task.start()
268260
return task
269261
}
270262

263+
private func findTask(for urlTask: URLSessionTask) -> Task? {
264+
let task = tasks.first { $0.task == urlTask}
265+
if task == nil {
266+
log(.error, "Cannot find on-going HTTP task for \(urlTask)")
267+
}
268+
return task
269+
}
270+
271271

272272
// MARK: - URLSessionDataDelegate
273273

274274
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> ()) {
275-
guard let i = findTaskIndex(dataTask) else {
275+
guard let task = findTask(for: dataTask) else {
276276
completionHandler(.cancel)
277277
return
278278
}
279-
tasks[i].urlSession(session, didReceive: response, completionHandler: completionHandler)
279+
task.urlSession(session, didReceive: response, completionHandler: completionHandler)
280280
}
281281

282282
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
283-
guard let i = findTaskIndex(dataTask) else {
284-
return
285-
}
286-
tasks[i].urlSession(session, didReceive: data)
283+
findTask(for: dataTask)?.urlSession(session, didReceive: data)
287284
}
288285

289286
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
290-
guard let i = findTaskIndex(task) else {
291-
return
292-
}
293-
tasks[i].urlSession(session, didCompleteWithError: error)
287+
findTask(for: task)?.urlSession(session, didCompleteWithError: error)
294288
}
295289

296290

Support/Carthage/.xcodegen

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# XCODEGEN VERSION
2-
2.25.0
2+
2.29.0
33

44
# SPEC
55
{
@@ -7504,6 +7504,7 @@
75047504
../../Sources/Shared/Publication/Services/Locator/DefaultLocatorService.swift
75057505
../../Sources/Shared/Publication/Services/Locator/LocatorService.swift
75067506
../../Sources/Shared/Publication/Services/Positions
7507+
../../Sources/Shared/Publication/Services/Positions/InMemoryPositionsService.swift
75077508
../../Sources/Shared/Publication/Services/Positions/PerResourcePositionsService.swift
75087509
../../Sources/Shared/Publication/Services/Positions/PositionsService.swift
75097510
../../Sources/Shared/Publication/Services/PublicationService.swift
@@ -7525,6 +7526,7 @@
75257526
../../Sources/Shared/Toolkit/Archive/ExplodedArchive.swift
75267527
../../Sources/Shared/Toolkit/Archive/Minizip.swift
75277528
../../Sources/Shared/Toolkit/Archive/ZIPFoundation.swift
7529+
../../Sources/Shared/Toolkit/Atomic.swift
75287530
../../Sources/Shared/Toolkit/Cancellable.swift
75297531
../../Sources/Shared/Toolkit/CancellableResult.swift
75307532
../../Sources/Shared/Toolkit/ControlFlow.swift

Support/Carthage/Readium.xcodeproj/project.pbxproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
825642E013351C922B6510AD /* UTI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B28C65845F0575C40877F6 /* UTI.swift */; };
158158
82BAA3EB081DD29A928958AC /* ContentLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A496C959F870BAFDB447DA /* ContentLayout.swift */; };
159159
837C0BC3151E302508B4BC44 /* LCPAuthenticating.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CB0BFECA8236412881393AA /* LCPAuthenticating.swift */; };
160+
861C71906603180ABD01E8FA /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB57FCAEE605484A7290DBB /* Atomic.swift */; };
160161
862098954DE3522E87E806CC /* Minizip.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFFEBDFE931745C07DACD4A3 /* Minizip.xcframework */; };
161162
874BD412CBA1D392451B952B /* Assets in Resources */ = {isa = PBXBuildFile; fileRef = 251275D0DF87F85158A5FEA9 /* Assets */; };
162163
88A171A36700ACF5A4AD6305 /* PublicationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667B76C4766DFF58D066D40B /* PublicationService.swift */; };
@@ -538,6 +539,7 @@
538539
C5E7CEDF6EA681FE8119791B /* Feed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Feed.swift; sourceTree = "<group>"; };
539540
C7931CB2A5658CAAECD150B0 /* NSRegularExpression.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSRegularExpression.swift; sourceTree = "<group>"; };
540541
CAD79372361D085CA0500CF4 /* Properties+OPDS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Properties+OPDS.swift"; sourceTree = "<group>"; };
542+
CBB57FCAEE605484A7290DBB /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
541543
CC925E451D875E5F74748EDC /* Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Optional.swift; sourceTree = "<group>"; };
542544
CDA8111A330AB4D7187DD743 /* LocatorService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocatorService.swift; sourceTree = "<group>"; };
543545
CE641F78FD99A426A80B3495 /* Zip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Zip.h; sourceTree = "<group>"; };
@@ -1287,6 +1289,7 @@
12871289
C42B511253C3D9C6DA8AA5CC /* Toolkit */ = {
12881290
isa = PBXGroup;
12891291
children = (
1292+
CBB57FCAEE605484A7290DBB /* Atomic.swift */,
12901293
7BBD54FD376456C1925316BC /* Cancellable.swift */,
12911294
0CB0D3EE83AE0CE1F0B0B0CF /* CancellableResult.swift */,
12921295
55BC4119B8937D17ED80B1AB /* ControlFlow.swift */,
@@ -1687,7 +1690,7 @@
16871690
};
16881691
};
16891692
buildConfigurationList = 5A872BCD95ECE5673BC89051 /* Build configuration list for PBXProject "Readium" */;
1690-
compatibilityVersion = "Xcode 10.0";
1693+
compatibilityVersion = "Xcode 11.0";
16911694
developmentRegion = en;
16921695
hasScannedForEncodings = 0;
16931696
knownRegions = (
@@ -1842,6 +1845,7 @@
18421845
09B7475BC8E63C940BD5881A /* Archive.swift in Sources */,
18431846
A3EBB38968F8EB4ABC560678 /* ArchiveFetcher.swift in Sources */,
18441847
AA218336FBD1C23959542515 /* Array.swift in Sources */,
1848+
861C71906603180ABD01E8FA /* Atomic.swift in Sources */,
18451849
5C8ED4151A6C7EF6608A03F8 /* AudioSession.swift in Sources */,
18461850
8E4C9F5A53A6F9B8FC28B7D4 /* BufferedResource.swift in Sources */,
18471851
6D27F5B8C7DBFBF5FB99A4BE /* Bundle.swift in Sources */,

Support/Carthage/Readium.xcodeproj/xcshareddata/xcschemes/R2Navigator.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
33
LastUpgradeVersion = "1250"
4-
version = "1.3">
4+
version = "1.7">
55
<BuildAction
66
parallelizeBuildables = "YES"
77
buildImplicitDependencies = "YES"

Support/Carthage/Readium.xcodeproj/xcshareddata/xcschemes/R2Shared.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
33
LastUpgradeVersion = "1250"
4-
version = "1.3">
4+
version = "1.7">
55
<BuildAction
66
parallelizeBuildables = "YES"
77
buildImplicitDependencies = "YES"

Support/Carthage/Readium.xcodeproj/xcshareddata/xcschemes/R2Streamer.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
33
LastUpgradeVersion = "1250"
4-
version = "1.3">
4+
version = "1.7">
55
<BuildAction
66
parallelizeBuildables = "YES"
77
buildImplicitDependencies = "YES"

Support/Carthage/Readium.xcodeproj/xcshareddata/xcschemes/ReadiumLCP.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
33
LastUpgradeVersion = "1250"
4-
version = "1.3">
4+
version = "1.7">
55
<BuildAction
66
parallelizeBuildables = "YES"
77
buildImplicitDependencies = "YES"

0 commit comments

Comments
 (0)