Converted Failable type to Validated property wrapper

This commit is contained in:
Caleb Kleveter 2019-06-06 17:31:22 -05:00
parent a3d86b2ba7
commit 5a785409cb
No known key found for this signature in database
GPG Key ID: B38DBD5CF2C98D69
22 changed files with 496 additions and 708 deletions

View File

@ -1,6 +1,7 @@
extension Failable where T == Bool {
extension Validated where T == Bool {
/// See [`Bool.toggle()`](https://developer.apple.com/documentation/swift/bool/2994863-toggle).
public mutating func toggle() {
self.value?.toggle()
guard case let .value(value) = self else { return }
self = .init(initialValue: !value)
}
}

View File

@ -1,25 +1,30 @@
extension Failable: Equatable where T: Equatable {
extension Validated: Equatable where T: Equatable {
/// See [`Equatable.==(_:_:)`](https://developer.apple.com/documentation/swift/equatable/1539854).
public static func == (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Bool {
switch (lhs.stored, rhs.stored) {
case let (.success(left), .success(right)): return left == right
case let (.failure(left), .failure(right)): return left.localizedDescription == right.localizedDescription
public static func == (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Bool {
switch (lhs, rhs) {
case let (.value(left), .value(right)): return left == right
case let (.error(left), .error(right)): return left.localizedDescription == right.localizedDescription
default: return false
}
}
}
extension Failable: Comparable where T: Comparable {
extension Validated: Comparable where T: Comparable {
/// See [`Comparable.<(_:_:)`](https://developer.apple.com/documentation/swift/comparable/1538311).
public static func < (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Bool {
return Failable<Bool, EmptyValidation<Bool>>(Failable.map(lhs, rhs) { left, right in left < right }).value ?? false
public static func < (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Bool {
switch (lhs, rhs) {
case let (.value(left), .value(right)): return left < right
default: return false
}
}
}
extension Failable: Hashable where T: Hashable {
extension Validated: Hashable where T: Hashable {
/// See [`Hashable.hash(into:)`](https://developer.apple.com/documentation/swift/hashable/2995575-hash).
public func hash(into hasher: inout Hasher) {
hasher.combine(String(describing: Validations.self))
hasher.combine(self.value)
switch self {
case let .value(value): hasher.combine(value)
case let .error(error): hasher.combine(error.localizedDescription)
}
}
}

View File

@ -1 +1 @@
extension Failable: Error where T: Error {}
extension Validated: Error where T: Error {}

View File

@ -1,64 +1,64 @@
extension Failable: ExpressibleByIntegerLiteral where T: ExpressibleByIntegerLiteral {
extension Validated: ExpressibleByIntegerLiteral where T: ExpressibleByIntegerLiteral {
/// See [`ExpressibleByIntegerLiteral.init(integerLiteral:)`](https://developer.apple.com/documentation/swift/expressiblebyintegerliteral/2298913-init).
public init(integerLiteral value: T.IntegerLiteralType) {
self = Failable(T(integerLiteral: value))
self = Validated(initialValue: T(integerLiteral: value))
}
}
extension Failable: ExpressibleByFloatLiteral where T: ExpressibleByFloatLiteral {
extension Validated: ExpressibleByFloatLiteral where T: ExpressibleByFloatLiteral {
/// See [`ExpressibleByFloatLiteral.init(floatLiteral:)`](https://developer.apple.com/documentation/swift/expressiblebyfloatliteral/2294405-init).
public init(floatLiteral value: T.FloatLiteralType) {
self = Failable(T(floatLiteral: value))
self = Validated(initialValue: T(floatLiteral: value))
}
}
extension Failable: ExpressibleByBooleanLiteral where T: ExpressibleByBooleanLiteral {
extension Validated: ExpressibleByBooleanLiteral where T: ExpressibleByBooleanLiteral {
/// See [`ExpressibleByBooleanLiteral.init(booleanLiteral:)`](https://developer.apple.com/documentation/swift/expressiblebybooleanliteral/2296011-init).
public init(booleanLiteral value: T.BooleanLiteralType) {
self = Failable(T(booleanLiteral: value))
self = Validated(initialValue: T(booleanLiteral: value))
}
}
extension Failable: ExpressibleByNilLiteral where T: ExpressibleByNilLiteral {
extension Validated: ExpressibleByNilLiteral where T: ExpressibleByNilLiteral {
/// See [`ExpressibleByNilLiteral.init(nilLiteral:)`](https://developer.apple.com/documentation/swift/expressiblebynilliteral).
public init(nilLiteral: ()) {
self = Failable(T(nilLiteral: ()))
self = Validated(initialValue: T(nilLiteral: ()))
}
}
extension Failable: ExpressibleByStringLiteral where T: ExpressibleByStringLiteral {
extension Validated: ExpressibleByStringLiteral where T: ExpressibleByStringLiteral {
/// See [`ExpressibleByStringLiteral.init(stringLiteral:)`](https://developer.apple.com/documentation/swift/expressiblebystringliteral/2294174-init)
public init(stringLiteral value: T.StringLiteralType) {
self = Failable(T(stringLiteral: value))
self = Validated(initialValue: T(stringLiteral: value))
}
}
extension Failable: ExpressibleByExtendedGraphemeClusterLiteral where T: ExpressibleByExtendedGraphemeClusterLiteral {
extension Validated: ExpressibleByExtendedGraphemeClusterLiteral where T: ExpressibleByExtendedGraphemeClusterLiteral {
/// See [`ExpressibleByExtendedGraphemeClusterLiteral.init(extendedGraphemeClusterLiteral:)`](https://developer.apple.com/documentation/swift/expressiblebyextendedgraphemeclusterliteral/2294280-init).
public init(extendedGraphemeClusterLiteral value: T.ExtendedGraphemeClusterLiteralType) {
self = Failable(T(extendedGraphemeClusterLiteral: value))
self = Validated(initialValue: T(extendedGraphemeClusterLiteral: value))
}
}
extension Failable: ExpressibleByUnicodeScalarLiteral where T: ExpressibleByUnicodeScalarLiteral {
extension Validated: ExpressibleByUnicodeScalarLiteral where T: ExpressibleByUnicodeScalarLiteral {
/// See [`ExpressibleByUnicodeScalarLiteral.init(unicodeScalarLiteral:)`](https://developer.apple.com/documentation/swift/expressiblebyunicodescalarliteral/2296043-init).
public init(unicodeScalarLiteral value: T.UnicodeScalarLiteralType) {
self = Failable(T(unicodeScalarLiteral: value))
self = Validated(initialValue: T(unicodeScalarLiteral: value))
}
}
extension Failable: ExpressibleByArrayLiteral where T: ExpressibleByArrayLiteral {
extension Validated: ExpressibleByArrayLiteral where T: ExpressibleByArrayLiteral {
/// See [`ExpressibleByArrayLiteral.init(arrayLiteral:)`](https://developer.apple.com/documentation/swift/expressiblebyarrayliteral/2908652-init).
public init(arrayLiteral elements: T.ArrayLiteralElement...) {
let initializer = unsafeBitCast(T.init(arrayLiteral:), to: (([T.ArrayLiteralElement]) -> T).self)
self = Failable(initializer(elements))
self = Validated(initialValue: initializer(elements))
}
}
extension Failable: ExpressibleByDictionaryLiteral where T: ExpressibleByDictionaryLiteral {
extension Validated: ExpressibleByDictionaryLiteral where T: ExpressibleByDictionaryLiteral {
/// See [`ExpressibleByDictionaryLiteral.init(dictionaryLiteral:)`](https://developer.apple.com/documentation/swift/expressiblebydictionaryliteral/2295781-init).
public init(dictionaryLiteral elements: (T.Key, T.Value)...) {
let initializer = unsafeBitCast(T.init(dictionaryLiteral:), to: (([(T.Key, T.Value)]) -> T).self)
self = Failable(initializer(elements))
self = Validated(initialValue: initializer(elements))
}
}

View File

@ -1,25 +1,25 @@
extension Failable: RawRepresentable where T: RawRepresentable {
extension Validated: RawRepresentable where T: RawRepresentable {
/// See [`RawRepresentable.RawValue`](https://developer.apple.com/documentation/swift/rawrepresentable/1540809-rawvalue).
public typealias RawValue = Result<T.RawValue, Error>
/// See [`RawRepresentable.init(rawValue:)`](https://developer.apple.com/documentation/swift/rawrepresentable/1538354-inithttps://developer.apple.com/documentation/swift/rawrepresentable/1538354-init)
public init?(rawValue: RawValue) {
guard case let .success(raw) = rawValue, let value = T(rawValue: raw) else { return nil }
self = Failable(value)
self = Validated(initialValue: value)
}
/// See [`RawRepresentable.rawValue`](https://developer.apple.com/documentation/swift/rawrepresentable/1540698-rawvalue).
public var rawValue: Result<T.RawValue, Error> {
return self[keyPath: \.rawValue]
return Result(catching: { try self.get().rawValue })
}
}
extension Failable: CaseIterable where T: CaseIterable {
extension Validated: CaseIterable where T: CaseIterable {
/// See [`CaseIterable.AllCases`](https://developer.apple.com/documentation/swift/caseiterable/2994868-allcases).
public typealias AllCases = Array<Failable<T, Validations>>
public typealias AllCases = Array<Validated<T, Validations>>
/// See [`CaseIterable.allCases`](https://developer.apple.com/documentation/swift/caseiterable/2994869-allcases)
public static var allCases: AllCases {
return T.allCases.map(Failable.init)
return T.allCases.map(Validated.init)
}
}

View File

@ -1,24 +1,24 @@
extension Failable: CustomStringConvertible where T: CustomStringConvertible {
extension Validated: CustomStringConvertible where T: CustomStringConvertible {
/// See [`CustomStringConvertible.description`](https://developer.apple.com/documentation/swift/customstringconvertible/1539130-description).
public var description: String {
switch self.stored {
case let .success(value): return "Failable(" + value.description + ")"
case let .failure(error): return "Failable(error: " + error.localizedDescription + ")"
switch self {
case let .value(value): return "Validated(" + value.description + ")"
case let .error(error): return "Validated(error: " + error.localizedDescription + ")"
}
}
}
extension Failable: LosslessStringConvertible where T: LosslessStringConvertible {
extension Validated: LosslessStringConvertible where T: LosslessStringConvertible {
/// See [`LosslessStringConvertible.init(_:)`](https://developer.apple.com/documentation/swift/losslessstringconvertible/2429639-init).
public init?(_ description: String) {
guard let value = T(description) else { return nil }
self.init(value)
self.init(initialValue: value)
}
}
extension Failable: CustomDebugStringConvertible where T: CustomDebugStringConvertible {
extension Validated: CustomDebugStringConvertible where T: CustomDebugStringConvertible {
/// See [`CustomDebugStringConvertible.debugDescription`](https://developer.apple.com/documentation/swift/customdebugstringconvertible/1540125-debugdescription).
public var debugDescription: String {
return "Failable(value: " + self.value.debugDescription + ", validations: " + String(describing: Validations.self) + ")"
return "Validated(value: " + self.value.debugDescription + ", validations: " + String(describing: Validations.self) + ")"
}
}

View File

@ -1,177 +0,0 @@
// MARK: - Keyed Container
extension KeyedDecodingContainer {
/// Decodes a `Failable` instance with the given stored type for the given key.
///
/// - Parameters:
/// - type: The type of `Failable` instance to decode.
/// - key: The key that the decoded value is associated with.
///
/// - Returns: A value of the requested type, if present for the given key and convertible to the requested type.
public func decode<T, V>(_ type: Failable<T, V>.Type, forKey key: K) throws -> Failable<T, V> where T: Decodable {
let wrapped = try self.decode(T.self, forKey: key)
return try Failable(wrapped).verified()
}
/// Decodes a `Failable` instance with the given stored type for the given key if it exists.
///
/// - Parameters:
/// - type: The type of `Failable` instance to decode.
/// - key: The key that the decoded value is associated with.
///
/// - Returns: A value of the requested type, if present for the given key and convertible to the requested type.
public func decode<T, V>(_ type: Failable<T?, V>.Type, forKey key: K) throws -> Failable<T?, V> where T: Decodable {
let wrapped = try self.decodeIfPresent(T.self, forKey: key)
return try Failable(wrapped).verified()
}
}
extension KeyedEncodingContainer {
func value<T, V>(from failable: Failable<T, V>, for key: K) throws -> T where T: Encodable {
guard let encodable = failable.value else {
throw EncodingError.invalidValue(failable, .init(
codingPath: self.codingPath + [key],
debugDescription: "Cannot encode error as value of type `\(T.self)`",
underlyingError: failable.error
))
}
return encodable
}
/// Encodes the given `Failable` value for the given key.
///
/// - Parameters:
/// - value: The value to encode.
/// - key: The key to associate the value with.
public mutating func encode<T, V>(_ value: Failable<T, V>, forKey key: K) throws where T: Encodable {
try self.encode(self.value(from: value, for: key), forKey: key)
}
/// Encodes the given `Failable` value for the given key if it exists.
///
/// - Parameters:
/// - value: The value to encode.
/// - key: The key to associate the value with.
public mutating func encode<T, V>(_ value: Failable<T?, V>, forKey key: K) throws where T: Encodable {
try self.encodeIfPresent(self.value(from: value, for: key), forKey: key)
}
}
// MARK: - Unkeyed Container
extension UnkeyedDecodingContainer {
/// Decodes a value of the given type.
///
/// - Parameter type: The type of `Failable` instance to decode.
/// - Returns: A value of the requested type, if present for the given key and convertible to the requested type.
public mutating func decode<T, V>(_ type: Failable<T, V>.Type) throws -> Failable<T, V> where T: Decodable {
let wrapped = try self.decode(T.self)
return try Failable(wrapped).verified()
}
/// Decodes a value of the given type.
///
/// - Parameter type: The type of `Failable` instance to decode.
/// - Returns: A value of the requested type, if present for the given key and convertible to the requested type.
public mutating func decode<T, V>(_ type: Failable<T?, V>.Type) throws -> Failable<T?, V> where T: Decodable {
let wrapped = try self.decodeIfPresent(T.self)
return try Failable(wrapped).verified()
}
}
extension UnkeyedEncodingContainer {
func value<T, V>(from failable: Failable<T, V>) throws -> T where T: Encodable {
guard let encodable = failable.value else {
throw EncodingError.invalidValue(failable, .init(
codingPath: self.codingPath,
debugDescription: "Cannot encode error as value of type `\(T.self)`",
underlyingError: failable.error
))
}
return encodable
}
/// Encodes the given `Failable` value.
///
/// - Parameter value: The value to encode.
public mutating func encode<T, V>(_ value: Failable<T, V>) throws where T: Encodable {
try self.encode(self.value(from: value))
}
/// Encodes the given `Failable` value if it exists.
///
/// If the value stored by the `Failable` instance is `nil`, then `.encodeNil()` is called instead.
///
/// - Parameter value: The value to encode.
public mutating func encode<T, V>(_ value: Failable<T?, V>) throws where T: Encodable {
if let encodable = try self.value(from: value) {
try self.encode(encodable)
} else {
try self.encodeNil()
}
}
}
// MARK: Single Value Container
extension SingleValueDecodingContainer {
/// Decodes a single `Failable` value of the given type.
///
/// - Parameter type: The type of `Failable` instance to decode.
/// - Returns: A value of the requested type.
public func decode<T, V>(_ type: Failable<T, V>.Type) throws -> Failable<T, V> where T: Decodable {
let wrapped = try self.decode(T.self)
return try Failable(wrapped).verified()
}
/// Decodes a single `Failable` value of the given type.
///
/// - Parameter type: The type of `Failable` instance to decode.
/// - Returns: A value of the requested type.
public func decode<T, V>(_ type: Failable<T?, V>.Type) throws -> Failable<T?, V> where T: Decodable {
if self.decodeNil() {
return try Failable(nil).verified()
} else {
let wrapped = try self.decode(T.self)
return try Failable(wrapped).verified()
}
}
}
extension SingleValueEncodingContainer {
func value<T, V>(from failable: Failable<T, V>) throws -> T where T: Encodable {
guard let encodable = failable.value else {
throw EncodingError.invalidValue(failable, .init(
codingPath: self.codingPath,
debugDescription: "Cannot encode error as value of type `\(T.self)`",
underlyingError: failable.error
))
}
return encodable
}
/// Encodes a single `Failable` value.
///
/// - Parameter value: The value to encode.
public mutating func encode<T, V>(_ value: Failable<T, V>) throws where T: Encodable {
try self.encode(self.value(from: value))
}
/// Encodes a single `Failable` value if it exists.
///
/// If the value stored by the `Failable` instance is `nil`, then `.encodeNil()` is called instead.
///
/// - Parameter value: The value to encode.
public mutating func encode<T, V>(_ value: Failable<T?, V>) throws where T: Encodable {
if let encodable = try self.value(from: value) {
try self.encode(encodable)
} else {
try self.encodeNil()
}
}
}

View File

@ -1,29 +1,20 @@
extension Failable: Encodable where T: Encodable {
extension Validated: Encodable where T: Encodable {
/// See [`Encodable.encode(to:)`](https://developer.apple.com/documentation/swift/encodable/2893603-encode)
public func encode(to encoder: Encoder)throws {
var container = encoder.singleValueContainer()
switch self.stored {
case let .success(value):
try container.encode(value)
case let .failure(error):
throw EncodingError.invalidValue(self, .init(
codingPath: encoder.codingPath,
debugDescription: "Cannot encode error as value of type `\(T.self)`",
underlyingError: error
))
}
try container.encode(self.get())
}
}
extension Failable: Decodable where T: Decodable {
extension Validated: Decodable where T: Decodable {
/// See [`Decodable.init(from:)`](https://developer.apple.com/documentation/swift/decodable/2894081-init)
public init(from decoder: Decoder)throws {
let container = try decoder.singleValueContainer()
if _isOptional(T.self), container.decodeNil() {
self = try Failable(Void?.none as! T).verified()
self = try Validated(initialValue: (Optional<Void>.none as! T)).validate()
} else {
self = try Failable(container.decode(T.self)).verified()
self = try Validated(initialValue: container.decode(T.self)).validate()
}
}
}

View File

@ -1,6 +1,6 @@
extension Failable: Sequence where T: Sequence {
extension Validated: Sequence where T: Sequence {
/// See [`Sequence.Element`](https://developer.apple.com/documentation/swift/sequence/2908099-element).
public typealias Element = Failable<T.Element, EmptyValidation<T.Element>>
public typealias Element = AlwaysValidated<T.Element>
/// See [`IteratorProtocol`](https://developer.apple.com/documentation/swift/iteratorprotocol).
///
@ -9,7 +9,7 @@ extension Failable: Sequence where T: Sequence {
public struct Iterator: IteratorProtocol {
/// See [`IteratorProtocol.Element`](https://developer.apple.com/documentation/swift/iteratorprotocol/1641632-element).
public typealias Element = Failable.Element
public typealias Element = Validated.Element
var internalIterator: AnyIterator<T.Element>?
@ -20,7 +20,7 @@ extension Failable: Sequence where T: Sequence {
/// See [`IteratorProtocol.next()`](https://developer.apple.com/documentation/swift/iteratorprotocol/1641682-next).
public mutating func next() -> Element? {
if self.internalIterator != nil {
return (self.internalIterator?.next()).map(Element.init(_:))
return (self.internalIterator?.next()).map(Element.init(initialValue:))
} else {
return nil
}
@ -39,9 +39,9 @@ extension Failable: Sequence where T: Sequence {
}
}
extension Failable: Collection where T: Collection {
extension Validated: Collection where T: Collection {
/// See [`Collection.Index`](https://developer.apple.com/documentation/swift/collection/2943866-index).
public typealias Index = Failable<T.Index, EmptyValidation<T.Index>>
public typealias Index = AlwaysValidated<T.Index>
/// See [`Collection.startIndex`](https://developer.apple.com/documentation/swift/collection/2946080-startindex).
public var startIndex: Index {
@ -49,37 +49,37 @@ extension Failable: Collection where T: Collection {
}
/// See [`Collection.endIndex`](https://developer.apple.com/documentation/swift/collection/2944204-endindex).
public var endIndex: Failable<T.Index, EmptyValidation<T.Index>> {
public var endIndex: Index {
return self[keyPath: \.endIndex]
}
/// See [`Collection.subscript(_:)`](https://developer.apple.com/documentation/swift/collection/1641358-subscript).
public subscript (position: Index) -> Element {
get {
return Failable.map(self, position) { collection, index in collection[index] }
return Validated.map(self, position) { collection, index in collection[index] }
}
}
/// See [`Collection.index(after:)`](https://developer.apple.com/documentation/swift/collection/2943746-index).
public func index(after i: Failable<T.Index, EmptyValidation<T.Index>>) -> Failable<T.Index, EmptyValidation<T.Index>> {
return Failable.map(self, i) { collection, index in collection.index(after: index) }
public func index(after i: Index) -> Index {
return Validated.map(self, i) { collection, index in collection.index(after: index) }
}
}
extension Failable: BidirectionalCollection where T: BidirectionalCollection {
extension Validated: BidirectionalCollection where T: BidirectionalCollection {
/// See [`BidirectionalCollection.index(before:)`](https://developer.apple.com/documentation/swift/bidirectionalcollection/3017603-formindex).
public func index(before i: Failable<T.Index, EmptyValidation<T.Index>>) -> Failable<T.Index, EmptyValidation<T.Index>> {
return Failable.map(self, i) { collection, index in collection.index(before: index) }
public func index(before i: Index) -> Index {
return Validated.map(self, i) { collection, index in collection.index(before: index) }
}
}
extension Failable: RandomAccessCollection where T: RandomAccessCollection { }
extension Validated: RandomAccessCollection where T: RandomAccessCollection { }
extension Failable: MutableCollection where T: MutableCollection {
extension Validated: MutableCollection where T: MutableCollection {
/// See [`MutableCollection.subscript(_:)`](https://developer.apple.com/documentation/swift/mutablecollection/1640969-subscript).
public subscript (position: Index) -> Element {
get {
return Failable.map(self, position) { collection, index in collection[index] }
return Validated.map(self, position) { collection, index in collection[index] }
}
set {
if let value = newValue.value, let index = position.value {
@ -89,9 +89,9 @@ extension Failable: MutableCollection where T: MutableCollection {
}
}
extension Failable: RangeReplaceableCollection where T: RangeReplaceableCollection {
extension Validated: RangeReplaceableCollection where T: RangeReplaceableCollection {
/// See [`RangeReplaceableCollection.init()`](https://developer.apple.com/documentation/swift/rangereplaceablecollection/1641467-init).
public init() {
self = Failable(T())
self = Validated(initialValue: T())
}
}

View File

@ -11,51 +11,51 @@ public struct MagnitudeValidation<Magnitude>: Validation where Magnitude: Numeri
}
}
extension Failable: Strideable where T: Strideable {
extension Validated: Strideable where T: Strideable {
/// See [`Strideable.Stride`](https://developer.apple.com/documentation/swift/strideable/1541220-stride).
public typealias Stride = Failable<T.Stride, EmptyValidation<T.Stride>>
public typealias Stride = AlwaysValidated<T.Stride>
/// See [`Strideable.advanced(by:)`](https://developer.apple.com/documentation/swift/strideable/1641148-advanced).
public func advanced(by n: Stride) -> Failable<T, Validations> {
return Failable.map(self, n) { start, stride in return start.advanced(by: stride) }
public func advanced(by n: Stride) -> Validated<T, Validations> {
return Validated.map(self, n) { start, stride in return start.advanced(by: stride) }
}
/// See [`Strideable.distance(to:)`](https://developer.apple.com/documentation/swift/strideable/1641775-distance).
public func distance(to other: Failable<T, Validations>) -> Stride {
return Failable.map(self, other) { start, end in start.distance(to: end) }
public func distance(to other: Validated<T, Validations>) -> Stride {
return Validated.map(self, other) { start, end in start.distance(to: end) }
}
}
extension Failable: AdditiveArithmetic where T: AdditiveArithmetic {
extension Validated: AdditiveArithmetic where T: AdditiveArithmetic {
/// See [`AdditiveArithmetic.zero`](https://developer.apple.com/documentation/swift/additivearithmetic/3126829-zero).
public static var zero: Failable<T, Validations> {
return Failable(T.zero)
public static var zero: Validated<T, Validations> {
return Validated(initialValue: T.zero)
}
/// See [`AdditiveArithmetic.-(_:_:)`](https://developer.apple.com/documentation/swift/additivearithmetic/3126825).
public static func - (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Failable<T, Validations> {
return Failable.map(lhs, rhs) { left, right in left - right }
public static func - (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Validated<T, Validations> {
return Validated.map(lhs, rhs) { left, right in left - right }
}
/// See [`AdditiveArithmetic.+(_:_:)`](https://developer.apple.com/documentation/swift/additivearithmetic/3126821).
public static func + (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Failable<T, Validations> {
return Failable.map(lhs, rhs) { left, right in left + right }
public static func + (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Validated<T, Validations> {
return Validated.map(lhs, rhs) { left, right in left + right }
}
/// See [`AdditiveArithmetic.-=(_:_:)`](https://developer.apple.com/documentation/swift/additivearithmetic/3126828).
public static func -= (lhs: inout Failable<T, Validations>, rhs: Failable<T, Validations>) {
public static func -= (lhs: inout Validated<T, Validations>, rhs: Validated<T, Validations>) {
lhs = lhs - rhs
}
/// See [`AdditiveArithmetic.+=(_:_:)`](https://developer.apple.com/documentation/swift/additivearithmetic/3126824).
public static func += (lhs: inout Failable<T, Validations>, rhs: Failable<T, Validations>) {
public static func += (lhs: inout Validated<T, Validations>, rhs: Validated<T, Validations>) {
lhs = lhs + rhs
}
}
extension Failable: Numeric where T: Numeric {
extension Validated: Numeric where T: Numeric {
/// See [`Numeric.Magnitude`](https://developer.apple.com/documentation/swift/numeric/2884423-magnitude).
public typealias Magnitude = Failable<T.Magnitude, MagnitudeValidation<T.Magnitude>>
public typealias Magnitude = Validated<T.Magnitude, MagnitudeValidation<T.Magnitude>>
/// See [`Numeric.magnitude`](https://developer.apple.com/documentation/swift/numeric/2884876-magnitude).
public var magnitude: Magnitude {
@ -65,65 +65,65 @@ extension Failable: Numeric where T: Numeric {
/// See [`Numeric.init(exactly:)`](https://developer.apple.com/documentation/swift/numeric/2886795-init).
public init?<N>(exactly source: N) where N : BinaryInteger {
guard let value = T(exactly: source) else { return nil }
self.init(value)
self.init(initialValue: value)
}
/// See [`Numeric.*(_:_:)`](https://developer.apple.com/documentation/swift/numeric/2883821).
public static func * (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Failable<T, Validations> {
return Failable.map(lhs, rhs, closure: { left, right in left * right })
public static func * (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Validated<T, Validations> {
return Validated.map(lhs, rhs, closure: { left, right in left * right })
}
/// See [`Numeric.*=(_:_:)`](https://developer.apple.com/documentation/swift/numeric/2886882).
public static func *= (lhs: inout Failable<T, Validations>, rhs: Failable<T, Validations>) {
public static func *= (lhs: inout Validated<T, Validations>, rhs: Validated<T, Validations>) {
lhs = lhs * rhs
}
}
extension Failable: SignedNumeric where T: SignedNumeric {
extension Validated: SignedNumeric where T: SignedNumeric {
/// See [`SignedNumeric.negate()`](https://developer.apple.com/documentation/swift/signednumeric/2883859-negate).
public mutating func negate() {
self.value?.negate()
}
/// See [`SignedNumeric.-(_:)`](https://developer.apple.com/documentation/swift/signednumeric/2965579).
public static prefix func - (lhs: Failable<T, Validations>) -> Failable<T, Validations> {
public static prefix func - (lhs: Validated<T, Validations>) -> Validated<T, Validations> {
guard let value = lhs.value else { return lhs }
return Failable<T, Validations>(-value)
return Validated<T, Validations>(initialValue: -value)
}
}
/// See [`AdditiveArithmetic.-(_:_:)`](https://developer.apple.com/documentation/swift/additivearithmetic/3126825).
public func - <T, V1, V2>(lhs: Failable<T, V1>, rhs: Failable<T, V2>) -> Failable<T, AppendedValidations<V1, V2>>
public func - <T, V1, V2>(lhs: Validated<T, V1>, rhs: Validated<T, V2>) -> Validated<T, AppendedValidations<V1, V2>>
where T: AdditiveArithmetic
{
return Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left - right }
return Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left - right }
}
/// See [`AdditiveArithmetic.+(_:_:)`](https://developer.apple.com/documentation/swift/additivearithmetic/3126821).
public func + <T, V1, V2>(lhs: Failable<T, V1>, rhs: Failable<T, V2>) -> Failable<T, AppendedValidations<V1, V2>>
public func + <T, V1, V2>(lhs: Validated<T, V1>, rhs: Validated<T, V2>) -> Validated<T, AppendedValidations<V1, V2>>
where T: AdditiveArithmetic
{
return Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left + right }
return Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left + right }
}
/// See [`Numeric.*(_:_:)`](https://developer.apple.com/documentation/swift/numeric/2883821).
public func * <T, V1, V2>(lhs: Failable<T, V1>, rhs: Failable<T, V2>) -> Failable<T, AppendedValidations<V1, V2>>
public func * <T, V1, V2>(lhs: Validated<T, V1>, rhs: Validated<T, V2>) -> Validated<T, AppendedValidations<V1, V2>>
where T: Numeric
{
return Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left * right }
return Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left * right }
}
/// See [`AdditiveArithmetic.-=(_:_:)`](https://developer.apple.com/documentation/swift/additivearithmetic/3126828).
public func -= <T, V1, V2>(lhs: inout Failable<T, V1>, rhs: Failable<T, V2>) where T: AdditiveArithmetic {
lhs = Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left - right }
public func -= <T, V1, V2>(lhs: inout Validated<T, V1>, rhs: Validated<T, V2>) where T: AdditiveArithmetic {
lhs = Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left - right }
}
/// See [`AdditiveArithmetic.+=(_:_:)`](https://developer.apple.com/documentation/swift/additivearithmetic/3126824).
public func += <T, V1, V2>(lhs: inout Failable<T, V1>, rhs: Failable<T, V2>) where T: AdditiveArithmetic {
lhs = Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left + right }
public func += <T, V1, V2>(lhs: inout Validated<T, V1>, rhs: Validated<T, V2>) where T: AdditiveArithmetic {
lhs = Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left + right }
}
/// See [`Numeric.*=(_:_:)`](https://developer.apple.com/documentation/swift/numeric/2886882).
public func *= <T, V1, V2>(lhs: inout Failable<T, V1>, rhs: Failable<T, V2>) where T: Numeric {
lhs = Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left * right }
public func *= <T, V1, V2>(lhs: inout Validated<T, V1>, rhs: Validated<T, V2>) where T: Numeric {
lhs = Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left * right }
}

View File

@ -1,41 +1,41 @@
// TODO: Try to remove `Validations == MagnitudeValidation<T>` constraint.
extension Failable: FloatingPoint where T: FloatingPoint, Validations == MagnitudeValidation<T> {
extension Validated: FloatingPoint where T: FloatingPoint, Validations == MagnitudeValidation<T> {
/// See [`FloatingPoint.Exponent`](https://developer.apple.com/documentation/swift/floatingpoint/1848224-exponent).
public typealias Exponent = Failable<T.Exponent, EmptyValidation<T.Exponent>>
public typealias Exponent = AlwaysValidated<T.Exponent>
/// See [`FloatingPoint.nan`](https://developer.apple.com/documentation/swift/floatingpoint/1641652-nan).
public static var nan: Failable<T, Validations> {
return Failable(T.nan)
public static var nan: Validated<T, Validations> {
return Validated(initialValue: T.nan)
}
/// See [`FloatingPoint.signalingNaN`](https://developer.apple.com/documentation/swift/floatingpoint/1845864-signalingnan).
public static var signalingNaN: Failable<T, Validations> {
return Failable(T.signalingNaN)
public static var signalingNaN: Validated<T, Validations> {
return Validated(initialValue: T.signalingNaN)
}
/// See [`FloatingPoint.infinity`](https://developer.apple.com/documentation/swift/floatingpoint/1641304-infinity).
public static var infinity: Failable<T, Validations> {
return Failable(T.infinity)
public static var infinity: Validated<T, Validations> {
return Validated(initialValue: T.infinity)
}
/// See [`FloatingPoint.greatestFiniteMagnitude`](https://developer.apple.com/documentation/swift/floatingpoint/1849534-greatestfinitemagnitude).
public static var greatestFiniteMagnitude: Failable<T, Validations> {
return Failable(T.greatestFiniteMagnitude)
public static var greatestFiniteMagnitude: Validated<T, Validations> {
return Validated(initialValue: T.greatestFiniteMagnitude)
}
/// See [`FloatingPoint.pi`](https://developer.apple.com/documentation/swift/floatingpoint/1845454-pi).
public static var pi: Failable<T, Validations> {
return Failable(T.pi)
public static var pi: Validated<T, Validations> {
return Validated(initialValue: T.pi)
}
/// See [`FloatingPoint.leastNormalMagnitude`](https://developer.apple.com/documentation/swift/floatingpoint/1849504-leastnormalmagnitude).
public static var leastNormalMagnitude: Failable<T, Validations> {
return Failable(T.leastNormalMagnitude)
public static var leastNormalMagnitude: Validated<T, Validations> {
return Validated(initialValue: T.leastNormalMagnitude)
}
/// See [`FloatingPoint.leastNonzeroMagnitude`](https://developer.apple.com/documentation/swift/floatingpoint/1848591-leastnonzeromagnitude).
public static var leastNonzeroMagnitude: Failable<T, Validations> {
return Failable(T.leastNonzeroMagnitude)
public static var leastNonzeroMagnitude: Validated<T, Validations> {
return Validated(initialValue: T.leastNonzeroMagnitude)
}
@ -45,7 +45,7 @@ extension Failable: FloatingPoint where T: FloatingPoint, Validations == Magnitu
}
/// See [`FloatingPoint.ulp`](https://developer.apple.com/documentation/swift/floatingpoint/1847492-ulp).
public var ulp: Failable<T, Validations> {
public var ulp: Validated<T, Validations> {
return self[keyPath: \.ulp]
}
@ -55,18 +55,18 @@ extension Failable: FloatingPoint where T: FloatingPoint, Validations == Magnitu
}
/// See [`FloatingPoint.exponent`](https://developer.apple.com/documentation/swift/floatingpoint/1846275-exponent).
public var exponent: Failable<T.Exponent, EmptyValidation<T.Exponent>> {
return self[keyPath: \.exponent]
public var exponent: Exponent {
return self.map { $0.exponent }
}
/// See [`FloatingPoint.significand`](https://developer.apple.com/documentation/swift/floatingpoint/1847298-significand).
public var significand: Failable<T, Validations> {
return self[keyPath: \.significand]
public var significand: Validated<T, Validations> {
return self.map { $0.significand }
}
/// See [`FloatingPoint.nextUp`](https://developer.apple.com/documentation/swift/floatingpoint/1848104-nextup).
public var nextUp: Failable<T, Validations> {
return self[keyPath: \.nextUp]
public var nextUp: Validated<T, Validations> {
return self.map { $0.nextUp }
}
/// See [`FloatingPoint.isNormal`](https://developer.apple.com/documentation/swift/floatingpoint/1641394-isnormal).
@ -112,42 +112,42 @@ extension Failable: FloatingPoint where T: FloatingPoint, Validations == Magnitu
/// See [`FloatingPoint.init(_:)`](https://developer.apple.com/documentation/swift/floatingpoint/1641560-init).
public init(_ value: Int) {
self = Failable(T(value))
self = Validated(initialValue: T(value))
}
/// See [`FloatingPoint.init(_:)`](https://developer.apple.com/documentation/swift/floatingpoint/2964416-init).
public init<Source>(_ value: Source) where Source : BinaryInteger {
self = Failable(T(value))
self = Validated(initialValue: T(value))
}
/// See [`FloatingPoint.init(sign:exponent:significand:`](https://developer.apple.com/documentation/swift/floatingpoint/1845755-init).
public init(sign: FloatingPointSign, exponent: Exponent, significand: Failable<T, Validations>) {
self = Failable.map(exponent, significand) { exp, sig in T(sign: sign, exponent: exp, significand: sig)}
public init(sign: FloatingPointSign, exponent: Exponent, significand: Validated<T, Validations>) {
self = Validated.map(exponent, significand) { exp, sig in T(sign: sign, exponent: exp, significand: sig)}
}
/// See [`FloatingPoint.init(signOf:magnitudeOf:)`](https://developer.apple.com/documentation/swift/floatingpoint/1849294-init).
public init(signOf sign: Failable<T, Validations>, magnitudeOf maginitude: Failable<T, Validations>) {
self = Failable.map(sign, maginitude, closure: T.init(signOf:magnitudeOf:))
public init(signOf sign: Validated<T, Validations>, magnitudeOf maginitude: Validated<T, Validations>) {
self = Validated.map(sign, maginitude, closure: T.init(signOf:magnitudeOf:))
}
/// See [`FloatingPoint.*(_:_:)`](https://developer.apple.com/documentation/swift/floatingpoint/2886135).
public static func * (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Failable<T, Validations> {
return Failable.map(lhs, rhs) { left, right in left * right }
public static func * (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Validated<T, Validations> {
return Validated.map(lhs, rhs) { left, right in left * right }
}
/// See [`FloatingPoint.*=(_:_:)`](https://developer.apple.com/documentation/swift/floatingpoint/2885700).
public static func *= (lhs: inout Failable<T, Validations>, rhs: Failable<T, Validations>) {
public static func *= (lhs: inout Validated<T, Validations>, rhs: Validated<T, Validations>) {
lhs = lhs * rhs
}
/// See [`FloatingPoint./(_:_:)`](https://developer.apple.com/documentation/swift/floatingpoint/2884057).
public static func / (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Failable<T, Validations> {
return Failable.map(lhs, rhs) { left, right in left / right }
public static func / (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Validated<T, Validations> {
return Validated.map(lhs, rhs) { left, right in left / right }
}
/// See [`FloatingPoint./=(_:_:)`](https://developer.apple.com/documentation/swift/floatingpoint/2886632).
public static func /= (lhs: inout Failable<T, Validations>, rhs: Failable<T, Validations>) {
public static func /= (lhs: inout Validated<T, Validations>, rhs: Validated<T, Validations>) {
lhs = lhs / rhs
}
@ -157,8 +157,8 @@ extension Failable: FloatingPoint where T: FloatingPoint, Validations == Magnitu
}
/// See [`FloatingPoint.formRemainder(dividingBy:)`](https://developer.apple.com/documentation/swift/floatingpoint/2299459-formremainder).
public mutating func formRemainder(dividingBy other: Failable<T, Validations>) {
self = Failable.map(self, other) { left, right in
public mutating func formRemainder(dividingBy other: Validated<T, Validations>) {
self = Validated.map(self, other) { left, right in
var result = left
result.formRemainder(dividingBy: right)
return result
@ -166,8 +166,8 @@ extension Failable: FloatingPoint where T: FloatingPoint, Validations == Magnitu
}
/// See [`FloatingPoint.formTruncatingRemainder(dividingBy:)`](https://developer.apple.com/documentation/swift/floatingpoint/1846470-formtruncatingremainder).
public mutating func formTruncatingRemainder(dividingBy other: Failable<T, Validations>) {
self = Failable.map(self, other) { left, right in
public mutating func formTruncatingRemainder(dividingBy other: Validated<T, Validations>) {
self = Validated.map(self, other) { left, right in
var result = left
result.formTruncatingRemainder(dividingBy: right)
return result
@ -184,34 +184,34 @@ extension Failable: FloatingPoint where T: FloatingPoint, Validations == Magnitu
}
/// See [`FloatingPoint.addProduct(_:_:)`](https://developer.apple.com/documentation/swift/floatingpoint/2295205-addproduct).
public mutating func addProduct(_ lhs: Failable<T, Validations>, _ rhs: Failable<T, Validations>) {
public mutating func addProduct(_ lhs: Validated<T, Validations>, _ rhs: Validated<T, Validations>) {
self = self.map { value in
var result = value
let _: Failable<(), EmptyValidation<()>> = try Failable.map(lhs, rhs) { left, right in
let _: AlwaysValidated<()> = try Validated.map(lhs, rhs) { left, right in
result.addProduct(left, right)
}.verified()
}.validate()
return result
}
}
/// See [`FloatingPoint.isEqual(to:)`](https://developer.apple.com/documentation/swift/floatingpoint/1846385-isequal).
public func isEqual(to other: Failable<T, Validations>) -> Bool {
public func isEqual(to other: Validated<T, Validations>) -> Bool {
return self == other
}
/// See [`FloatingPoint.isLess(than:)`](https://developer.apple.com/documentation/swift/floatingpoint/1849403-isless).
public func isLess(than other: Failable<T, Validations>) -> Bool {
public func isLess(than other: Validated<T, Validations>) -> Bool {
return self < other
}
/// See [`FloatingPoint.isLessThanOrEqualTo(_:)`](https://developer.apple.com/documentation/swift/floatingpoint/1849007-islessthanorequalto).
public func isLessThanOrEqualTo(_ other: Failable<T, Validations>) -> Bool {
public func isLessThanOrEqualTo(_ other: Validated<T, Validations>) -> Bool {
return self <= other
}
/// See [`FloatingPoint.isTotallyOrdered(belowOrEqualTo:)`](https://developer.apple.com/documentation/swift/floatingpoint/2428057-istotallyordered).
public func isTotallyOrdered(belowOrEqualTo other: Failable<T, MagnitudeValidation<T>>) -> Bool {
let ordered: Failable<Bool, EmptyValidation<Bool>> = Failable.map(self, other) { left, right -> Bool in
public func isTotallyOrdered(belowOrEqualTo other: Validated<T, MagnitudeValidation<T>>) -> Bool {
let ordered: AlwaysValidated<Bool> = Validated.map(self, other) { left, right -> Bool in
return left.isTotallyOrdered(belowOrEqualTo: right)
}
@ -219,12 +219,12 @@ extension Failable: FloatingPoint where T: FloatingPoint, Validations == Magnitu
}
}
extension Failable: BinaryFloatingPoint where T: BinaryFloatingPoint, Validations == MagnitudeValidation<T> {
extension Validated: BinaryFloatingPoint where T: BinaryFloatingPoint, Validations == MagnitudeValidation<T> {
/// See [`BinaryFloatingPoint.RawSignificand`](https://developer.apple.com/documentation/swift/binaryfloatingpoint/1846956-rawexponent).
public typealias RawSignificand = Failable<T.RawSignificand, EmptyValidation<T.RawSignificand>>
public typealias RawSignificand = AlwaysValidated<T.RawSignificand>
/// See [`BinaryFloatingPoint.RawExponent`](https://developer.apple.com/documentation/swift/binaryfloatingpoint/1848447-rawsignificand).
public typealias RawExponent = Failable<T.RawExponent, EmptyValidation<T.RawExponent>>
public typealias RawExponent = AlwaysValidated<T.RawExponent>
/// See [`BinaryFloatingPoint.exponentBitCount`](https://developer.apple.com/documentation/swift/binaryfloatingpoint/1847221-exponentbitcount).
public static var exponentBitCount: Int {
@ -242,34 +242,34 @@ extension Failable: BinaryFloatingPoint where T: BinaryFloatingPoint, Validation
}
/// See [`BinaryFloatingPoint.binade`](https://developer.apple.com/documentation/swift/binaryfloatingpoint/1848292-binade).
public var binade: Failable<T, Validations> {
return self[keyPath: \.binade]
public var binade: Validated<T, Validations> {
return self.map { $0.binade }
}
/// See [`BinaryFloatingPoint.exponentBitPattern`](https://developer.apple.com/documentation/swift/binaryfloatingpoint/1846505-exponentbitpattern).
public var exponentBitPattern: Failable<T.RawExponent, EmptyValidation<T.RawExponent>> {
return self[keyPath: \.exponentBitPattern]
public var exponentBitPattern: AlwaysValidated<T.RawExponent> {
return self.map { $0.exponentBitPattern }
}
/// See [`BinaryFloatingPoint.significandBitPattern`](https://developer.apple.com/documentation/swift/binaryfloatingpoint/1845838-significandbitpattern).
public var significandBitPattern: Failable<T.RawSignificand, EmptyValidation<T.RawSignificand>> {
return self[keyPath: \.significandBitPattern]
public var significandBitPattern: AlwaysValidated<T.RawSignificand> {
return self.map { $0.significandBitPattern }
}
/// See [`BinaryFloatingPoint.init(sign:exponentBitPattern:significandBitPattern)`](https://developer.apple.com/documentation/swift/binaryfloatingpoint/1849503-init).
public init(sign: FloatingPointSign, exponentBitPattern expBP: RawExponent, significandBitPattern sigBP: RawSignificand) {
self = Failable.map(expBP, sigBP) { exp, sig in T(sign: sign, exponentBitPattern: exp, significandBitPattern: sig) }
self = Validated.map(expBP, sigBP) { exp, sig in T(sign: sign, exponentBitPattern: exp, significandBitPattern: sig) }
}
}
/// See [`Numeric.*(_:_:)`](https://developer.apple.com/documentation/swift/numeric/2883821).
public func / <T, V1, V2>(lhs: Failable<T, V1>, rhs: Failable<T, V2>) -> Failable<T, AppendedValidations<V1, V2>>
public func / <T, V1, V2>(lhs: Validated<T, V1>, rhs: Validated<T, V2>) -> Validated<T, AppendedValidations<V1, V2>>
where T: FloatingPoint
{
return Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left / right }
return Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left / right }
}
/// See [`AdditiveArithmetic.-=(_:_:)`](https://developer.apple.com/documentation/swift/additivearithmetic/3126828).
public func /= <T, V1, V2>(lhs: inout Failable<T, V1>, rhs: Failable<T, V2>) where T: FloatingPoint {
lhs = Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left / right }
public func /= <T, V1, V2>(lhs: inout Validated<T, V1>, rhs: Validated<T, V2>) where T: FloatingPoint {
lhs = Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left / right }
}

View File

@ -1,21 +1,21 @@
extension Failable: UnsignedInteger where T: UnsignedInteger { }
extension Validated: UnsignedInteger where T: UnsignedInteger { }
extension Failable: SignedInteger where T: SignedInteger { }
extension Validated: SignedInteger where T: SignedInteger { }
extension Failable: FixedWidthInteger where T: FixedWidthInteger {
extension Validated: FixedWidthInteger where T: FixedWidthInteger {
/// See [`FixedWidthInteger.bitWidth`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2886552-bitwidth).
public static var bitWidth: Int {
return T.bitWidth
}
/// See [`FixedWidthInteger.min`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2884515-min).
public static var min: Failable<T, Validations> {
return Failable(T.min)
public static var min: Validated<T, Validations> {
return Validated(initialValue: T.min)
}
/// See [`FixedWidthInteger.max`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2883788-max).
public static var max: Failable<T, Validations> {
return Failable(T.max)
public static var max: Validated<T, Validations> {
return Validated(initialValue: T.max)
}
/// See [`FixedWidthInteger.nonzeroBitCount`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2885911-nonzerobitcount).
@ -29,81 +29,81 @@ extension Failable: FixedWidthInteger where T: FixedWidthInteger {
}
/// See [`FixedWidthInteger.byteSwapped`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2884324-byteswapped).
public var byteSwapped: Failable<T, Validations> {
public var byteSwapped: Validated<T, Validations> {
return self.map { $0.byteSwapped }
}
/// I don't know what this initializer is for. The `FixedWidthInteger` requires it,
/// but I can't find the documentation. Here's a unicorn instead: 🦄
public init<BI>(_truncatingBits truncatingBits: BI) where BI : BinaryInteger {
self = Failable(T(truncatingBits))
self = Validated(initialValue: T(truncatingBits))
}
/// See [`FixedWidthInteger.addingReportingOverflow(_:)`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2885260-addingreportingoverflow).
public func addingReportingOverflow(_ rhs: Failable<T, Validations>)
-> (partialValue: Failable<T, Validations>, overflow: Bool)
public func addingReportingOverflow(_ rhs: Validated<T, Validations>)
-> (partialValue: Validated<T, Validations>, overflow: Bool)
{
let result: Failable<(T, Bool), EmptyValidation<(T, Bool)>> = Failable.map(self, rhs) { left, right in
let result: AlwaysValidated<(T, Bool)> = Validated.map(self, rhs) { left, right in
return left.addingReportingOverflow(right)
}
let overflow: Failable<Bool, EmptyValidation<Bool>> = result.map { $0.1 }
let overflow: AlwaysValidated<Bool> = result.map { $0.1 }
return (partialValue: result.map { $0.0 }, overflow: overflow.value ?? false)
}
/// See [`FixedWidthInteger.subtractingReportingOverflow(_:)`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2885098-subtractingreportingoverflow).
public func subtractingReportingOverflow(_ rhs: Failable<T, Validations>)
-> (partialValue: Failable<T, Validations>, overflow: Bool)
public func subtractingReportingOverflow(_ rhs: Validated<T, Validations>)
-> (partialValue: Validated<T, Validations>, overflow: Bool)
{
let result: Failable<(T, Bool), EmptyValidation<(T, Bool)>> = Failable.map(self, rhs) { left, right in
let result: AlwaysValidated<(T, Bool)> = Validated.map(self, rhs) { left, right in
return left.subtractingReportingOverflow(right)
}
let overflow: Failable<Bool, EmptyValidation<Bool>> = result.map { $0.1 }
let overflow: AlwaysValidated<Bool> = result.map { $0.1 }
return (partialValue: result.map { $0.0 }, overflow: overflow.value ?? false)
}
/// See [`FixedWidthInteger.multipliedReportingOverflow(by:)`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2884864-multipliedreportingoverflow).
public func multipliedReportingOverflow(by rhs: Failable<T, Validations>)
-> (partialValue: Failable<T, Validations>, overflow: Bool)
public func multipliedReportingOverflow(by rhs: Validated<T, Validations>)
-> (partialValue: Validated<T, Validations>, overflow: Bool)
{
let result: Failable<(T, Bool), EmptyValidation<(T, Bool)>> = Failable.map(self, rhs) { left, right in
let result: AlwaysValidated<(T, Bool)> = Validated.map(self, rhs) { left, right in
return left.multipliedReportingOverflow(by: right)
}
let overflow: Failable<Bool, EmptyValidation<Bool>> = result.map { $0.1 }
let overflow: AlwaysValidated<Bool> = result.map { $0.1 }
return (partialValue: result.map { $0.0 }, overflow: overflow.value ?? false)
}
/// See [`FixedWidthInteger.dividedReportingOverflow(by:)`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2885588-dividedreportingoverflow).
public func dividedReportingOverflow(by rhs: Failable<T, Validations>)
-> (partialValue: Failable<T, Validations>, overflow: Bool)
public func dividedReportingOverflow(by rhs: Validated<T, Validations>)
-> (partialValue: Validated<T, Validations>, overflow: Bool)
{
let result: Failable<(T, Bool), EmptyValidation<(T, Bool)>> = Failable.map(self, rhs) { left, right in
let result: AlwaysValidated<(T, Bool)> = Validated.map(self, rhs) { left, right in
return left.dividedReportingOverflow(by: right)
}
let overflow: Failable<Bool, EmptyValidation<Bool>> = result.map { $0.1 }
let overflow: AlwaysValidated<Bool> = result.map { $0.1 }
return (partialValue: result.map { $0.0 }, overflow: overflow.value ?? false)
}
/// See [`FixedWidthInteger.remainderReportingOverflow(dividingBy:)`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2892758-remainderreportingoverflow).
public func remainderReportingOverflow(dividingBy rhs: Failable<T, Validations>)
-> (partialValue: Failable<T, Validations>, overflow: Bool)
public func remainderReportingOverflow(dividingBy rhs: Validated<T, Validations>)
-> (partialValue: Validated<T, Validations>, overflow: Bool)
{
let result: Failable<(T, Bool), EmptyValidation<(T, Bool)>> = Failable.map(self, rhs) { left, right in
let result: AlwaysValidated<(T, Bool)> = Validated.map(self, rhs) { left, right in
return left.remainderReportingOverflow(dividingBy: right)
}
let overflow: Failable<Bool, EmptyValidation<Bool>> = result.map { $0.1 }
let overflow: AlwaysValidated<Bool> = result.map { $0.1 }
return (partialValue: result.map { $0.0 }, overflow: overflow.value ?? false)
}
/// See [`FixedWidthInteger.multipliedFullWidth(by:)`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2884581-multipliedfullwidth).
public func multipliedFullWidth(by other: Failable<T, Validations>)
-> (high: Failable<T, Validations>, low: Failable<T.Magnitude, MagnitudeValidation<T.Magnitude>>)
public func multipliedFullWidth(by other: Validated<T, Validations>)
-> (high: Validated<T, Validations>, low: Validated<T.Magnitude, MagnitudeValidation<T.Magnitude>>)
{
let results: Failable<(T, T.Magnitude), EmptyValidation<(T, T.Magnitude)>> = Failable.map(self, other) { left, right in
let results: AlwaysValidated<(T, T.Magnitude)> = Validated.map(self, other) { left, right in
return left.multipliedFullWidth(by: right)
}
@ -112,23 +112,23 @@ extension Failable: FixedWidthInteger where T: FixedWidthInteger {
/// See [`FixedWidthInteger.dividingFullWidth(dividend:)`](https://developer.apple.com/documentation/swift/fixedwidthinteger/2884055-dividingfullwidth).
public func dividingFullWidth(
_ dividend: (high: Failable<T, Validations>, low: Failable<T.Magnitude, MagnitudeValidation<T.Magnitude>>)
) -> (quotient: Failable<T, Validations>, remainder: Failable<T, Validations>) {
switch (self.stored, dividend.high.stored, dividend.low.stored) {
case let (.success(l), .success(high), .success(low)):
_ dividend: (high: Validated<T, Validations>, low: Validated<T.Magnitude, MagnitudeValidation<T.Magnitude>>)
) -> (quotient: Validated<T, Validations>, remainder: Validated<T, Validations>) {
switch (self, dividend.high, dividend.low) {
case let (.value(l), .value(high), .value(low)):
let result = l.dividingFullWidth((high, low))
return (Failable(result.quotient), Failable(result.remainder))
case let (_, .failure(left), .failure(right)):
return (Validated(initialValue: result.quotient), Validated(initialValue: result.remainder))
case let (_, .error(left), .error(right)):
let error = ValidationError.foundError(ErrorJoin(left, right))
return (Failable(error), Failable(error))
case (.failure(let err), _, _), (_, .failure(let err), _), (_, _, .failure(let err)):
return (.error(error), .error(error))
case (.error(let err), _, _), (_, .error(let err), _), (_, _, .error(let err)):
let error = ValidationError.foundError(err)
return (Failable(error), Failable(error))
return (.error(error), .error(error))
}
}
}
extension Failable: BinaryInteger where T: BinaryInteger {
extension Validated: BinaryInteger where T: BinaryInteger {
/// See [`BinaryInteger.Words`](https://developer.apple.com/documentation/swift/binaryinteger/2894610-words).
public typealias Words = Array<UInt>
@ -139,29 +139,29 @@ extension Failable: BinaryInteger where T: BinaryInteger {
/// See [`BinaryInteger.init(_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2885704-init).
public init<BI>(_ source: BI) where BI: BinaryInteger {
self = Failable(T(source))
self = Validated(initialValue: T(source))
}
/// See [`BinaryInteger.init(_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2884166-init).
public init<BFP>(_ source: BFP) where BFP : BinaryFloatingPoint {
self = Failable(T(source))
self = Validated(initialValue: T(source))
}
/// See [`BinaryInteger.init(clamping:)`](https://developer.apple.com/documentation/swift/binaryinteger/2886143-init).
public init<BI>(clamping source: BI) where BI: BinaryInteger {
self = Failable(T(clamping: source))
self = Validated(initialValue: T(clamping: source))
}
/// See [`BinaryInteger.init(exactly:)`](https://developer.apple.com/documentation/swift/binaryinteger/2925955-init).
public init?<BFP>(exactly source: BFP) where BFP : BinaryFloatingPoint {
guard let value = T(exactly: source) else { return nil }
self = Failable(value)
self = Validated(initialValue: value)
}
/// See [`BinaryInteger.init(truncatingIfNeeded:)`](https://developer.apple.com/documentation/swift/binaryinteger/2925529-init).
public init<BI>(truncatingIfNeeded source: BI) where BI: BinaryInteger {
let t = T(truncatingIfNeeded: source)
self = Failable(t)
self = Validated(initialValue: t)
}
/// See [`BinaryInteger.isSigned`](https://developer.apple.com/documentation/swift/binaryinteger/2886485-issigned).
@ -180,122 +180,125 @@ extension Failable: BinaryInteger where T: BinaryInteger {
}
/// See [`BinaryInteger.~(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2884248).
public prefix static func ~ (value: Failable<T, Validations>) -> Failable<T, Validations> {
public prefix static func ~ (value: Validated<T, Validations>) -> Validated<T, Validations> {
return value.map { ~$0 }
}
/// See [`BinaryInteger./(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2885552).
public static func / (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Failable<T, Validations> {
return Failable.map(lhs, rhs) { left, right in return left / right }
public static func / (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Validated<T, Validations> {
return Validated.map(lhs, rhs) { left, right in return left / right }
}
/// See [`BinaryInteger./=(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2885191).
public static func /= (lhs: inout Failable<T, Validations>, rhs: Failable<T, Validations>) {
public static func /= (lhs: inout Validated<T, Validations>, rhs: Validated<T, Validations>) {
lhs = lhs / rhs
}
/// See [`BinaryInteger.%(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2885003).
public static func % (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Failable<T, Validations> {
return Failable.map(lhs, rhs) { left, right in return left % right }
public static func % (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Validated<T, Validations> {
return Validated.map(lhs, rhs) { left, right in return left % right }
}
/// See [`BinaryInteger.%=(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2886158).
public static func %= (lhs: inout Failable<T, Validations>, rhs: Failable<T, Validations>) {
public static func %= (lhs: inout Validated<T, Validations>, rhs: Validated<T, Validations>) {
lhs = lhs % rhs
}
/// See [`BinaryInteger.&(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/3017613).
public static func & (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Failable<T, Validations> {
return Failable.map(lhs, rhs) { left, right in return left & right }
public static func & (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Validated<T, Validations> {
return Validated.map(lhs, rhs) { left, right in return left & right }
}
/// See [`BinaryInteger.&=(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2885976).
public static func &= (lhs: inout Failable<T, Validations>, rhs: Failable<T, Validations>) {
public static func &= (lhs: inout Validated<T, Validations>, rhs: Validated<T, Validations>) {
lhs = lhs & rhs
}
/// See [`BinaryInteger.|(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/3017645).
public static func | (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Failable<T, Validations> {
return Failable.map(lhs, rhs) { left, right in return left | right }
public static func | (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Validated<T, Validations> {
return Validated.map(lhs, rhs) { left, right in return left | right }
}
/// See [`BinaryInteger.|=(_:_:)`]().
public static func |= (lhs: inout Failable<T, Validations>, rhs: Failable<T, Validations>) {
public static func |= (lhs: inout Validated<T, Validations>, rhs: Validated<T, Validations>) {
lhs = lhs | rhs
}
/// See [`BinaryInteger.^(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2884669).
public static func ^ (lhs: Failable<T, Validations>, rhs: Failable<T, Validations>) -> Failable<T, Validations> {
return Failable.map(lhs, rhs) { left, right in return left ^ right }
public static func ^ (lhs: Validated<T, Validations>, rhs: Validated<T, Validations>) -> Validated<T, Validations> {
return Validated.map(lhs, rhs) { left, right in return left ^ right }
}
/// See [`BinaryInteger.^=(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/3017635).
public static func ^= (lhs: inout Failable<T, Validations>, rhs: Failable<T, Validations>) {
public static func ^= (lhs: inout Validated<T, Validations>, rhs: Validated<T, Validations>) {
lhs = lhs ^ rhs
}
/// See [`BinaryInteger.>>=(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2926011).
public static func >>= <RHS>(lhs: inout Failable<T, Validations>, rhs: RHS) where RHS : BinaryInteger {
public static func >>= <RHS>(lhs: inout Validated<T, Validations>, rhs: RHS) where RHS : BinaryInteger {
lhs = lhs.map { $0 >> rhs }
}
/// See [`BinaryInteger.<<=(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2926303).
public static func <<= <RHS>(lhs: inout Failable<T, Validations>, rhs: RHS) where RHS : BinaryInteger {
public static func <<= <RHS>(lhs: inout Validated<T, Validations>, rhs: RHS) where RHS : BinaryInteger {
lhs = lhs.map { $0 << rhs }
}
}
/// See [`BinaryInteger.%(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2885003).
public func % <T, V1, V2>(lhs: Failable<T, V1>, rhs: Failable<T, V2>) -> Failable<T, AppendedValidations<V1, V2>>
public func % <T, V1, V2>(lhs: Validated<T, V1>, rhs: Validated<T, V2>) -> Validated<T, AppendedValidations<V1, V2>>
where T: BinaryInteger
{
return Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left % right }
return Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left % right }
}
/// See [`BinaryInteger.&(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/3017613).
public func & <T, V1, V2>(lhs: Failable<T, V1>, rhs: Failable<T, V2>) -> Failable<T, AppendedValidations<V1, V2>>
public func & <T, V1, V2>(lhs: Validated<T, V1>, rhs: Validated<T, V2>) -> Validated<T, AppendedValidations<V1, V2>>
where T: BinaryInteger
{
return Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left & right }
return Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left & right }
}
/// See [`BinaryInteger.<(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2885984).
public func < <T, V1, V2>(lhs: Failable<T, V1>, rhs: Failable<T, V2>) -> Bool
where T: BinaryInteger
public func < <T, V1, Other>(lhs: Validated<T, V1>, rhs: Other) -> Bool
where T: BinaryInteger, Other: BinaryInteger
{
return Failable<Bool, EmptyValidation<Bool>>(Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> Bool in left < right }).value ?? false
switch lhs {
case let .value(value): return value < rhs
case .error: return false
}
}
/// See [`BinaryInteger.^(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/3017635).
public func ^ <T, V1, V2>(lhs: Failable<T, V1>, rhs: Failable<T, V2>) -> Failable<T, AppendedValidations<V1, V2>>
public func ^ <T, V1, V2>(lhs: Validated<T, V1>, rhs: Validated<T, V2>) -> Validated<T, AppendedValidations<V1, V2>>
where T: BinaryInteger
{
return Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left ^ right }
return Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left ^ right }
}
/// See [`BinaryInteger.|(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/3017645).
public func | <T, V1, V2>(lhs: Failable<T, V1>, rhs: Failable<T, V2>) -> Failable<T, AppendedValidations<V1, V2>>
public func | <T, V1, V2>(lhs: Validated<T, V1>, rhs: Validated<T, V2>) -> Validated<T, AppendedValidations<V1, V2>>
where T: BinaryInteger
{
return Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left | right }
return Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left | right }
}
/// See [`BinaryInteger.%=(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2886158).
public func %= <T, V1, V2>(lhs: inout Failable<T, V1>, rhs: Failable<T, V2>) where T: BinaryInteger {
lhs = Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left % right }
public func %= <T, V1, V2>(lhs: inout Validated<T, V1>, rhs: Validated<T, V2>) where T: BinaryInteger {
lhs = Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left % right }
}
/// See [`BinaryInteger.&=(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2885976).
public func &= <T, V1, V2>(lhs: inout Failable<T, V1>, rhs: Failable<T, V2>) where T: BinaryInteger {
lhs = Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left & right }
public func &= <T, V1, V2>(lhs: inout Validated<T, V1>, rhs: Validated<T, V2>) where T: BinaryInteger {
lhs = Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left & right }
}
/// See [`BinaryInteger.^=(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2885182).
public func ^= <T, V1, V2>(lhs: inout Failable<T, V1>, rhs: Failable<T, V2>) where T: BinaryInteger {
lhs = Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left ^ right }
public func ^= <T, V1, V2>(lhs: inout Validated<T, V1>, rhs: Validated<T, V2>) where T: BinaryInteger {
lhs = Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left ^ right }
}
/// See [`BinaryInteger.|=(_:_:)`](https://developer.apple.com/documentation/swift/binaryinteger/2884669).
public func |= <T, V1, V2>(lhs: inout Failable<T, V1>, rhs: Failable<T, V2>) where T: BinaryInteger {
lhs = Failable<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left | right }
public func |= <T, V1, V2>(lhs: inout Validated<T, V1>, rhs: Validated<T, V2>) where T: BinaryInteger {
lhs = Validated<T, V1>.map(lhs, rhs) { (left: T, right: T) -> T in left | right }
}

View File

@ -1,6 +1,6 @@
extension Failable: SIMDStorage where T: SIMDStorage {
extension Validated: SIMDStorage where T: SIMDStorage {
/// See [`SIMDStorage.Scalar`](https://developer.apple.com/documentation/swift/simdstorage/3140578-scalar)
public typealias Scalar = Failable<T.Scalar, EmptyValidation<T.Scalar>>
public typealias Scalar = AlwaysValidated<T.Scalar>
/// See [`SIMDStorage.scalarCount`](https://developer.apple.com/documentation/swift/simdstorage/3140580-scalarcount)
public var scalarCount: Int {
@ -9,7 +9,7 @@ extension Failable: SIMDStorage where T: SIMDStorage {
/// See [`SIMDStorage.init()`](https://developer.apple.com/documentation/swift/simdstorage/3140579-init).
public init() {
self = Failable(T())
self = Validated(initialValue: T())
}
/// See [`subscript(_:)`](https://developer.apple.com/documentation/swift/simdstorage/3140581-subscript).
@ -25,7 +25,7 @@ extension Failable: SIMDStorage where T: SIMDStorage {
}
}
extension Failable: SIMD where T: SIMD {
extension Validated: SIMD where T: SIMD {
/// See [`SIMD.MaskStorage`](https://developer.apple.com/documentation/swift/simd/3139486-maskstorage).
public typealias MaskStorage = T.MaskStorage
}

View File

@ -1,5 +1,5 @@
/// A `Failable` type with a validation that can't fail.
public typealias NonFailable<T> = Failable<T, EmptyValidation<T>>
public typealias AlwaysValidated<T> = Validated<T, EmptyValidation<T>>
/// A type that can fail when being set because the new value does pass certain validations.
///
@ -36,91 +36,62 @@ public typealias NonFailable<T> = Failable<T, EmptyValidation<T>>
///
/// `Dictionary` and `Array` types are not supported for literal initialization yet because array
/// splatting for variadic parameters is not supported yet.
public struct Failable<T, Validations> where Validations: Validation, Validations.Supported == T {
internal private(set) var stored: Result<T, Error>
init(result: Result<T, Error>) {
self.stored = result
@propertyDelegate
public enum Validated<T, Validations> where Validations: Validation, Validations.Supported == T {
case value(T)
case error(Error)
public init(by validations: Validations.Type = Validations.self, value: T) {
self = Validated(initialValue: value)
}
init(_ error: Error) {
self.stored = .failure(error)
public init(initialValue: T?) {
guard let value = initialValue else {
self = .error(ValidationError(
identifier: "unexpectedNil",
reason: "Cannot iniitialize value of type `\(T.self)` from `nil` value")
)
return
}
do {
try Validations.run(value)
self = .value(value)
} catch let error {
self = .error(error)
}
}
/// Gets the stored value of the current instance if it exists.
///
/// Thie property will return `nil` if an error is held instead.
///
/// You can set the stored value if the `Failable` instance by using this properties setter.
/// The value will not be set if `T` is non-optional and `nil` is passed in.
public var value: T? {
get {
guard case let .success(value) = self.stored else { return nil }
guard case let .value(value) = self else { return nil }
return value
}
set {
if newValue == nil, !_isOptional(T.self) { return }
guard let value = newValue else { return }
self.stored = Result(catching: {
do {
try Validations.run(value)
return value
})
self = .value(value)
} catch let error {
self = .error(error)
}
}
}
/// Gets the error stored in the current instance.
///
/// This property returns `nil` if a value of type `T` is stored instead.
public var error: Error? {
guard case let .failure(error) = self.stored else { return nil }
return error
public func validate()throws -> Validated {
guard case let .error(error) = self else {
return self
}
throw error
}
/// Creates a new `Failable` instance.
///
/// - Parameter t: The orginal value for the instance.
/// This value will be validated and the initializer will fail if it doesn't pass.
public init(_ t: T) {
self.stored = Result.init(catching: {
try Validations.run(t)
return t
})
}
/// Creates a new `Failable` instance.
///
/// - Parameters:
/// - t: The initial value for the instance.
/// - validation: The validation type for the instance.
public init(_ t: T, _ validation: Validations.Type) {
self.init(t)
}
/// Initialize a new `Failable` instance from an already existing instance.
/// This can be useful to specify the types of an ambiguous `Failable` instance.
///
/// - Parameter failable: The `Failable` instance to initialize with.
public init(_ failable: Failable<T, Validations>) {
self = failable
}
/// Gets the value stored in the current instance.
///
/// - Returns: The stored value, of type `T`.
/// - Throws: The error stored in the current value.
public func get()throws -> T {
return try self.stored.get()
}
/// Verified that the current instance contains a value instead of an error.
/// If an error is found, it will be thrown.
///
/// - Returns: Self, if it contains a value value.
/// - Throws: The stored `Error` instance.
public func verified()throws -> Failable<T, Validations> {
switch self.stored {
case let .failure(error): throw error
case .success: return self
switch self {
case let .value(value): return value
case let .error(error): throw error
}
}
@ -132,10 +103,14 @@ public struct Failable<T, Validations> where Validations: Validation, Validation
/// - value: The stored value of the current instance that will be converted.
///
/// - Returns: A new `Failable` instance that uses the value returned by the `transform` closure.
public func map<Value, NewValidations>(_ transform: (_ value: T)throws -> Value) -> Failable<Value, NewValidations> {
switch self.stored {
case let .success(value): return Failable<Value, NewValidations>(result: Result(catching: { try transform(value) }))
case let .failure(error): return Failable<Value, NewValidations>(result: .failure(error))
public func map<Value, NewValidations>(
_ transform: (_ value: T)throws -> Value
) -> Validated<Value, NewValidations> {
switch self {
case let .value(value):
do { return try .init(initialValue: transform(value)) }
catch { return .error(error) }
case let .error(error): return .error(error)
}
}
@ -146,10 +121,12 @@ public struct Failable<T, Validations> where Validations: Validation, Validation
/// - value: The stored value of the current instance to convert.
///
/// - Returns: A new `Failable` instance with value returned by the `transform` closure.
public func map(_ transform: (_ value: T)throws -> T) -> Failable<T, Validations> {
switch self.stored {
case let .success(value): return Failable(result: Result(catching: { try transform(value) }))
case let .failure(error): return Failable(result: .failure(error))
public func map(_ transform: (_ value: T)throws -> T) -> Validated<T, Validations> {
switch self {
case let .value(value):
do { return try .init(initialValue: transform(value)) }
catch { return .error(error) }
case let .error(error): return .error(error)
}
}
@ -162,16 +139,13 @@ public struct Failable<T, Validations> where Validations: Validation, Validation
///
/// - Returns: The `Failable` instance that was returned from the `trasnform` closure.
public func flatMap<Value, NewValidations>(
_ transform: (T)throws -> Failable<Value, NewValidations>
) -> Failable<Value, NewValidations> {
switch self.stored {
case let .success(t):
do {
return try transform(t)
} catch let error {
return Failable<Value, NewValidations>(result: .failure(error))
}
case let .failure(error): return Failable<Value, NewValidations>(result: .failure(error))
_ transform: (T)throws -> Validated<Value, NewValidations>
) -> Validated<Value, NewValidations> {
switch self {
case let .value(value):
do { return try transform(value) }
catch { return .error(error) }
case let .error(error): return .error(error)
}
}
@ -182,61 +156,32 @@ public struct Failable<T, Validations> where Validations: Validation, Validation
/// - value: The stored value of the current instance that will be converted.
///
/// - Returns: The `Failable` instance that was returned from the `trasnform` closure.
public func flatMap(_ transform: (_ value: T)throws -> Failable<T, Validations>) -> Failable<T, Validations> {
switch self.stored {
case let .success(value):
do {
return try transform(value)
} catch let error {
return Failable(result: .failure(error))
}
case let .failure(error): return Failable(result: .failure(error))
public func flatMap(_ transform: (_ value: T)throws -> Validated<T, Validations>) -> Validated<T, Validations> {
switch self {
case let .value(value):
do { return try transform(value) }
catch { return .error(error) }
case let .error(error): return .error(error)
}
}
/// Accesses the value of a keypath for the stored value where the stored value type
/// and the keypath value type are equivalent.
///
/// - Parameter path: The keypath of the value to access.
/// - Returns: A `Failable` instance with the value of the keypath.
public subscript (keyPath path: KeyPath<T, T>) -> Failable<T, Validations> {
return self.map { value in value[keyPath: path] }
}
/// Accesses the value of a keypath for the stored value where the stored value type and keypath value type are different.
///
/// - Parameter path: The keypath of the value to access.
/// - Returns: A `Failable` instance with the value of the keypath.
public subscript <Value, NewValidations>(keyPath path: KeyPath<T, Value>) -> Failable<Value, NewValidations> {
return self.map { value in value[keyPath: path] }
}
}
extension Failable {
extension Validated {
public static func map<A, B, R, AV, BV, RV>(
_ left: Failable<A, AV>,
_ right: Failable<B, BV>,
_ left: Validated<A, AV>,
_ right: Validated<B, BV>,
closure: (A, B)throws -> R
) -> Failable<R, RV> {
switch (left.stored, right.stored) {
case let (.success(l), .success(r)): return Failable<R, RV>(result: Result(catching: { try closure(l, r) }))
case let (.failure(l), .failure(r)): return Failable<R, RV>(ValidationError.foundError(ErrorJoin(l, r)))
case let (.success, .failure(error)): return Failable<R, RV>(ValidationError.foundError(error))
case let (.failure(error), .success): return Failable<R, RV>(ValidationError.foundError(error))
) -> Validated<R, RV> {
switch (left, right) {
case let (.value(l), .value(r)):
do {
return try Validated<R, RV>(initialValue: closure(l, r))
} catch let error {
return .error(error)
}
case let (.error(l), .error(r)): return .error(ValidationError.foundError(ErrorJoin(l, r)))
case let (.value, .error(error)): return .error(ValidationError.foundError(error))
case let (.error(error), .value): return .error(ValidationError.foundError(error))
}
}
}
extension CustomStringConvertible {
/// Easily create `Failable` versions of types conforming to `CustomStringConvertible`. This includes most, if not all, core Swift types.
///
/// This paramater defaults to its own type, so if the validation type can be infered, you don't need to pass the paramater in.
///
/// var story: Failable<String, Length1028> = try "Once upon a time...".failable()
///
/// - Parameter validations: The validation type to use when mutating the stored value.
public func failable<Validations>(_ validations: Validations.Type = Validations.self) -> Failable<Self, Validations> {
return Failable(self)
}
}

View File

@ -1,15 +0,0 @@
infix operator <~: AssignmentPrecedence
/// Sets the stored value of a `Failable` type.
///
/// You have to use this operator instead of `=` so the validations always run on the new value before it is assigned.
///
/// - Complexity: O(n^m), where _n_ is the number of type compatible sub-validations for the `Failable` type's sub-validations
/// and _m_ is the depth of the sub-validations.
///
/// - Parameters:
/// - root: The `Failable` instance that holds the value to be mutated.
/// - value: The new value for the `root.value` property.
public func <~ <T, Validations>(root: inout Failable<T, Validations>, value: T) {
root.value = value
}

View File

@ -1,44 +0,0 @@
import XCTest
@testable import Failable
final class FailableTests: XCTestCase {
func testInit()throws {
var story: NonFailable<String> = "Hello world...".failable()
XCTAssertEqual(story.value, "Hello world...")
story = "Long long ago...".failable()
XCTAssertEqual(story.value, "Long long ago...")
}
func testSet()throws {
var story: NonFailable<String> = "Hello world...".failable()
story <~ "Long long ago..."
XCTAssertEqual(story.value, "Long long ago...")
}
func testKeyPathSubscript()throws {
let string = "Hello World"
let failable: NonFailable<String> = string.failable()
XCTAssertEqual(failable[keyPath: \.count], string.count)
}
func testEncode()throws {
let data = Failable(["key": "value"], EmptyValidation<[String: String]>.self)
let json = try String(data: JSONEncoder().encode(data), encoding: .utf8)
XCTAssertEqual(json, "{\"key\":\"value\"}")
}
func testDecode()throws {
let json = """
{
"key": "value"
}
""".data(using: .utf8)!
let object = try JSONDecoder().decode(NonFailable<[String: String]>.self, from: json)
XCTAssertEqual(object.value, ["key": "value"])
}
}

View File

@ -0,0 +1,35 @@
@testable import Failable
import XCTest
struct IsTrue: Validation {
static func validate(_ value: Bool) throws {
guard value else {
throw ValidationError(identifier: "expectedTrue", reason: "Bool value must be `true`")
}
}
}
struct Test: Codable, Hashable {
@Validated<Bool, IsTrue> var bool: Bool = nil
}
final class PropertyWrapperTests: XCTestCase {
func testWrapper() throws {
var test = Test()
XCTAssertEqual(test.bool, true)
test.bool = false
XCTAssertNotEqual(test.bool, false)
}
}
extension Validated {
mutating func test(_ newValue: T) throws {
self.value = newValue
switch self {
case let .error(error): throw error
case .value: return
}
}
}

View File

@ -0,0 +1,39 @@
import XCTest
@testable import Failable
fileprivate struct Data: Codable {
@AlwaysValidated<String> var string: String
}
final class ValidatedTests: XCTestCase {
func testInit()throws {
let story = Data(string: "Hello World...")
_ = try story.$string.get()
}
func testSet()throws {
var story = Data(string: "Hello World...")
_ = try story.$string.get()
try story.$string.test("Long long ago...")
XCTAssertEqual(story.string, "Long long ago...")
}
func testEncode()throws {
let data = Data(string: "Hello")
let json = try String(data: JSONEncoder().encode(data), encoding: .utf8)
XCTAssertEqual(json, "{\"string\":\"Hello\"}")
}
func testDecode()throws {
let json = """
{
"string": "hello"
}
""".data(using: .utf8)!
let object = try JSONDecoder().decode(Data.self, from: json)
XCTAssertEqual(object.string, "hello")
}
}

View File

@ -13,36 +13,34 @@ internal struct Length1028<C>: LengthValidation where C: Collection {
static var maxLength: Int { return 1028 }
}
internal typealias StringLengthArray = ElementValidation<[String], Length1028<String>>
fileprivate struct Lists {
@Validated<[Bool], LengthRange10To1028<[Bool]>> var bools: [Bool]
@Validated<[String], ElementValidation<[String], Length1028<String>>> var strings: [String]
}
final class CollectionTests: XCTestCase {
func testLengthValidation()throws {
try XCTAssertThrowsError(Failable([], LengthRange10To1028<[Bool]>.self).get())
var lists = Lists(bools: [], strings: [])
_ = try lists.$bools.get()
try lists.$bools.test([true, true, true, false, false, false, true, true, false, false])
try lists.$bools.test(Array(repeating: true, count: 1028))
var bools = Failable([true, true, true, false, false, false, true, true, false, false], LengthRange10To1028<[Bool]>.self)
XCTAssertEqual(bools.value, [true, true, true, false, false, false, true, true, false, false])
bools <~ Array(repeating: true, count: 5)
bools <~ Array(repeating: false, count: 5)
bools <~ Array(repeating: true, count: 1029)
bools <~ Array(repeating: false, count: 1029)
try XCTAssertThrowsError(bools.get())
let array = Array(repeating: true, count: 1028)
bools <~ array
XCTAssertEqual(bools.value, array)
try XCTAssertThrowsError(lists.$bools.test(Array(repeating: true, count: 5)))
try XCTAssertThrowsError(lists.$bools.test(Array(repeating: false, count: 5)))
try XCTAssertThrowsError(lists.$bools.test(Array(repeating: true, count: 1029)))
try XCTAssertThrowsError(lists.$bools.test(Array(repeating: false, count: 1029)))
}
func testElementValidation()throws {
let tooLong = String(repeating: "x", count: 1029)
let longest = String(repeating: "g", count: 1028)
var strings = Failable<[String], StringLengthArray>(["G", "D", "A", "E"])
XCTAssertEqual(strings.value, ["G", "D", "A", "E"])
strings <~ ["G", "O", "O", tooLong]
try XCTAssertThrowsError(strings.get())
var lists = Lists(bools: [], strings: ["G", "D", "A", "E"])
_ = try lists.$strings.get()
strings <~ ["G", "OOOO", "World", longest]
XCTAssertEqual(strings.value, ["G", "OOOO", "World", longest])
let longest = String(repeating: "g", count: 1028)
try lists.$strings.test(["G", "OOOO", "World", longest])
let tooLong = String(repeating: "x", count: 1029)
try lists.$strings.test(["G", "O", "O", tooLong])
}
}

View File

@ -20,44 +20,46 @@ internal struct LessThan: InRangeValidation {
static let max: Int? = 9_999
}
fileprivate struct Numbers {
@Validated<Int, NumberThousand> var thousands: Int
@Validated<Int, GreaterThan> var large: Int
@Validated<Int, LessThan> var small: Int
}
final class ComparableTests: XCTestCase {
func testNumberThousand()throws {
var int = Failable<Int, NumberThousand>(5_000)
var numbers = Numbers(thousands: 5_000, large: 0, small: 0)
_ = try numbers.$thousands.get()
try numbers.$thousands.test(9_999)
try numbers.$thousands.test(1_000)
int <~ 9_999
int <~ 1_000
try XCTAssertNoThrow(int.get())
int <~ 999
int <~ 10_000
try XCTAssertThrowsError(int.get())
try XCTAssertThrowsError(numbers.$thousands.test(999))
try XCTAssertThrowsError(numbers.$thousands.test(10_000))
}
func testGreaterThan()throws {
var int = Failable<Int, GreaterThan>(5_000)
var numbers = Numbers(thousands: 0, large: 5_000, small: 0)
int <~ 1_000
int <~ 10_000
int <~ Int.max
try XCTAssertNoThrow(int.get())
try numbers.$large.test(1_000)
try numbers.$large.test(10_000)
try numbers.$large.test(Int.max)
int <~ 999
int <~ 0
int <~ Int.min
try XCTAssertThrowsError(int.get())
try XCTAssertThrowsError(numbers.$large.test(999))
try XCTAssertThrowsError(numbers.$large.test(0))
try XCTAssertThrowsError(numbers.$large.test(Int.min))
}
func testLessThan()throws {
var int = Failable<Int, LessThan>(5_000)
var numbers = Numbers(thousands: 0, large: 0, small: 5_000)
_ = try numbers.$small.get()
int <~ 9_999
int <~ 999
int <~ 0
int <~ Int.min
try XCTAssertNoThrow(int.get())
try numbers.$small.test(9_999)
try numbers.$small.test(999)
try numbers.$small.test(0)
try numbers.$small.test(Int.min)
int <~ 10_000
int <~ Int.max
try XCTAssertThrowsError(int.get())
try XCTAssertThrowsError(numbers.$small.test(10_000))
try XCTAssertThrowsError(numbers.$small.test(Int.max))
}
}

View File

@ -3,30 +3,32 @@ import XCTest
typealias OptionalStringLength = NotNilValidate<LengthRange10To1028<String>>
fileprivate struct Optionals {
@Validated<Bool?, NotNil<Bool>> var bool: Bool
@Validated<String?, OptionalStringLength> var string: String
}
final class OptionalTests: XCTestCase {
func testNotNil()throws {
var optional: Failable<Bool?, NotNil<Bool>> = false
var optionals = Optionals(bool: false, string: "")
_ = try optionals.$bool.get()
try optionals.$bool.test(true)
try optionals.$bool.test(false)
optional <~ true
optional <~ false
try XCTAssertNoThrow(optional.get())
optional <~ nil
try XCTAssertThrowsError(optional.get())
try XCTAssertThrowsError(optionals.$bool.test(nil))
}
func testNotNilValidate()throws {
var optional: Failable<String?, OptionalStringLength> = "Hello World"
var optionals = Optionals(bool: true, string: "Hello World")
optional <~ "Long long ago"
optional <~ String(repeating: "x", count: 10)
optional <~ String(repeating: "x", count: 1028)
optional <~ nil
try XCTAssertNoThrow(optional.get())
try optionals.$string.test("Long long ago")
try optionals.$string.test(String(repeating: "x", count: 10))
try optionals.$string.test(String(repeating: "x", count: 1028))
try optionals.$string.test(nil)
optional <~ String(repeating: "x", count: 9)
optional <~ String(repeating: "x", count: 1029)
try XCTAssertThrowsError(optional.get())
try XCTAssertThrowsError(optionals.$string.test(String(repeating: "x", count: 9)))
try XCTAssertThrowsError(optionals.$string.test(String(repeating: "x", count: 1029)))
}
}

View File

@ -5,20 +5,23 @@ internal struct USPhoneNumber: RegexValidation {
static let pattern = "1?-?\\(?[0-9]{3}\\)?-?[0-9]{3}-?[0-9]{4}"
}
fileprivate struct Number {
@Validated<String, USPhoneNumber> var phone: String
}
final class StringTests: XCTestCase {
func testUSPhoneNumber()throws {
var number: Failable<String, USPhoneNumber> = "731-943-4316".failable()
var number = Number(phone: "731-943-4316")
_ = try number.$phone.get()
number <~ "(731)-943-4316"
number <~ "1-731-943-4316"
number <~ "7319434316"
try XCTAssertNoThrow(number.get())
try number.$phone.test("(731)-943-4316")
try number.$phone.test("1-731-943-4316")
try number.$phone.test("7319434316")
number <~ ""
number <~ "943-4316"
number <~ "1-800-EAT-MEAT"
number <~ "4316-943-731"
try XCTAssertThrowsError(number.get())
XCTAssertThrowsError(try number.$phone.test(""))
XCTAssertThrowsError(try number.$phone.test("943-4316"))
XCTAssertThrowsError(try number.$phone.test("1-800-EAT-MEAT"))
XCTAssertThrowsError(try number.$phone.test("4316-943-731"))
}
}