             $0 + ($1.meta.totalFileAllocatedSize ?? 0)
         }
     }
+
+    // MARK: - Staging
+
+    /// DataCache allows for parallel reads and writes. This is made possible by
+    /// DataCacheStaging.
+    ///
+    /// For example, when the data is added in cache, it is first added to staging
+    /// and is removed from staging only after data is written to disk. Removal works
+    /// the same way.
+    private final class Staging {
+        private var changes = [String: Change]()
+        private var changeRemoveAll: ChangeRemoveAll?
+
+        struct ChangeRemoveAll {
+            let id: Int
+        }
+
+        struct Change {
+            let key: String
+            let id: Int
+            let type: ChangeType
+        }
+
+        enum ChangeType {
+            case add(Data)
+            case remove
+        }
+
+        private var nextChangeId = 0
+
+        // MARK: Changes
+
+        func change(for key: String) -> ChangeType? {
+            if let change = changes[key] {
+                return change.type
+            }
+            if changeRemoveAll != nil {
+                return .remove
+            }
+            return nil
+        }
+
+        // MARK: Register Changes
+
+        func add(data: Data, for key: String) -> Change {
+            return _makeChange(.add(data), for: key)
+        }
+
+        func removeData(for key: String) -> Change {
+            return _makeChange(.remove, for: key)
+        }
+
+        private func _makeChange(_ type: ChangeType, for key: String) -> Change {
+            nextChangeId += 1
+            let change = Change(key: key, id: nextChangeId, type: type)
+            changes[key] = change
+            return change
+        }
+
+        func removeAll() -> ChangeRemoveAll {
+            nextChangeId += 1
+            let change = ChangeRemoveAll(id: nextChangeId)
+            changeRemoveAll = change
+            changes.removeAll()
+            return change
+        }
+
+        // MARK: Flush Changes
+
+        func flushed(_ change: Change) {
+            if let index = changes.index(forKey: change.key),
+                changes[index].value.id == change.id {
+                changes.remove(at: index)
+            }
+        }
+
+        func flushed(_ change: ChangeRemoveAll) {
+            if changeRemoveAll?.id == change.id {
+                changeRemoveAll = nil
+            }
+        }
+    }
 }
-
-// MARK: - DataCacheStaging
-
-/// DataCache allows for parallel reads and writes. This is made possible by
-/// DataCacheStaging.
-///
-/// For example, when the data is added in cache, it is first added to staging
-/// and is removed from staging only after data is written to disk. Removal works
-/// the same way.
-private final class DataCacheStaging {
-    private var changes = [String: Change]()
-    private var changeRemoveAll: ChangeRemoveAll?
-
-    struct ChangeRemoveAll {
-        let id: Int
-    }
-
-    struct Change {
-        let key: String
-        let id: Int
-        let type: ChangeType
-    }
-
-    enum ChangeType {
-        case add(Data)
-        case remove
-    }
-
-    private var nextChangeId = 0
-
-    // MARK: Changes
-
-    func change(for key: String) -> ChangeType? {
-        if let change = changes[key] {
-            return change.type
-        }
-        if changeRemoveAll != nil {
-            return .remove
-        }
-        return nil
-    }
-
-    // MARK: Register Changes
-
-    func add(data: Data, for key: String) -> Change {
-        return _makeChange(.add(data), for: key)
-    }
-
-    func removeData(for key: String) -> Change {
-        return _makeChange(.remove, for: key)
-    }
-
-    private func _makeChange(_ type: ChangeType, for key: String) -> Change {
-        nextChangeId += 1
-        let change = Change(key: key, id: nextChangeId, type: type)
-        changes[key] = change
-        return change
-    }
-
-    func removeAll() -> ChangeRemoveAll {
-        nextChangeId += 1
-        let change = ChangeRemoveAll(id: nextChangeId)
-        changeRemoveAll = change
-        changes.removeAll()
-        return change
-    }
-
-    // MARK: Flush Changes
-
-    func flushed(_ change: Change) {
-        if let index = changes.index(forKey: change.key),
-            changes[index].value.id == change.id {
-            changes.remove(at: index)
-        }
-    }
-
-    func flushed(_ change: ChangeRemoveAll) {
-        if changeRemoveAll?.id == change.id {
-            changeRemoveAll = nil
-        }
-    }
-}

    ///
    /// - warning: Multiple instances with the same path are *not* allowed as they
    /// would conflict with each other.
    internal convenience init(name: String) throws {
        guard let root = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
            throw NSError(domain: NSCocoaErrorDomain, code: NSFileNoSuchFileError, userInfo: nil)
        }


    /// Stores data for the given key. The method returns instantly and the data
    /// is written asyncrhonously.
    public func storeData(_ data: Data, for key: Key) {
        self[key] = data
    }

    /// Removes data for the given key. The method returns instantly, the data
    /// is removed asyncrhonously.
    public func removeData(for key: Key) {
        self[key] = nil
    }

