swift-sdk/Sources/MCP/Base/UnitInterval.swift
Mattt fac4df6b1a
Add support for sampling (#119)
* Add UnitInterval type

* Add test coverage for UnitInterval

* Add support for sampling

* Add integration tests for sampling
2025-05-26 04:57:24 -07:00

126 lines
4.1 KiB
Swift

/// A value constrained to the range 0.0 to 1.0, inclusive.
///
/// `UnitInterval` represents a normalized value that is guaranteed to be within
/// the unit interval [0, 1]. This type is commonly used for representing
/// priorities in sampling request model preferences.
///
/// The type provides safe initialization that returns `nil` for values outside
/// the valid range, ensuring that all instances contain valid unit interval values.
///
/// - Example:
/// ```swift
/// let zero: UnitInterval = 0 // 0.0
/// let half = UnitInterval(0.5)! // 0.5
/// let one: UnitInterval = 1.0 // 1.0
/// let invalid = UnitInterval(1.5) // nil
/// ```
public struct UnitInterval: Hashable, Sendable {
private let value: Double
/// Creates a unit interval value from a `Double`.
///
/// - Parameter value: A double value that must be in the range 0.0...1.0
/// - Returns: A `UnitInterval` instance if the value is valid, `nil` otherwise
///
/// - Example:
/// ```swift
/// let valid = UnitInterval(0.75) // Optional(0.75)
/// let invalid = UnitInterval(-0.1) // nil
/// let boundary = UnitInterval(1.0) // Optional(1.0)
/// ```
public init?(_ value: Double) {
guard (0...1).contains(value) else { return nil }
self.value = value
}
/// The underlying double value.
///
/// This property provides access to the raw double value that is guaranteed
/// to be within the range [0, 1].
///
/// - Returns: The double value between 0.0 and 1.0, inclusive
public var doubleValue: Double { value }
}
// MARK: - Comparable
extension UnitInterval: Comparable {
public static func < (lhs: UnitInterval, rhs: UnitInterval) -> Bool {
lhs.value < rhs.value
}
}
// MARK: - CustomStringConvertible
extension UnitInterval: CustomStringConvertible {
public var description: String { "\(value)" }
}
// MARK: - Codable
extension UnitInterval: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let doubleValue = try container.decode(Double.self)
guard let interval = UnitInterval(doubleValue) else {
throw DecodingError.dataCorrupted(
DecodingError.Context(
codingPath: decoder.codingPath,
debugDescription: "Value \(doubleValue) is not in range 0...1")
)
}
self = interval
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(value)
}
}
// MARK: - ExpressibleByFloatLiteral
extension UnitInterval: ExpressibleByFloatLiteral {
/// Creates a unit interval from a floating-point literal.
///
/// This initializer allows you to create `UnitInterval` instances using
/// floating-point literals. The literal value must be in the range [0, 1]
/// or a runtime error will occur.
///
/// - Parameter value: A floating-point literal between 0.0 and 1.0
///
/// - Warning: This initializer will crash if the literal is outside the valid range.
/// Use the failable initializer `init(_:)` for runtime validation.
///
/// - Example:
/// ```swift
/// let quarter: UnitInterval = 0.25
/// let half: UnitInterval = 0.5
/// ```
public init(floatLiteral value: Double) {
self.init(value)!
}
}
// MARK: - ExpressibleByIntegerLiteral
extension UnitInterval: ExpressibleByIntegerLiteral {
/// Creates a unit interval from an integer literal.
///
/// This initializer allows you to create `UnitInterval` instances using
/// integer literals. Only the values 0 and 1 are valid.
///
/// - Parameter value: An integer literal, either 0 or 1
///
/// - Warning: This initializer will crash if the literal is outside the valid range.
/// Use the failable initializer `init(_:)` for runtime validation.
///
/// - Example:
/// ```swift
/// let zero: UnitInterval = 0
/// let one: UnitInterval = 1
/// ```
public init(integerLiteral value: Int) {
self.init(Double(value))!
}
}