 import enum Result.NoError
 
 /// Describes how multiple producers should be joined together.
-public enum FlattenStrategy: Equatable {
+public struct FlattenStrategy {
+	fileprivate enum Kind {
+		case concurrent(limit: UInt)
+		case latest
+		case race
+	}
+
+	fileprivate let kind: Kind
+
+	private init(kind: Kind) {
+		self.kind = kind
+	}
+
 	/// The producers should be merged, so that any value received on any of the
 	/// input producers will be forwarded immediately to the output producer.
 	///
 	/// The resulting producer will complete only when all inputs have
 	/// completed.
-	public static let merge = FlattenStrategy.concurrent(limit: .max)
+	public static let merge = FlattenStrategy(kind: .concurrent(limit: .max))
 
 	/// The producers should be concatenated, so that their values are sent in
 	/// the order of the producers themselves.
 	///
 	/// The resulting producer will complete only when all inputs have
 	/// completed.
-	public static let concat = FlattenStrategy.concurrent(limit: 1)
+	public static let concat = FlattenStrategy(kind: .concurrent(limit: 1))
 
 	/// The producers should be merged, but only up to the given limit at any
 	/// point of time, so that any value received on any of the input producers

	/// The resulting producer will complete when:
	/// 1. The producer-of-producers and the first "alive" producer has completed.
	/// 2. The producer-of-producers has completed without inner producer being "alive".
	case race

	public static func ==(left: FlattenStrategy, right: FlattenStrategy) -> Bool {
		switch (left, right) {
		case (.latest, .latest):
			return true

		case (.concurrent(let leftLimit), .concurrent(let rightLimit)):
			return leftLimit == rightLimit

		default:
			return false
		}
	}
}

extension Signal where Value: SignalProducerConvertible, Error == Value.Error {

	/// - parameters:
	///   - strategy: Strategy used when flattening signals.
	public func flatten(_ strategy: FlattenStrategy) -> Signal<Value.Value, Value.Error> {
		switch strategy.kind {
		case .concurrent(let limit):
			return self.concurrent(limit: limit)

