 /// Optionally, make the cycling `reversible`
 /// in either direction, so instead of starting
 /// again, it reverses when it reaches min/max.
+/// Alternatively, make this `finite` so that
+/// it stops when its bound is reached.
 @propertyWrapper
-public struct Cycled : DynamicProperty {
-    private let min:Int
-    private let max:Int
-    private let reversible:Bool
-    @State private var number:Int = 0
+public struct Cycled<T:SignedNumeric & Comparable> : DynamicProperty {
+    /// Type of cycling behavior
+    public enum Mode {
+        /// Cycle numbers from beginning and when
+        /// reaching the end, start at the beginning.
+        /// Default cycling behavior.
+        case repeatable
+        /// Cycle numbers from beginning and when
+        /// reaching the end, go back to the beginning
+        /// and vice versa.
+        case reversible
+        /// Cycle numbers from beginning and when
+        /// reaching the end, stop.
+        case finite
+    }
+    private let min:T
+    private let max:T
+    private let mode:Mode
+    private var reversible:Bool {
+        mode == .reversible
+    }
+    private var finite:Bool {
+        mode == .finite
+    }
+    @State private var number:T = 0
     @State private var shouldReverse:Bool = false
-    public var wrappedValue:Int {
+    public var wrappedValue:T {
         get { return number }
         nonmutating set {
-            guard newValue != 0 else { return }
+            guard newValue != T.zero else { return }
             let value = shouldReverse ? -newValue : newValue
             let newNumber = number + value
-            if value < 0 { // decrementing
+            if value < T.zero { // decrementing
                 if newNumber < min {
-                    number = max
+                    if reversible || finite {
+                        // Past min value, clamp to min.
+                        // It will either start going back the opposite way
+                        // for "reversible" or just stay there for "finite".
+                        number = min
+                    } else {
+                        // Past min, start again at max. "repeatable"
+                        number = max
+                    }
                 } else {
                     number = newNumber
                 }
             } else { // incrementing
                 if newNumber > max {
-                    number = min
+                    if reversible || finite {
+                        number = max
+                    } else {
+                        number = min
+                    }
                 } else {
                     number = newNumber
                 }

}
#endif

/// Property that cycles through integers
/// resetting to 0 when `max` is reached.
///
/// Alternatively, pass `min` to reset to

/// Optionally, make the cycling `reversible`
/// in either direction, so instead of starting
/// again, it reverses when it reaches min/max.
/// Alternatively, make this `finite` so that
/// it stops when its bound is reached.
/// See also @Cycled if this is used in SwiftUI.
@propertyWrapper
public struct CycledRaw<T:SignedNumeric & Comparable> {
    public enum Mode {
        case repeatable, reversible, finite
    }
    private let min:T
    private let max:T
    private let mode:Mode
    private var reversible:Bool {
        mode == .reversible
    }
    private var finite:Bool {
        mode == .finite
    }
    private var shouldReverse:Bool = false
    private var number:T
    public var wrappedValue:T {
        get { return number }
        set {
            guard newValue != T.zero else { return }
            let value = shouldReverse ? -newValue : newValue
            let newNumber = number + value
            if newValue < T.zero { // decrementing
                if newNumber < min {
                    if reversible || finite {
                        number = min
                    } else {
                        number = max
                    }
                } else {
                    number = newNumber
                }
            } else { // incrementing
                if newNumber > max {
                    if reversible || finite {
                        number = max
                    } else {
                        number = min
                    }
                } else {
                    number = newNumber
                }
