func getValue()

in Sources/OSS/Internal/ExpiringValue.swift [49:112]


    func getValue(getExpiringValue: @escaping @Sendable () async throws -> (T, Date)) async throws -> T {
        let task: Task<T, Error>
        switch state {
        case .noValue:
            task = try getValueTask(getExpiringValue)
            state = .waitingOnValue(task)

        case let .initialWaitingOnValue(task):
            return try await withTaskCancellationHandler {
                switch await task.result {
                case let .success(result):
                    self.state = .withValue(result.0, result.1)
                    return result.0
                case let .failure(error):
                    self.state = .error(error)
                    throw error
                }
            } onCancel: {
                task.cancel()
            }

        case let .waitingOnValue(waitingOnTask):
            task = waitingOnTask

        case let .withValue(value, expires):
            if expires.timeIntervalSinceNow < 0 {
                // value has expired, create new task to update value and
                // return the result of that task
                task = try getValueTask(getExpiringValue)
                state = .waitingOnValue(task)
            } else if expires.timeIntervalSinceNow < threshold {
                // value is about to expire, create new task to update value and
                // return current value
                let task = try getValueTask(getExpiringValue)
                state = .withValueAndWaiting(value, expires, task)
                return value
            } else {
                return value
            }

        case let .withValueAndWaiting(value, expires, waitingOnTask):
            if expires.timeIntervalSinceNow < 0 {
                // as value has expired wait for task to finish and return result
                task = waitingOnTask
            } else {
                // value hasn't expired so return current value
                return value
            }

        case let .error(error):
            throw error
        }
        return try await withTaskCancellationHandler {
            switch await task.result {
            case let .success(value):
                return value
            case let .failure(error):
                self.state = .error(error)
                throw error
            }
        } onCancel: {
            task.cancel()
        }
    }