Skip to content

Commit 011f233

Browse files
committed
refactor(GlanceService): add point-free composition and loading guard
- Add tuple-based GlanceData.init for point-free map(GlanceData.init) - Extract withLoadingGuard helper for reusable concurrent protection - Simplify loadData to 4-line Haskell-inspired pipeline
1 parent f389204 commit 011f233

1 file changed

Lines changed: 15 additions & 6 deletions

File tree

Packages/ClaudeUsage/Sources/Glance/Data/GlanceService.swift

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public struct GlanceData: Sendable {
1818
self.todayCost = todayCost
1919
self.activeSession = activeSession
2020
}
21+
22+
/// Tuple-based init for point-free composition
23+
init(_ tuple: (TodayCost, UsageSession?)) {
24+
self.init(todayCost: tuple.0, activeSession: tuple.1)
25+
}
2126
}
2227

2328
// MARK: - GlanceService
@@ -53,18 +58,22 @@ public actor GlanceService {
5358

5459
/// Loads glance data. Returns nil if a load is already in progress.
5560
public func loadData(invalidateCache: Bool = true) async -> Result<GlanceData, Error>? {
61+
await withLoadingGuard {
62+
if invalidateCache { await clearCache() }
63+
return await executeFetch().map(GlanceData.init)
64+
}
65+
}
66+
67+
// MARK: - Private
68+
69+
private func withLoadingGuard<T>(_ operation: () async -> T) async -> T? {
5670
guard !isLoading else {
5771
logger.debug("loadData: skipped - already loading")
5872
return nil
5973
}
6074
isLoading = true
6175
defer { isLoading = false }
62-
63-
if invalidateCache { await clearCache() }
64-
65-
// Pipeline: fetch → compose
66-
return await executeFetch()
67-
.map { cost, session in GlanceData(todayCost: cost, activeSession: session) }
76+
return await operation()
6877
}
6978

7079
private func executeFetch() async -> Result<(TodayCost, UsageSession?), Error> {

0 commit comments

Comments
 (0)