/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/// This implements the developer facing API for recording timespan metrics.
///
/// Instances of this class type are automatically generated by the parsers at build time,
/// allowing developers to record values that were previously registered in the metrics.yaml file.
///
/// The timespan API only exposes the `TimespanMetricType.start()`, `TimespanMetricType.stop()`
/// and `TimespanMetricType.cancel()`  methods.
public typealias TimespanMetricType = TimespanMetric

extension TimespanMetricType {
    /// Convenience method to simplify measuring a function or block of code
    ///
    /// - parameters:
    ///     * funcToMeasure: Accepts a function or closure to measure that can return a value
    public func measure<U>(funcToMeasure: () -> U) -> U {
        start()
        // Putting `stop` in a `defer` block guarantees it will execute at the end
        // of the scope, after the return value is pushed onto the stack.
        // Reference: https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html
        // under the "Specifying Cleanup Actions" section.
        defer {
            stop()
        }
        return funcToMeasure()
    }

    /// Convenience method to simplify measuring a function or block of code
    ///
    /// If the measured function throws, the measurement is canceled and the exception rethrown.
    ///
    /// - parameters:
    ///     * funcToMeasure: Accepts a function or closure to measure that can return a value
    public func measure<U>(funcToMeasure: () throws -> U) throws -> U {
        start()

        do {
            let returnValue = try funcToMeasure()
            stop()
            return returnValue
        } catch {
            cancel()
            throw error
        }
    }
}
