<commit_before>//
//  Validated.swift
//  Validated
//
//  Created by <NAME> on 2/24/16.
//  Copyright © 2016 <NAME>. All rights reserved.
//

/// This protocol needs to be implemented in order to add a requirement to
/// a wrapped type.
/// Implementers receive the wrapped type and need to determine if its values
/// fulfill the requirements of the wrapper type.
/// ~~~
/// struct NonEmptyStringValidator: Validator {
///     static func validate(value: String) -> Bool {
///         return !value.isEmpty
///     }
/// }
/// ~~~
public protocol Validator {
    typealias WrappedType

    /// Validates if a value of the wrapped type fullfills the requirements of the
    /// wrapper type.
    ///
    /// - parameter validate: An instance of the `WrappedType`
    /// - returns: A `Bool` indicating success(`true`)/failure(`false`) of the validation
    static func validate(value: WrappedType) -> Bool
}

/// Wraps a type together with one validator. Provides a failable initializer
/// that will only return a value of `Validated` if the provided `WrapperType` value
/// fulfills the requirements of the specified `Validator`.
public struct Validated<WrapperType, V: Validator where V.WrappedType == WrapperType> {
    /// The value that passes the defined `Validator`.
    ///
    /// If you are able to access this property; it means the wrappedType passes the validator.
    public let value: WrapperType

    /// Failible initializer that will only succeed if the provided value fulfills the requirements specified by the `Validator`.
    public init?(_ value: WrapperType) {
        guard V.validate(value) else { return nil }
        self.value = value
    }
}

/// Wraps a type together with two validators. Provides a failable initializer
/// that will only return a value of `Validated` if the provided `WrapperType` value
/// fulfills the requirements of both specified `Validator` types.
public struct Validated2<
    WrapperType,
    V1: Validator,
    V2: Validator where
        V1.WrappedType == WrapperType,
        V2.WrappedType == WrapperType> {
    /// The value that passes the two provided `Validator`s.
    public let value: WrapperType

    /// Failible initializer that will only succeed if the provided value fulfills the requirements specified by the `Validator`s.
    public init?(_ value: WrapperType) {
        guard V1.validate(value) && V2.validate(value) else { return nil }
        self.value = value
    }
}

/// Wraps a type together with three validators. Provides a failable initializer
/// that will only return a value of `Validated` if the provided `WrapperType` value
/// fulfills the requirements of all three specified `Validator` types.
public struct Validated3<
    WrapperType,
    V1: Validator,
    V2: Validator,
    V3: Validator where
        V1.WrappedType == WrapperType,
        V2.WrappedType == WrapperType,
        V3.WrappedType == WrapperType> {
    /// The value that passes the three provided `Validator`s.
    public let value: WrapperType

    /// Failable initializer that will only succeed if the provided value fulfills the requirements specified by the `Validator`s.
    public init?(_ value: WrapperType) {
        guard V1.validate(value) && V2.validate(value) && V3.validate(value) else { return nil }
        self.value = value
    }
}

/// Validator wrapper which is valid when `V1` and `V2` validated to `true`.
public struct And<
    V1: Validator,
    V2: Validator where
        V1.WrappedType == V2.WrappedType>: Validator {
    public static func validate(value: V1.WrappedType) -> Bool {
        return V1.validate(value) && V2.validate(value)
    }
}

/// Validator wrapper which is valid when either `V1` or `V2` validated to `true`.
public struct Or<<commit_msg>[Validation] Add Throwing Initializer<commit_after>//
//  Validated.swift
//  Validated
//
//  Created by <NAME> on 2/24/16.
//  Copyright © 2016 <NAME>. All rights reserved.
//

/// This protocol needs to be implemented in order to add a requirement to
/// a wrapped type.
/// Implementers receive the wrapped type and need to determine if its values
/// fulfill the requirements of the wrapper type.
/// ~~~
/// struct NonEmptyStringValidator: Validator {
///     static func validate(value: String) -> Bool {
///         return !value.isEmpty
///     }
/// }
/// ~~~
public protocol Validator {
    typealias WrappedType

    /// Validates if a value of the wrapped type fullfills the requirements of the
    /// wrapper type.
    ///
    /// - parameter validate: An instance of the `WrappedType`
    /// - returns: A `Bool` indicating success(`true`)/failure(`false`) of the validation
    static func validate(value: WrappedType) -> Bool
}


/// Error that is thrown when a validation fails. Proivdes the validator type and 
/// the value that failed validation
public struct ValidatorError: ErrorType, CustomStringConvertible {
    /// The value that failed validation.
    public let wrapperValue: Any
    /// Type of a specific `Validator`. `Any` is used because `Validator` has associated type requirements.
    public let validator: Any.Type

    public var description: String {
        return "Value: '\(wrapperValue)' <\(wrapperValue.dynamicType)>, failed validation of Validator: \(validator.self)"
    }
}

/// Wraps a type together with one validator. Provides a failable initializer
/// that will only return a value of `Validated` if the provided `WrapperType` value
/// fulfills the requirements of the specified `Validator`.
public struct Validated<WrapperType, V: Validator where V.WrappedType == WrapperType> {
    /// The value that passes the defined `Validator`.
    ///
    /// If you are able to access this property; it means the wrappedType passes the validator.
    public let value: WrapperType

    /// Throwing initializer that will *not* throw an error if the provided value fulfills the requirements 
    /// specified by the `Validator`.
    public init(_ value: WrapperType) throws {
        guard V.validate(value) else {
            throw ValidatorError(
                wrapperValue: value,
                validator: V.self)
        }

/// Wraps a type together with two validators. Provides a failable initializer
/// that will only return a value of `Validated` if the provided `WrapperType` value
/// fulfills the requirements of both specified `Validator` types.
public struct Validated2<
    WrapperType,
    V1: Validator,
    V2: Validator where
        V1.WrappedType == WrapperType,
        V2.WrappedType == WrapperType> {
    /// The value that passes the two provided `Validator`s.
    public let value: WrapperType

    /// Failible initializer that will only succeed if the provided value fulfills the requirements specified by the `Validator`s.
    public init?(_ value: WrapperType) {
        guard V1.validate(value) && V2.validate(value) else { return nil }
        self.value = value
    }
}

/// Wraps a type together with three validators. Provides a failable initializer
/// that will only return a value of `Validated` if the provided `WrapperType` value
/// fulfills the requirements of all three specified `Validator` types.
public struct Validated3<
    WrapperType,
    V1: Validator,
    V2: Validator,
    V3: Validator where
        V1.WrappedType == WrapperType,
        V2.WrappedType == WrapperType,
        V3.WrappedType == WrapperType> {
    /// The value that passes the three provided `Validator`s.
    public let value: WrapperType

    /// Failible initializer that will only succeed if the provided value fulfills the requirements specified by the `Validator`.
    public init?(value: WrapperType) {
    }
}

/// Validator wrapper which is valid when `V1` and `V2` validated to `true`.
public struct And<
    V1: Validator,
    V2: Validator where
        V1.WrappedType == V2.WrappedType>: Validator {
    public static func validate(value: V1.WrappedType) -> Bool {
        return V1.validate(value) && V2.validate(value)
    }
}

/// Validator wrapper which is valid when either `V1` or `V2` validated to `true`.
public struct Or<
{'fraction_non_alphanumeric': 0.09630639563708478, 'fraction_numerical': 0.00880019831432821, 'mean_word_length': 2.9303458353628837, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1327095', 'n_tokens_mistral': 2216, 'n_tokens_neox': 2164, 'n_words': 898}