Skip to content

Commit

Permalink
Protocol: Guarantee (#62).
Browse files Browse the repository at this point in the history
  • Loading branch information
oscbyspro committed Aug 30, 2024
1 parent 31f123e commit 686fe53
Show file tree
Hide file tree
Showing 12 changed files with 282 additions and 340 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,12 @@ compose better than others. A trusted input delegates precondition checks to the
so that complex types can be built with less overhead. The type system will ask you to accept or
reject such inputs. Your validation strategy will either make your code safer or easier to audit.


```swift
init(_:) // error: traps
init(_:prune:) // error: throws
init(exactly:) // error: nil
init(unchecked:) // error: unchecked
init(_:) // error: precondition
init(unchecked:) // error: assert
init(unsafe:) // error: %%%%%%
```

<a name="nomenclature-unchecked-value"/>
Expand Down
55 changes: 55 additions & 0 deletions Sources/CoreKit/Guarantee+Validation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//=----------------------------------------------------------------------------=
// This source file is part of the Ultimathnum open source project.
//
// Copyright (c) 2023 Oscar Byström Ericsson
// Licensed under Apache License, Version 2.0
//
// See http://www.apache.org/licenses/LICENSE-2.0 for license information.
//=----------------------------------------------------------------------------=

//*============================================================================*
// MARK: * Guarantee x Validation
//*============================================================================*

extension Guarantee {

//=------------------------------------------------------------------------=
// MARK: Initializers
//=------------------------------------------------------------------------=

/// Creates a new instance by trapping on failure.
///
/// - Requires: The given `value` must satisfy the `predicate` of this type.
///
@inlinable public init(_ value: consuming Value) {
precondition(Self.predicate(value), String.brokenInvariant())
self.init(unsafe:/**/value)
}

/// Creates a new instance by trapping on failure in debug mode.
///
/// - Requires: The given `value` must satisfy the `predicate` of this type.
///
@inlinable public init(unchecked value: consuming Value) {
Swift.assert(Self.predicate(value), String.brokenInvariant())
self.init(unsafe:/**/value)
}

/// Creates a new instance by returning `nil` on failure.
///
/// - Requires: The given `value` must satisfy the `predicate` of this type.
///
@inlinable public init?(exactly value: consuming Value) {
guard Self.predicate(value) else { return nil }
self.init(unsafe:/**/value)
}

/// Creates a new instance by throwing the `error()` on failure.
///
/// - Requires: The given `value` must satisfy the `predicate` of this type.
///
@inlinable public init<Error>(_ value: consuming Value, prune error: @autoclosure () -> Error) throws where Error: Swift.Error {
guard Self.predicate(value) else { throw error() }
self.init(unsafe:/**/value)
}
}
51 changes: 51 additions & 0 deletions Sources/CoreKit/Guarantee.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//=----------------------------------------------------------------------------=
// This source file is part of the Ultimathnum open source project.
//
// Copyright (c) 2023 Oscar Byström Ericsson
// Licensed under Apache License, Version 2.0
//
// See http://www.apache.org/licenses/LICENSE-2.0 for license information.
//=----------------------------------------------------------------------------=

//*============================================================================*
// MARK: * Guarantee
//*============================================================================*

/// A trusted input type.
///
/// ### Trusted Input
///
/// This is a trusted input type. Validate inputs with these methods:
///
/// ```swift
/// init(_:prune:) // error: throws
/// init(exactly:) // error: nil
/// init(_:) // error: precondition
/// init(unchecked:) // error: assert
/// init(unsafe:) // error: %%%%%%
/// ```
///
public protocol Guarantee<Value> {

associatedtype Value

//=------------------------------------------------------------------------=
// MARK: Metadata
//=------------------------------------------------------------------------=

/// Indicates whether the given `value` satisfies its `predicate`.
@inlinable static func predicate(_ value: borrowing Value) -> Bool

//=------------------------------------------------------------------------=
// MARK: Initializers
//=------------------------------------------------------------------------=

/// Creates a new instance without validation.
///
/// - Requires: The given `value` must satisfy the `predicate` of this type.
///
@inlinable init(unsafe value: consuming Value)

/// Consumes `self` and returns its `value`.
@inlinable consuming func payload() -> Value
}
56 changes: 10 additions & 46 deletions Sources/CoreKit/Models/Guarantees/Finite.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//=----------------------------------------------------------------------------=

//*============================================================================*
// MARK: * Natural
// MARK: * Finite
//*============================================================================*

/// A finite value.
Expand All @@ -18,24 +18,19 @@
/// This is a trusted input type. Validate inputs with these methods:
///
/// ```swift
/// init(_:) // error: traps
/// init(_:prune:) // error: throws
/// init(exactly:) // error: nil
/// init(unchecked:) // error: unchecked
/// init(_:) // error: precondition
/// init(unchecked:) // error: assert
/// init(unsafe:) // error: %%%%%%
/// ```
///
@frozen public struct Finite<Value>: Equatable where Value: BinaryInteger {

public typealias Value = Value

@frozen public struct Finite<Value>: Equatable, Guarantee where Value: BinaryInteger {

//=------------------------------------------------------------------------=
// MARK: Metadata
//=------------------------------------------------------------------------=

/// Indicates whether the given `value` can be trusted.
///
/// - Returns: `value ∈ ℤ`
///
@inlinable public static func predicate(_ value: /* borrowing */ Value) -> Bool {
!value.isInfinite // await borrowing fix
}
Expand All @@ -50,49 +45,18 @@
// MARK: Initializers
//=------------------------------------------------------------------------=

/// Creates a new instance without validation in release mode.
///
/// - Requires: `value ∈ ℤ`
///
/// - Warning: Only use this method when you know the `value` is valid.
///
@_disfavoredOverload // collection.map(Self.init)
@inlinable public init(unchecked value: consuming Value) {
Swift.assert(Self.predicate(value), String.brokenInvariant())
self.value = value
}

/// Creates a new instance by trapping on failure.
///
/// - Requires: `value ∈ ℤ`
///
@inlinable public init(_ value: consuming Value) {
precondition(Self.predicate(value), String.brokenInvariant())
@inlinable public init(unsafe value: consuming Value) {
self.value = value
}

/// Creates a new instance by returning `nil` on failure.
///
/// - Requires: `value ∈ ℤ`
///
@inlinable public init?(exactly value: consuming Value) {
guard Self.predicate(value) else { return nil }
self.value = value
}

/// Creates a new instance by throwing the `error()` on failure.
///
/// - Requires: `value ∈ ℤ`
///
@inlinable public init<Error>(_ value: consuming Value, prune error: @autoclosure () -> Error) throws where Error: Swift.Error {
guard Self.predicate(value) else { throw error() }
self.value = value
@inlinable public consuming func payload() -> Value {
self.value
}

//=------------------------------------------------------------------------=
// MARK: Transformations
//=------------------------------------------------------------------------=

/// The `magnitude` of `self`.
@inlinable public consuming func magnitude() -> Finite<Value.Magnitude> {
Finite<Value.Magnitude>(unchecked: self.value.magnitude())
Expand Down
52 changes: 8 additions & 44 deletions Sources/CoreKit/Models/Guarantees/Natural.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
/// This is a trusted input type. Validate inputs with these methods:
///
/// ```swift
/// init(_:) // error: traps
/// init(_:prune:) // error: throws
/// init(exactly:) // error: nil
/// init(unchecked:) // error: unchecked
/// init(_:) // error: precondition
/// init(unchecked:) // error: assert
/// init(unsafe:) // error: %%%%%%
/// ```
///
/// ### How to bit cast a `Natural<Value>`
Expand All @@ -31,18 +32,12 @@
/// however, that the inverse case is not as simple. `U8(255)` is natural,
/// for example, but it becomes negative when you reinterpret it as `I8(-1)`.
///
@frozen public struct Natural<Value>: Equatable where Value: BinaryInteger {

public typealias Value = Value

@frozen public struct Natural<Value>: Equatable, Guarantee where Value: BinaryInteger {

//=------------------------------------------------------------------------=
// MARK: Metadata
//=------------------------------------------------------------------------=

/// Indicates whether the given `value` can be trusted.
///
/// - Returns: `value ∈ ℕ`
///
@inlinable public static func predicate(_ value: /* borrowing */ Value) -> Bool {
!Bool(value.appendix) // await borrowing fix
}
Expand All @@ -57,43 +52,12 @@
// MARK: Initializers
//=------------------------------------------------------------------------=

/// Creates a new instance without validation in release mode.
///
/// - Requires: `value ∈ ℕ`
///
/// - Warning: Only use this method when you know the `value` is valid.
///
@_disfavoredOverload // collection.map(Self.init)
@inlinable public init(unchecked value: consuming Value) {
Swift.assert(Self.predicate(value), String.brokenInvariant())
self.value = value
}

/// Creates a new instance by trapping on failure.
///
/// - Requires: `value ∈ ℕ`
///
@inlinable public init(_ value: consuming Value) {
precondition(Self.predicate(value), String.brokenInvariant())
self.value = value
}

/// Creates a new instance by returning `nil` on failure.
///
/// - Requires: `value ∈ ℕ`
///
@inlinable public init?(exactly value: consuming Value) {
guard Self.predicate(value) else { return nil }
@inlinable public init(unsafe value: consuming Value) {
self.value = value
}

/// Creates a new instance by throwing the `error()` on failure.
///
/// - Requires: `value ∈ ℕ`
///
@inlinable public init<Error>(_ value: consuming Value, prune error: @autoclosure () -> Error) throws where Error: Swift.Error {
guard Self.predicate(value) else { throw error() }
self.value = value
@inlinable public consuming func payload() -> Value {
self.value
}

//=------------------------------------------------------------------------=
Expand Down
52 changes: 8 additions & 44 deletions Sources/CoreKit/Models/Guarantees/Nonzero.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,21 @@
/// This is a trusted input type. Validate inputs with these methods:
///
/// ```swift
/// init(_:) // error: traps
/// init(_:prune:) // error: throws
/// init(exactly:) // error: nil
/// init(unchecked:) // error: unchecked
/// init(_:) // error: precondition
/// init(unchecked:) // error: assert
/// init(unsafe:) // error: %%%%%%
/// ```
///
@frozen public struct Nonzero<Value>: BitCastable, Equatable where Value: BinaryInteger {

public typealias Value = Value

@frozen public struct Nonzero<Value>: BitCastable, Equatable, Guarantee where Value: BinaryInteger {

public typealias BitPattern = Nonzero<Value.Magnitude>

//=------------------------------------------------------------------------=
// MARK: Metadata
//=------------------------------------------------------------------------=

/// Indicates whether the given `value` can be trusted.
///
/// - Returns: `value ≠ 0`
///
@inlinable public static func predicate(_ value: /* borrowing */ Value) -> Bool {
!value.isZero // await borrowing fix
}
Expand All @@ -52,43 +47,12 @@
// MARK: Initializers
//=------------------------------------------------------------------------=

/// Creates a new instance without validation in release mode.
///
/// - Requires: `value ≠ 0`
///
/// - Warning: Only use this method when you know the `value` is valid.
///
@_disfavoredOverload // collection.map(Self.init)
@inlinable public init(unchecked value: consuming Value) {
Swift.assert(Self.predicate(value), String.brokenInvariant())
self.value = value
}

/// Creates a new instance by trapping on failure.
///
/// - Requires: `value ≠ 0`
///
@inlinable public init(_ value: consuming Value) {
precondition(Self.predicate(value), String.brokenInvariant())
self.value = value
}

/// Creates a new instance by returning `nil` on failure.
///
/// - Requires: `value ≠ 0`
///
@inlinable public init?(exactly value: consuming Value) {
guard Self.predicate(value) else { return nil }
@inlinable public init(unsafe value: consuming Value) {
self.value = value
}

/// Creates a new instance by throwing the `error()` on failure.
///
/// - Requires: `value ≠ 0`
///
@inlinable public init<Error>(_ value: consuming Value, prune error: @autoclosure () -> Error) throws where Error: Swift.Error {
guard Self.predicate(value) else { throw error() }
self.value = value
@inlinable public consuming func payload() -> Value {
self.value
}

//=------------------------------------------------------------------------=
Expand Down
Loading

0 comments on commit 686fe53

Please sign in to comment.