diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
deleted file mode 100644
--- a/CHANGELOG.markdown
+++ /dev/null
@@ -1,4 +0,0 @@
-# Change log
-
-Witch follows the [Package Versioning Policy](https://pvp.haskell.org). You can
-find release notes [on GitHub](https://github.com/tfausak/witch/releases).
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,4 @@
+# Change log
+
+Witch follows the [Package Versioning Policy](https://pvp.haskell.org). You can
+find release notes [on GitHub](https://github.com/tfausak/witch/releases).
diff --git a/LICENSE.markdown b/LICENSE.markdown
deleted file mode 100644
--- a/LICENSE.markdown
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2023 Taylor Fausak
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 Taylor Fausak
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.markdown b/README.markdown
deleted file mode 100644
--- a/README.markdown
+++ /dev/null
@@ -1,9 +0,0 @@
-# Witch
-
-[![Workflow](https://github.com/tfausak/witch/actions/workflows/workflow.yaml/badge.svg)](https://github.com/tfausak/witch/actions/workflows/workflow.yaml)
-[![Hackage](https://img.shields.io/hackage/v/witch)](https://hackage.haskell.org/package/witch)
-[![Stackage](https://www.stackage.org/package/witch/badge/nightly?label=stackage)](https://www.stackage.org/package/witch)
-
-:mage_woman: Convert values from one type into another.
-
-See the documentation on Hackage: <https://hackage.haskell.org/package/witch>.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,8 @@
+# Witch
+
+[![CI](https://github.com/tfausak/witch/actions/workflows/ci.yml/badge.svg)](https://github.com/tfausak/witch/actions/workflows/ci.yml)
+[![Hackage](https://badgen.net/hackage/v/witch)](https://hackage.haskell.org/package/witch)
+
+:mage_woman: Convert values from one type into another.
+
+See the documentation on Hackage: <https://hackage.haskell.org/package/witch>.
diff --git a/source/hedgehog/Main.hs b/source/hedgehog/Main.hs
new file mode 100644
--- /dev/null
+++ b/source/hedgehog/Main.hs
@@ -0,0 +1,1561 @@
+{-# LANGUAGE DerivingVia #-}
+
+import qualified Control.Monad.Trans.Writer as Writer
+import qualified Data.Bits as Bits
+import qualified Data.ByteString as ByteString
+import qualified Data.ByteString.Lazy as LazyByteString
+import qualified Data.ByteString.Short as ShortByteString
+import qualified Data.Complex as Complex
+import qualified Data.Fixed as Fixed
+import qualified Data.Int as Int
+import qualified Data.IntMap as IntMap
+import qualified Data.IntSet as IntSet
+import qualified Data.List.NonEmpty as NonEmpty
+import qualified Data.Map as Map
+import qualified Data.Maybe as Maybe
+import qualified Data.Monoid as Monoid
+import qualified Data.Ratio as Ratio
+import qualified Data.Semigroup as Semigroup
+import qualified Data.Sequence as Seq
+import qualified Data.Set as Set
+import qualified Data.String as String
+import qualified Data.Tagged as Tagged
+import qualified Data.Text as Text
+import qualified Data.Text.Lazy as LazyText
+import qualified Data.Time as Time
+import qualified Data.Typeable as Typeable
+import qualified Data.Void as Void
+import qualified Data.Word as Word
+import qualified GHC.Stack as Stack
+import qualified Hedgehog as H
+import qualified Hedgehog.Gen as Gen
+import qualified Hedgehog.Main as Main
+import qualified Hedgehog.Range as Range
+import qualified Numeric.Natural as Natural
+import qualified System.OsString as OsString
+import qualified Witch
+import qualified Witch.Encoding as Encoding
+
+main :: IO ()
+main = Main.defaultMain $ fmap H.checkParallel groups
+
+groups :: [H.Group]
+groups =
+  [ groupA,
+    groupList,
+    groupInt8,
+    groupInt16,
+    groupInt32,
+    groupInt64,
+    groupInt,
+    groupInteger,
+    groupWord8,
+    groupWord16,
+    groupWord32,
+    groupWord64,
+    groupWord,
+    groupNatural,
+    groupFloat,
+    groupDouble,
+    groupPico,
+    groupNonEmpty,
+    groupSet,
+    groupIntSet,
+    groupMap,
+    groupIntMap,
+    groupSeq,
+    groupByteString,
+    groupLazyByteString,
+    groupShortByteString,
+    groupOsString,
+    groupText,
+    groupLazyText,
+    groupString,
+    groupMonoid,
+    groupSemigroup,
+    groupBool,
+    groupTime,
+    groupLatin1S,
+    groupLatin1L,
+    groupUtf8S,
+    groupUtf8L,
+    groupUtf16LS,
+    groupUtf16LL,
+    groupUtf16BS,
+    groupUtf16BL,
+    groupUtf32LS,
+    groupUtf32LL,
+    groupUtf32BS,
+    groupUtf32BL
+  ]
+
+groupA :: H.Group
+groupA = group "a" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Word.Word8
+
+  property "a" $ do
+    let t = s
+    fromFrom s t $ Gen.integral Range.linearBounded
+
+  property "Tagged" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy (Tagged.Tagged () Word.Word8)
+    fromFrom s t $ Gen.integral Range.linearBounded
+
+groupList :: H.Group
+groupList = group "List" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy [Word.Word8]
+
+  property "Set" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy (Set.Set Word.Word8)
+    fromFrom s t . Gen.list (Range.linear 0 10) $ Gen.integral Range.linearBounded
+
+groupInt8 :: H.Group
+groupInt8 = group "Int8" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Int.Int8
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    fromTryFrom s t . Gen.integral $ Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 maxBound
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f32) (mkUpperBound s f32)
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f64) (mkUpperBound s f64)
+
+groupInt16 :: H.Group
+groupInt16 = group "Int16" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Int.Int16
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 maxBound
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f32) (mkUpperBound s f32)
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f64) (mkUpperBound s f64)
+
+groupInt32 :: H.Group
+groupInt32 = group "Int32" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Int.Int32
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 maxBound
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f32) (mkUpperBound s f32)
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f64) (mkUpperBound s f64)
+
+groupInt64 :: H.Group
+groupInt64 = group "Int64" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Int.Int64
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 maxBound
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f32) (mkUpperBound s f32)
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f64) (mkUpperBound s f64)
+
+groupInt :: H.Group
+groupInt = group "Int" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Int
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 maxBound
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f32) (mkUpperBound s f32)
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f64) (mkUpperBound s f64)
+
+groupInteger :: H.Group
+groupInteger = group "Integer" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Integer
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromFrom s t . Gen.integral $ fmap (toInteger . asProxy t) Range.linearBounded
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    tryFromFrom s t . Gen.integral $ fmap (toInteger . asProxy t) Range.linearBounded
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    tryFromFrom s t . Gen.integral $ fmap (toInteger . asProxy t) Range.linearBounded
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    tryFromFrom s t . Gen.integral $ fmap (toInteger . asProxy t) Range.linearBounded
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    tryFromFrom s t . Gen.integral $ fmap (toInteger . asProxy t) Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . Gen.integral $ fmap (toInteger . asProxy t) Range.linearBounded
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromFrom s t . Gen.integral $ fmap (toInteger . asProxy t) Range.linearBounded
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    tryFromFrom s t . Gen.integral $ fmap (toInteger . asProxy t) Range.linearBounded
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    tryFromFrom s t . Gen.integral $ fmap (toInteger . asProxy t) Range.linearBounded
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    tryFromFrom s t . Gen.integral $ fmap (toInteger . asProxy t) Range.linearBounded
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    tryFromFrom s t . Gen.integral $ Range.linear 0 9999999999999999999
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    tryFromTryFrom s t . Gen.integral $ fmap (toInteger . asProxy f32) Range.linearBounded
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    tryFromTryFrom s t . Gen.integral $ fmap (toInteger . asProxy f64) Range.linearBounded
+
+  property "Complex" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy (Complex.Complex Integer)
+    fromTryFrom s t . Gen.integral $ Range.linear (-1000) 1000
+
+  property "Ratio" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy (Ratio.Ratio Integer)
+    fromTryFrom s t . Gen.integral $ Range.linear (-1000) 1000
+
+  property "Pico" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Fixed.Pico
+    fromTryFrom s t . Gen.integral $ Range.linear (-1000000000000) 1000000000000
+
+groupWord8 :: H.Group
+groupWord8 = group "Word8" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Word.Word8
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f32) (mkUpperBound s f32)
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f64) (mkUpperBound s f64)
+
+groupWord16 :: H.Group
+groupWord16 = group "Word16" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Word.Word16
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f32) (mkUpperBound s f32)
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f64) (mkUpperBound s f64)
+
+groupWord32 :: H.Group
+groupWord32 = group "Word32" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Word.Word32
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f32) (mkUpperBound s f32)
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f64) (mkUpperBound s f64)
+
+groupWord64 :: H.Group
+groupWord64 = group "Word64" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Word.Word64
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f32) (mkUpperBound s f32)
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f64) (mkUpperBound s f64)
+
+groupWord :: H.Group
+groupWord = group "Word" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Word
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    fromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s t) (mkUpperBound s t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    fromTryFrom s t $ Gen.integral Range.linearBounded
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f32) (mkUpperBound s f32)
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    tryFromTryFrom s t . Gen.integral $ Range.linear (mkLowerBound s f64) (mkUpperBound s f64)
+
+groupNatural :: H.Group
+groupNatural = group "Natural" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy t maxBound)
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy t maxBound)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy t maxBound)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy t maxBound)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy t maxBound)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    fromTryFrom s t . Gen.integral $ Range.linear 0 9999999999999999999
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy t maxBound)
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy t maxBound)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    tryFromFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy t maxBound)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    tryFromFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy t maxBound)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    tryFromFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy t maxBound)
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy f32 maxBound)
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    tryFromTryFrom s t . Gen.integral $ Range.linear 0 (unsafeFromIntegral $ asProxy f64 maxBound)
+
+groupFloat :: H.Group
+groupFloat = group "Float" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Float
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f32 t) (mkUpperBound f32 t)
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    tryFromFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f32 t) (mkUpperBound f32 t)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f32 t) (mkUpperBound f32 t)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f32 t) (mkUpperBound f32 t)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f32 t) (mkUpperBound f32 t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ fmap unF32 Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f32 t) (mkUpperBound f32 t)
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f32 t) (mkUpperBound f32 t)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f32 t) (mkUpperBound f32 t)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f32 t) (mkUpperBound f32 t)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f32 t) (mkUpperBound f32 t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear 0 (unF32 maxBound)
+
+  property "Rational" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Rational
+    tryFromFrom s t . Gen.realFloat $ fmap (realToFrac . unF32) Range.linearBounded
+
+  property "Double" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Double
+    fromFrom s t . Gen.realFloat $ fmap (realToFrac . unF32) Range.linearBounded
+
+groupDouble :: H.Group
+groupDouble = group "Double" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Double
+
+  property "Int8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int8
+    tryFromFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f64 t) (mkUpperBound f64 t)
+
+  property "Int16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int16
+    tryFromFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f64 t) (mkUpperBound f64 t)
+
+  property "Int32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int32
+    tryFromFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f64 t) (mkUpperBound f64 t)
+
+  property "Int64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int.Int64
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f64 t) (mkUpperBound f64 t)
+
+  property "Int" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Int
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f64 t) (mkUpperBound f64 t)
+
+  property "Integer" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Integer
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ fmap unF64 Range.linearBounded
+
+  property "Word8" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    tryFromFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f64 t) (mkUpperBound f64 t)
+
+  property "Word16" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word16
+    tryFromFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f64 t) (mkUpperBound f64 t)
+
+  property "Word32" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word32
+    tryFromFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f64 t) (mkUpperBound f64 t)
+
+  property "Word64" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word.Word64
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f64 t) (mkUpperBound f64 t)
+
+  property "Word" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Word
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear (mkLowerBound f64 t) (mkUpperBound f64 t)
+
+  property "Natural" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Natural.Natural
+    tryFromTryFrom s t . fmap realToFrac . Gen.integral $ Range.linear 0 (unF64 maxBound)
+
+  property "Rational" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Rational
+    tryFromFrom s t . Gen.realFloat $ fmap (realToFrac . unF64) Range.linearBounded
+
+  property "Float" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Float
+    fromFrom s t . Gen.realFloat $ fmap (realToFrac . unF32) Range.linearBounded
+
+groupPico :: H.Group
+groupPico = group "Pico" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Fixed.Pico
+
+  property "Rational" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Rational
+    fromTryFrom s t genPico
+
+groupNonEmpty :: H.Group
+groupNonEmpty = group "NonEmpty" $ do
+  property "[Word8]" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy (NonEmpty.NonEmpty Word.Word8)
+    let t = Typeable.Proxy :: Typeable.Proxy [Word.Word8]
+    fromTryFrom s t . Gen.nonEmpty (Range.linear 1 10) $ Gen.integral Range.linearBounded
+
+groupSet :: H.Group
+groupSet = group "Set" $ do
+  property "[Word8]" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy (Set.Set Word.Word8)
+    let t = Typeable.Proxy :: Typeable.Proxy [Word.Word8]
+    fromFrom s t . Gen.set (Range.linear 0 10) $ Gen.integral Range.linearBounded
+
+groupIntSet :: H.Group
+groupIntSet = group "IntSet" $ do
+  property "[Int]" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy [Int]
+    let t = Typeable.Proxy :: Typeable.Proxy IntSet.IntSet
+    fromFrom s t . Gen.list (Range.linear 0 10) . Gen.integral $ Range.linear (-100) 100
+
+groupMap :: H.Group
+groupMap = group "Map" $ do
+  property "[(Word8, Word8)]" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy [(Word.Word8, Word.Word8)]
+    let t = Typeable.Proxy :: Typeable.Proxy (Map.Map Word.Word8 Word.Word8)
+    fromFrom s t . Gen.list (Range.linear 0 10) $ (,) <$> Gen.integral Range.linearBounded <*> Gen.integral Range.linearBounded
+
+groupIntMap :: H.Group
+groupIntMap = group "IntMap" $ do
+  property "[(Int, Word8)]" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy [(Int, Word.Word8)]
+    let t = Typeable.Proxy :: Typeable.Proxy (IntMap.IntMap Word.Word8)
+    fromFrom s t . Gen.list (Range.linear 0 10) $ (,) <$> Gen.integral (Range.linear (-100) 100) <*> Gen.integral Range.linearBounded
+
+groupSeq :: H.Group
+groupSeq = group "Seq" $ do
+  property "[Word8]" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy [Word.Word8]
+    let t = Typeable.Proxy :: Typeable.Proxy (Seq.Seq Word.Word8)
+    fromFrom s t . Gen.list (Range.linear 0 10) $ Gen.integral Range.linearBounded
+
+groupByteString :: H.Group
+groupByteString = group "ByteString" $ do
+  property "[Word8]" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy ByteString.ByteString
+    let t = Typeable.Proxy :: Typeable.Proxy [Word.Word8]
+    fromFrom s t genByteString
+
+  property "LazyByteString" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy ByteString.ByteString
+    let t = Typeable.Proxy :: Typeable.Proxy LazyByteString.ByteString
+    fromFrom s t genByteString
+
+  property "ShortByteString" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy ByteString.ByteString
+    let t = Typeable.Proxy :: Typeable.Proxy ShortByteString.ShortByteString
+    fromFrom s t genByteString
+
+groupLazyByteString :: H.Group
+groupLazyByteString = group "LazyByteString" $ do
+  property "[Word8]" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyByteString.ByteString
+    let t = Typeable.Proxy :: Typeable.Proxy [Word.Word8]
+    fromFrom s t genLazyByteString
+
+groupShortByteString :: H.Group
+groupShortByteString = group "ShortByteString" $ do
+  property "[Word8]" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy ShortByteString.ShortByteString
+    let t = Typeable.Proxy :: Typeable.Proxy [Word.Word8]
+    fromFrom s t genShortByteString
+
+groupOsString :: H.Group
+groupOsString = group "OsString" $ do
+  property "[OsChar]" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy OsString.OsString
+    let t = Typeable.Proxy :: Typeable.Proxy [OsString.OsChar]
+    fromFrom s t genOsString
+
+  property "OsChar/Word" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Word
+    let t = Typeable.Proxy :: Typeable.Proxy OsString.OsChar
+    -- @0@ to @0xFF@ fits an 'OsString.OsChar' on both POSIX and Windows.
+    tryFromFrom s t . Gen.integral $ Range.linear 0 0xFF
+
+groupText :: H.Group
+groupText = group "Text" $ do
+  property "LazyText" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    let t = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromFrom s t genText
+
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    let t = Typeable.Proxy :: Typeable.Proxy String
+    fromFrom s t genText
+
+groupLazyText :: H.Group
+groupLazyText = group "LazyText" $ do
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    let t = Typeable.Proxy :: Typeable.Proxy String
+    fromFrom s t genLazyText
+
+groupString :: H.Group
+groupString = group "String" $ do
+  -- String -> Text -> String and String -> LazyText -> String are already
+  -- covered by the Text and LazyText groups. This group is here for
+  -- completeness to show that no String-as-source tests are missing.
+  pure ()
+
+groupMonoid :: H.Group
+groupMonoid = group "Monoid" $ do
+  property "Dual" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    let t = Typeable.Proxy :: Typeable.Proxy (Monoid.Dual Word.Word8)
+    fromFrom s t $ Gen.integral Range.linearBounded
+
+  property "Sum" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    let t = Typeable.Proxy :: Typeable.Proxy (Monoid.Sum Word.Word8)
+    fromFrom s t $ Gen.integral Range.linearBounded
+
+  property "Product" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    let t = Typeable.Proxy :: Typeable.Proxy (Monoid.Product Word.Word8)
+    fromFrom s t $ Gen.integral Range.linearBounded
+
+  property "First" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy (Maybe Word.Word8)
+    let t = Typeable.Proxy :: Typeable.Proxy (Monoid.First Word.Word8)
+    fromFrom s t $ Gen.maybe (Gen.integral Range.linearBounded)
+
+  property "Last" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy (Maybe Word.Word8)
+    let t = Typeable.Proxy :: Typeable.Proxy (Monoid.Last Word.Word8)
+    fromFrom s t $ Gen.maybe (Gen.integral Range.linearBounded)
+
+  property "Alt" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy (Maybe Word.Word8)
+    let t = Typeable.Proxy :: Typeable.Proxy (Monoid.Alt Maybe Word.Word8)
+    fromFrom s t $ Gen.maybe (Gen.integral Range.linearBounded)
+
+  property "Ap" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy (Maybe Word.Word8)
+    let t = Typeable.Proxy :: Typeable.Proxy (Monoid.Ap Maybe Word.Word8)
+    fromFrom s t $ Gen.maybe (Gen.integral Range.linearBounded)
+
+-- Endo cannot be tested because functions are not `Eq` or `Show`.
+
+groupSemigroup :: H.Group
+groupSemigroup = group "Semigroup" $ do
+  property "Min" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    let t = Typeable.Proxy :: Typeable.Proxy (Semigroup.Min Word.Word8)
+    fromFrom s t $ Gen.integral Range.linearBounded
+
+  property "Max" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    let t = Typeable.Proxy :: Typeable.Proxy (Semigroup.Max Word.Word8)
+    fromFrom s t $ Gen.integral Range.linearBounded
+
+  property "First" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    let t = Typeable.Proxy :: Typeable.Proxy (Semigroup.First Word.Word8)
+    fromFrom s t $ Gen.integral Range.linearBounded
+
+  property "Last" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Word.Word8
+    let t = Typeable.Proxy :: Typeable.Proxy (Semigroup.Last Word.Word8)
+    fromFrom s t $ Gen.integral Range.linearBounded
+
+groupBool :: H.Group
+groupBool = group "Bool" $ do
+  property "All" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Bool
+    let t = Typeable.Proxy :: Typeable.Proxy Monoid.All
+    fromFrom s t Gen.bool
+
+  property "Any" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Bool
+    let t = Typeable.Proxy :: Typeable.Proxy Monoid.Any
+    fromFrom s t Gen.bool
+
+groupTime :: H.Group
+groupTime = group "Time" $ do
+  property "Day/Integer" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Integer
+    let t = Typeable.Proxy :: Typeable.Proxy Time.Day
+    fromFrom s t . Gen.integral $ Range.linear (-100000) 100000
+
+  property "UniversalTime/Rational" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Rational
+    let t = Typeable.Proxy :: Typeable.Proxy Time.UniversalTime
+    fromFrom s t genRational
+
+  property "DiffTime/Pico" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Fixed.Pico
+    let t = Typeable.Proxy :: Typeable.Proxy Time.DiffTime
+    fromFrom s t genPico
+
+  property "NominalDiffTime/Pico" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Fixed.Pico
+    let t = Typeable.Proxy :: Typeable.Proxy Time.NominalDiffTime
+    fromFrom s t genPico
+
+-- Day -> DayOfWeek cannot be tested because there is no reverse instance.
+-- DayOfWeek is a many-to-one mapping (7 days of the week).
+
+-- The following time conversions are one-directional and cannot be
+-- roundtrip tested: SystemTime -> UTCTime, SystemTime -> POSIXTime,
+-- SystemTime -> AbsoluteTime, UTCTime -> POSIXTime, POSIXTime -> UTCTime,
+-- UTCTime -> SystemTime, ZonedTime -> UTCTime,
+-- CalendarDiffDays -> CalendarDiffTime, NominalDiffTime -> CalendarDiffTime.
+
+groupLatin1S :: H.Group
+groupLatin1S = group "Latin1S" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Encoding.Latin1S
+
+  property "Text" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genLatin1S
+
+  property "LazyText" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLatin1S
+
+  property "String" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genLatin1S
+
+groupLatin1L :: H.Group
+groupLatin1L = group "Latin1L" $ do
+  let s = Typeable.Proxy :: Typeable.Proxy Encoding.Latin1L
+
+  property "Text" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genLatin1L
+
+  property "LazyText" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLatin1L
+
+  property "String" $ do
+    let t = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genLatin1L
+
+groupUtf8S :: H.Group
+groupUtf8S = group "Utf8S" $ do
+  let t = Typeable.Proxy :: Typeable.Proxy Encoding.Utf8S
+
+  property "Text" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genText
+
+  property "LazyText" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLazyText
+
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genString
+
+groupUtf8L :: H.Group
+groupUtf8L = group "Utf8L" $ do
+  let t = Typeable.Proxy :: Typeable.Proxy Encoding.Utf8L
+
+  property "Text" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genText
+
+  property "LazyText" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLazyText
+
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genString
+
+groupUtf16LS :: H.Group
+groupUtf16LS = group "Utf16LS" $ do
+  let t = Typeable.Proxy :: Typeable.Proxy Encoding.Utf16LS
+
+  property "Text" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genText
+
+  property "LazyText" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLazyText
+
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genString
+
+groupUtf16LL :: H.Group
+groupUtf16LL = group "Utf16LL" $ do
+  let t = Typeable.Proxy :: Typeable.Proxy Encoding.Utf16LL
+
+  property "Text" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genText
+
+  property "LazyText" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLazyText
+
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genString
+
+groupUtf16BS :: H.Group
+groupUtf16BS = group "Utf16BS" $ do
+  let t = Typeable.Proxy :: Typeable.Proxy Encoding.Utf16BS
+
+  property "Text" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genText
+
+  property "LazyText" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLazyText
+
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genString
+
+groupUtf16BL :: H.Group
+groupUtf16BL = group "Utf16BL" $ do
+  let t = Typeable.Proxy :: Typeable.Proxy Encoding.Utf16BL
+
+  property "Text" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genText
+
+  property "LazyText" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLazyText
+
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genString
+
+groupUtf32LS :: H.Group
+groupUtf32LS = group "Utf32LS" $ do
+  let t = Typeable.Proxy :: Typeable.Proxy Encoding.Utf32LS
+
+  property "Text" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genText
+
+  property "LazyText" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLazyText
+
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genString
+
+groupUtf32LL :: H.Group
+groupUtf32LL = group "Utf32LL" $ do
+  let t = Typeable.Proxy :: Typeable.Proxy Encoding.Utf32LL
+
+  property "Text" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genText
+
+  property "LazyText" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLazyText
+
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genString
+
+groupUtf32BS :: H.Group
+groupUtf32BS = group "Utf32BS" $ do
+  let t = Typeable.Proxy :: Typeable.Proxy Encoding.Utf32BS
+
+  property "Text" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genText
+
+  property "LazyText" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLazyText
+
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genString
+
+groupUtf32BL :: H.Group
+groupUtf32BL = group "Utf32BL" $ do
+  let t = Typeable.Proxy :: Typeable.Proxy Encoding.Utf32BL
+
+  property "Text" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy Text.Text
+    fromTryFrom s t genText
+
+  property "LazyText" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy LazyText.Text
+    fromTryFrom s t genLazyText
+
+  property "String" $ do
+    let s = Typeable.Proxy :: Typeable.Proxy String
+    fromTryFrom s t genString
+
+genByteString :: H.Gen ByteString.ByteString
+genByteString =
+  fmap ByteString.pack . Gen.list (Range.linear 0 20) $ Gen.integral Range.linearBounded
+
+genLazyByteString :: H.Gen LazyByteString.ByteString
+genLazyByteString =
+  fmap LazyByteString.pack . Gen.list (Range.linear 0 20) $ Gen.integral Range.linearBounded
+
+genShortByteString :: H.Gen ShortByteString.ShortByteString
+genShortByteString =
+  fmap ShortByteString.pack . Gen.list (Range.linear 0 20) $ Gen.integral Range.linearBounded
+
+genOsString :: H.Gen OsString.OsString
+genOsString =
+  fmap OsString.pack . Gen.list (Range.linear 0 20) $ fmap OsString.unsafeFromChar Gen.ascii
+
+genText :: H.Gen Text.Text
+genText = Text.pack <$> Gen.string (Range.linear 0 20) Gen.unicode
+
+genLazyText :: H.Gen LazyText.Text
+genLazyText = LazyText.pack <$> Gen.string (Range.linear 0 20) Gen.unicode
+
+genString :: H.Gen String
+genString = Gen.string (Range.linear 0 20) Gen.unicode
+
+genLatin1S :: H.Gen Encoding.Latin1S
+genLatin1S = fmap Tagged.Tagged genByteString
+
+genLatin1L :: H.Gen Encoding.Latin1L
+genLatin1L = fmap Tagged.Tagged genLazyByteString
+
+genPico :: H.Gen Fixed.Pico
+genPico = fmap (fromInteger :: Integer -> Fixed.Pico) . Gen.integral $ Range.linear (-1000000000000) 1000000000000
+
+genRational :: H.Gen Rational
+genRational = do
+  n <- Gen.integral $ Range.linear (-1000000 :: Integer) 1000000
+  d <- Gen.integral $ Range.linear (1 :: Integer) 1000
+  pure $ n Ratio.% d
+
+newtype F32 = MkF32
+  { unF32 :: Int.Int32
+  }
+  deriving (Eq, Ord, Show)
+  deriving (Bits.Bits, Enum, Integral, Num, Real) via Int.Int32
+
+instance Bounded F32 where
+  minBound = MkF32 (-16777215)
+  maxBound = MkF32 16777215
+
+f32 :: Typeable.Proxy F32
+f32 = Typeable.Proxy
+
+newtype F64 = MkF64
+  { unF64 :: Int.Int64
+  }
+  deriving (Eq, Ord, Show)
+  deriving (Bits.Bits, Enum, Integral, Num, Real) via Int.Int64
+
+instance Bounded F64 where
+  minBound = MkF64 (-9007199254740991)
+  maxBound = MkF64 9007199254740991
+
+f64 :: Typeable.Proxy F64
+f64 = Typeable.Proxy
+
+mkLowerBound ::
+  ( Stack.HasCallStack,
+    Bits.Bits a,
+    Bounded a,
+    Bounded b,
+    Integral a,
+    Integral b
+  ) =>
+  proxy a ->
+  proxy b ->
+  a
+mkLowerBound a b =
+  unsafeFromIntegral $
+    max
+      (toInteger $ asProxy a minBound)
+      (toInteger $ asProxy b minBound)
+
+mkUpperBound ::
+  ( Stack.HasCallStack,
+    Bits.Bits a,
+    Bounded a,
+    Bounded b,
+    Integral a,
+    Integral b
+  ) =>
+  proxy a ->
+  proxy b ->
+  a
+mkUpperBound a b =
+  unsafeFromIntegral $
+    min
+      (toInteger $ asProxy a maxBound)
+      (toInteger $ asProxy b maxBound)
+
+asProxy :: proxy a -> a -> a
+asProxy = const id
+
+unsafeFromIntegral ::
+  (Stack.HasCallStack, Bits.Bits a, Bits.Bits b, Integral a, Integral b) =>
+  a ->
+  b
+unsafeFromIntegral = Maybe.fromJust . Bits.toIntegralSized
+
+group ::
+  String ->
+  Writer.Writer [(H.PropertyName, H.Property)] () ->
+  H.Group
+group n = H.Group (String.fromString n) . Writer.execWriter
+
+property ::
+  (Monad m) =>
+  String ->
+  H.PropertyT IO () ->
+  Writer.WriterT [(H.PropertyName, H.Property)] m ()
+property n = Writer.tell . pure . (,) (String.fromString n) . H.property
+
+fromFrom ::
+  ( Eq source,
+    Eq target,
+    Witch.From source target,
+    Witch.From target source,
+    Monad m,
+    Show source,
+    Show target
+  ) =>
+  proxy source ->
+  proxy target ->
+  H.Gen source ->
+  H.PropertyT m ()
+fromFrom s t =
+  tripping
+    (right . Witch.from . asProxy s)
+    (right . Witch.from . asProxy t)
+
+fromTryFrom ::
+  ( Eq source,
+    Eq target,
+    Witch.From source target,
+    Monad m,
+    Show source,
+    Show target,
+    Witch.TryFrom target source,
+    Typeable.Typeable source,
+    Typeable.Typeable target
+  ) =>
+  proxy source ->
+  proxy target ->
+  H.Gen source ->
+  H.PropertyT m ()
+fromTryFrom s t =
+  tripping
+    (right . Witch.from . asProxy s)
+    (Witch.tryFrom . asProxy t)
+
+tryFromFrom ::
+  ( Eq source,
+    Eq target,
+    Witch.TryFrom source target,
+    Witch.From target source,
+    Monad m,
+    Show source,
+    Show target,
+    Typeable.Typeable source,
+    Typeable.Typeable target
+  ) =>
+  proxy source ->
+  proxy target ->
+  H.Gen source ->
+  H.PropertyT m ()
+tryFromFrom s t =
+  tripping
+    (Witch.tryFrom . asProxy s)
+    (right . Witch.from . asProxy t)
+
+tryFromTryFrom ::
+  ( Eq source,
+    Eq target,
+    Witch.TryFrom source target,
+    Witch.TryFrom target source,
+    Monad m,
+    Show source,
+    Show target,
+    Typeable.Typeable source,
+    Typeable.Typeable target
+  ) =>
+  proxy source ->
+  proxy target ->
+  H.Gen source ->
+  H.PropertyT m ()
+tryFromTryFrom s t =
+  tripping
+    (Witch.tryFrom . asProxy s)
+    (Witch.tryFrom . asProxy t)
+
+tripping ::
+  (Eq source, Eq target, Monad m, Show source, Show target, Show e1, Show e2) =>
+  (source -> Either e1 target) ->
+  (target -> Either e2 source) ->
+  H.Gen source ->
+  H.PropertyT m ()
+tripping into from gen = do
+  s1 <- H.forAll gen
+  case into s1 of
+    Left _ ->
+      -- If we can't convert the source into the target, then there's nothing
+      -- to test. But we don't want to fail the property with 'H.evalEither'.
+      H.discard
+    Right t1 -> do
+      s2 <- H.evalEither $ from t1
+      -- Note that @s2@ is not equal to @s1@ in general because the target type
+      -- may lose information. For example if the source is a list and the
+      -- target is a set, then @s2@ will be sorted and have no duplicates.
+
+      t2 <- H.evalEither $ into s2
+      -- The target should be the same after round-tripping through the source.
+      t2 H.=== t1
+
+      s3 <- H.evalEither $ from t2
+      -- After the source has been through the target once, round-tripping
+      -- through the target /again/ shouldn't change it.
+      s3 H.=== s2
+
+right :: a -> Either Void.Void a
+right = Right
diff --git a/source/library/Witch.hs b/source/library/Witch.hs
--- a/source/library/Witch.hs
+++ b/source/library/Witch.hs
@@ -26,16 +26,45 @@
     Witch.TryFromException.TryFromException (..),
 
     -- ** Encodings
+
+    -- | Witch supports decoding text and encoding byte strings using various
+    -- character encodings. For example to convert from a 'String' into a
+    -- strict 'Data.ByteString.ByteString', you can use the
+    -- 'Witch.Encoding.Utf8S' alias:
+    --
+    -- @
+    -- 'Witch.Utility.into' \@'Data.ByteString.ByteString' ('Witch.Utility.into' \@'Witch.Encoding.Utf8S' ("..." :: 'String'))
+    -- -- "..."
+    -- @
+    --
+    -- And to convert from a strict 'Data.ByteString.ByteString' into a
+    -- 'String', you can use the 'Witch.Encoding.Utf8S' alias in the other
+    -- direction:
+    --
+    -- @
+    -- 'Witch.Utility.tryInto' \@'String' ('Witch.Utility.into' \@'Witch.Encoding.Utf8S' ("..." :: 'Data.ByteString.ByteString'))
+    -- -- Right "..."
+    -- @
+    Witch.Encoding.Latin1S,
+    Witch.Encoding.Latin1L,
     Witch.Encoding.ISO_8859_1,
+    Witch.Encoding.Utf8S,
+    Witch.Encoding.Utf8L,
     Witch.Encoding.UTF_8,
+    Witch.Encoding.Utf16LS,
+    Witch.Encoding.Utf16LL,
     Witch.Encoding.UTF_16LE,
+    Witch.Encoding.Utf16BS,
+    Witch.Encoding.Utf16BL,
     Witch.Encoding.UTF_16BE,
+    Witch.Encoding.Utf32LS,
+    Witch.Encoding.Utf32LL,
     Witch.Encoding.UTF_32LE,
+    Witch.Encoding.Utf32BS,
+    Witch.Encoding.Utf32BL,
     Witch.Encoding.UTF_32BE,
 
     -- * Utilities
-    Witch.Utility.as,
-    Witch.Utility.over,
     Witch.Utility.via,
     Witch.Utility.tryVia,
     Witch.Utility.maybeTryFrom,
@@ -83,7 +112,7 @@
 
     -- ** Type applications
 
-    -- | Although you can use this library without the [@TypeApplications@](https://downloads.haskell.org/~ghc/9.0.1/docs/html/users_guide/exts/type_applications.html)
+    -- | Although you can use this library without the [@TypeApplications@](https://downloads.haskell.org/ghc/9.6.1/docs/users_guide/exts/type_applications.html)
     -- language extension, the extension is strongly recommended. Since most
     -- functions provided by this library are polymorphic in at least one type
     -- variable, it's easy to use them in a situation that would be ambiguous.
@@ -273,6 +302,7 @@
 
 import qualified Witch.Encoding
 import qualified Witch.From
+import Witch.Generic ()
 import Witch.Instances ()
 import qualified Witch.Lift
 import qualified Witch.TryFrom
diff --git a/source/library/Witch/Encoding.hs b/source/library/Witch/Encoding.hs
--- a/source/library/Witch/Encoding.hs
+++ b/source/library/Witch/Encoding.hs
@@ -2,22 +2,60 @@
 
 module Witch.Encoding where
 
+import qualified Data.ByteString as ByteString
+import qualified Data.ByteString.Lazy as LazyByteString
 import qualified Data.Tagged as Tagged
 
 -- | <https://en.wikipedia.org/wiki/ISO/IEC_8859-1>
 type ISO_8859_1 = Tagged.Tagged "ISO-8859-1"
 
+-- | The 'ISO_8859_1' encoding for strict 'ByteString.ByteString's.
+type Latin1S = ISO_8859_1 ByteString.ByteString
+
+-- | The 'ISO_8859_1' encoding for lazy 'LazyByteString.ByteString's.
+type Latin1L = ISO_8859_1 LazyByteString.ByteString
+
 -- | <https://en.wikipedia.org/wiki/UTF-8>
 type UTF_8 = Tagged.Tagged "UTF-8"
 
+-- | The 'UTF_8' encoding for strict 'ByteString.ByteString's.
+type Utf8S = UTF_8 ByteString.ByteString
+
+-- | The 'UTF_8' encoding for lazy 'LazyByteString.ByteString's.
+type Utf8L = UTF_8 LazyByteString.ByteString
+
 -- | <https://en.wikipedia.org/wiki/UTF-16>
 type UTF_16LE = Tagged.Tagged "UTF-16LE"
 
+-- | The 'UTF_16LE' encoding for strict 'ByteString.ByteString's.
+type Utf16LS = UTF_16LE ByteString.ByteString
+
+-- | The 'UTF_16LE' encoding for lazy 'LazyByteString.ByteString's.
+type Utf16LL = UTF_16LE LazyByteString.ByteString
+
 -- | <https://en.wikipedia.org/wiki/UTF-16>
 type UTF_16BE = Tagged.Tagged "UTF-16BE"
 
+-- | The 'UTF_16BE' encoding for strict 'ByteString.ByteString's.
+type Utf16BS = UTF_16BE ByteString.ByteString
+
+-- | The 'UTF_16BE' encoding for lazy 'LazyByteString.ByteString's.
+type Utf16BL = UTF_16BE LazyByteString.ByteString
+
 -- | <https://en.wikipedia.org/wiki/UTF-32>
 type UTF_32LE = Tagged.Tagged "UTF-32LE"
 
+-- | The 'UTF_32LE' encoding for strict 'ByteString.ByteString's.
+type Utf32LS = UTF_32LE ByteString.ByteString
+
+-- | The 'UTF_32LE' encoding for lazy 'LazyByteString.ByteString's.
+type Utf32LL = UTF_32LE LazyByteString.ByteString
+
 -- | <https://en.wikipedia.org/wiki/UTF-32>
 type UTF_32BE = Tagged.Tagged "UTF-32BE"
+
+-- | The 'UTF_32BE' encoding for strict 'ByteString.ByteString's.
+type Utf32BS = UTF_32BE ByteString.ByteString
+
+-- | The 'UTF_32BE' encoding for lazy 'LazyByteString.ByteString's.
+type Utf32BL = UTF_32BE LazyByteString.ByteString
diff --git a/source/library/Witch/From.hs b/source/library/Witch/From.hs
--- a/source/library/Witch/From.hs
+++ b/source/library/Witch/From.hs
@@ -19,7 +19,7 @@
   -- > -- Avoid this:
   -- > from (x :: s)
   -- >
-  -- > -- Prefer this (using [@TypeApplications@](https://downloads.haskell.org/~ghc/9.0.1/docs/html/users_guide/exts/type_applications.html) language extension):
+  -- > -- Prefer this (using [@TypeApplications@](https://downloads.haskell.org/ghc/9.6.1/docs/users_guide/exts/type_applications.html) language extension):
   -- > from @s x
   --
   -- The default implementation of this method simply calls 'Coerce.coerce',
diff --git a/source/library/Witch/Generic.hs b/source/library/Witch/Generic.hs
new file mode 100644
--- /dev/null
+++ b/source/library/Witch/Generic.hs
@@ -0,0 +1,82 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
+module Witch.Generic where
+
+import qualified GHC.Generics as Generics
+import qualified Witch.From as From
+
+-- | This type class is used to implement generic conversions using the 'Generics.Generically' helper.
+-- This is an advanced use case.
+-- Most users will not need to know about this type class.
+-- And even for those that want to derive 'Generics.Generically', this type class should be an implementation detail.
+--
+-- This type class can convert between any two types as long as they have 'Generics.Generic' instances and they are structurally similar.
+-- For example, if you define your own empty type you could convert it to the typical 'Data.Void.Void' type:
+--
+-- > data Empty deriving Generic
+-- > deriving via Generically Void instance From Empty Void
+--
+-- Or your own unit type:
+--
+-- > data Unit = MkUnit deriving Generic
+-- > deriving via Generically () instance From Unit ()
+--
+-- Note that this looks superficially similar to @newtype Unit = MkUnit ()@ together with @instance From Unit ()@, but that goes through 'Data.Coerce.Coercible' and requires the types to be representationally equal.
+-- This approach (with 'Generics.Generically') only requires the types to be /structurally/ equal.
+-- In this case, @Unit@ is structurally equal to @()@ since they both have a single constructor with no arguments.
+--
+-- This also works with arbitrary product types, like a custom pair type:
+--
+-- > data Pair a b = MkPair a b deriving Generic
+-- > deriving via Generically (Pair c d)
+-- >   instance (From a c, From b d) => From (a, b) (Pair c d)
+--
+-- Note that this can also convert the type variables as long as they have 'From.From' instances as well.
+-- This allows converting from @(Int, Int)@ to @Pair Integer Integer@ in one step, for example.
+--
+-- And this works with arbitrary sum types as well:
+--
+-- > data Result a b = Failure a | Success b deriving Generic
+-- > deriving via Generically (Result c d)
+-- >   instance (From a c, From b d) => From (Either a b) (Result c d)
+--
+-- Note that these conversions are all /structural/ not semantic.
+-- That means if you had defined @Result@ as @Success b | Failure a@, then converting from 'Either' would be "wrong".
+-- 'Left' would convert into @Success@ and 'Right' would convert into @Failure@.
+class GFrom s t where
+  gFrom :: s x -> t x
+
+instance GFrom Generics.V1 Generics.V1 where
+  gFrom = id
+
+instance GFrom Generics.U1 Generics.U1 where
+  gFrom = id
+
+instance (From.From s t) => GFrom (Generics.K1 a s) (Generics.K1 b t) where
+  gFrom = Generics.K1 . From.from . Generics.unK1
+
+instance (GFrom s t) => GFrom (Generics.M1 a b s) (Generics.M1 c d t) where
+  gFrom = Generics.M1 . gFrom . Generics.unM1
+
+instance (GFrom s1 t1, GFrom s2 t2) => GFrom (s1 Generics.:+: s2) (t1 Generics.:+: t2) where
+  gFrom x = case x of
+    Generics.L1 l -> Generics.L1 $ gFrom l
+    Generics.R1 r -> Generics.R1 $ gFrom r
+
+instance (GFrom s1 t1, GFrom s2 t2) => GFrom (s1 Generics.:*: s2) (t1 Generics.:*: t2) where
+  gFrom (l Generics.:*: r) = gFrom l Generics.:*: gFrom r
+
+-- | See the 'GFrom' type class for an explanation of this instance.
+instance
+  ( Generics.Generic s,
+    Generics.Generic t,
+    GFrom (Generics.Rep s) (Generics.Rep t)
+  ) =>
+  From.From s (Generics.Generically t)
+  where
+  from = Generics.Generically . Generics.to . gFrom . Generics.from
diff --git a/source/library/Witch/Instances.hs b/source/library/Witch/Instances.hs
--- a/source/library/Witch/Instances.hs
+++ b/source/library/Witch/Instances.hs
@@ -9,6 +9,7 @@
 
 import qualified Control.Exception as Exception
 import qualified Control.Monad as Monad
+import qualified Data.Bifunctor as Bifunctor
 import qualified Data.Bits as Bits
 import qualified Data.ByteString as ByteString
 import qualified Data.ByteString.Char8 as Char8
@@ -25,7 +26,9 @@
 import qualified Data.List as List
 import qualified Data.List.NonEmpty as NonEmpty
 import qualified Data.Map as Map
+import qualified Data.Monoid as Monoid
 import qualified Data.Ratio as Ratio
+import qualified Data.Semigroup as Semigroup
 import qualified Data.Sequence as Seq
 import qualified Data.Set as Set
 import qualified Data.Tagged as Tagged
@@ -43,6 +46,7 @@
 import qualified Numeric
 import qualified Numeric.Natural as Natural
 import qualified System.IO.Unsafe as Unsafe
+import qualified System.OsString as OsString
 import qualified Witch.Encoding as Encoding
 import qualified Witch.From as From
 import qualified Witch.TryFrom as TryFrom
@@ -266,11 +270,7 @@
 
 -- | Uses 'fromIntegral' when the input is not negative.
 instance TryFrom.TryFrom Int.Int64 Natural.Natural where
-  -- This should use @eitherTryFrom fromNonNegativeIntegral@, but that causes
-  -- a bug in GHC 9.0.1.
-  -- https://mail.haskell.org/pipermail/haskell-cafe/2021-March/133540.html
-  tryFrom =
-    Utility.eitherTryFrom $ \s -> TryFrom.tryFrom (From.from s :: Integer)
+  tryFrom = Utility.eitherTryFrom fromNonNegativeIntegral
 
 -- | Uses 'fromIntegral' when the input is between -16,777,215 and 16,777,215
 -- inclusive.
@@ -409,12 +409,7 @@
 
 -- | Uses 'fromInteger' when the input is not negative.
 instance TryFrom.TryFrom Integer Natural.Natural where
-  -- This should use @eitherTryFrom fromNonNegativeIntegral@, but that causes
-  -- a bug in GHC 9.0.1. By inlining @fromNonNegativeIntegral@ and replacing
-  -- @fromIntegral@ with @fromInteger@, we can work around the bug.
-  -- https://mail.haskell.org/pipermail/haskell-cafe/2021-March/133540.html
-  tryFrom = Utility.eitherTryFrom $
-    \s -> if s < 0 then Left Exception.Underflow else Right $ fromInteger s
+  tryFrom = Utility.eitherTryFrom fromNonNegativeIntegral
 
 -- | Uses 'fromIntegral' when the input is between -16,777,215 and 16,777,215
 -- inclusive.
@@ -621,9 +616,7 @@
 
 -- | Uses 'fromIntegral'.
 instance From.From Word.Word64 Natural.Natural where
-  -- This should use @fromIntegral@, but that causes a bug in GHC 9.0.1.
-  -- https://mail.haskell.org/pipermail/haskell-cafe/2021-March/133540.html
-  from s = Utility.unsafeFrom (From.from s :: Integer)
+  from = fromIntegral
 
 -- | Uses 'Bits.toIntegralSized'.
 instance TryFrom.TryFrom Word.Word64 Int.Int8 where
@@ -938,20 +931,31 @@
 
 -- Fixed
 
--- | Uses 'Fixed.MkFixed'. This means @from \@Integer \@Centi 2@ is @0.02@
--- rather than @2.00@.
-instance From.From Integer (Fixed.Fixed a) where
-  from = Fixed.MkFixed
+-- | Uses 'fromInteger'. This means @from \@Integer \@Centi 2@ is @02.00@
+-- rather than @0.02@.
+instance (Fixed.HasResolution a) => From.From Integer (Fixed.Fixed a) where
+  from = fromInteger
 
--- | Uses 'Fixed.MkFixed'. This means @from \@Centi \@Integer 3.00@ is @300@
--- rather than @3@.
-instance From.From (Fixed.Fixed a) Integer where
-  from (Fixed.MkFixed t) = t
+-- | Converts via 'Rational' when there is no fractional part. This means
+-- @tryFrom \@Centi \@Integer 2.00@ is @Right 2@ and
+-- @tryFrom \@Centi \@Integer 0.02@ will fail.
+instance (Fixed.HasResolution a) => TryFrom.TryFrom (Fixed.Fixed a) Integer where
+  tryFrom = Utility.eitherTryFrom $ TryFrom.tryFrom @Rational . From.from
 
 -- | Uses 'toRational'.
 instance (Fixed.HasResolution a) => From.From (Fixed.Fixed a) Rational where
   from = toRational
 
+-- | Converts via 'Rational'.
+instance
+  (Fixed.HasResolution s, Fixed.HasResolution t) =>
+  TryFrom.TryFrom (Fixed.Fixed s) (Fixed.Fixed t)
+  where
+  tryFrom s =
+    Bifunctor.first (Utility.withSource s)
+      . TryFrom.tryFrom @Rational
+      $ From.from s
+
 -- Complex
 
 -- | Uses '(Complex.:+)' with an imaginary part of 0.
@@ -965,6 +969,94 @@
       then Right $ Complex.realPart s
       else Left Exception.LossOfPrecision
 
+-- Data.Monoid newtypes
+
+-- | Uses @'coerce'@.
+instance From.From a (Monoid.Dual a)
+
+-- | Uses @'coerce'@.
+instance From.From (Monoid.Dual a) a
+
+-- | Uses @'coerce'@.
+instance From.From (a -> a) (Monoid.Endo a)
+
+-- | Uses @'coerce'@.
+instance From.From (Monoid.Endo a) (a -> a)
+
+-- | Uses @'coerce'@.
+instance From.From Bool Monoid.All
+
+-- | Uses @'coerce'@.
+instance From.From Monoid.All Bool
+
+-- | Uses @'coerce'@.
+instance From.From Bool Monoid.Any
+
+-- | Uses @'coerce'@.
+instance From.From Monoid.Any Bool
+
+-- | Uses @'coerce'@.
+instance From.From a (Monoid.Sum a)
+
+-- | Uses @'coerce'@.
+instance From.From (Monoid.Sum a) a
+
+-- | Uses @'coerce'@.
+instance From.From a (Monoid.Product a)
+
+-- | Uses @'coerce'@.
+instance From.From (Monoid.Product a) a
+
+-- | Uses @'coerce'@.
+instance From.From (Maybe a) (Monoid.First a)
+
+-- | Uses @'coerce'@.
+instance From.From (Monoid.First a) (Maybe a)
+
+-- | Uses @'coerce'@.
+instance From.From (Maybe a) (Monoid.Last a)
+
+-- | Uses @'coerce'@.
+instance From.From (Monoid.Last a) (Maybe a)
+
+-- | Uses @'coerce'@.
+instance From.From (f a) (Monoid.Alt f a)
+
+-- | Uses @'coerce'@.
+instance From.From (Monoid.Alt f a) (f a)
+
+-- | Uses @'coerce'@.
+instance From.From (f a) (Monoid.Ap f a)
+
+-- | Uses @'coerce'@.
+instance From.From (Monoid.Ap f a) (f a)
+
+-- Data.Semigroup newtypes
+
+-- | Uses @'coerce'@.
+instance From.From a (Semigroup.Min a)
+
+-- | Uses @'coerce'@.
+instance From.From (Semigroup.Min a) a
+
+-- | Uses @'coerce'@.
+instance From.From a (Semigroup.Max a)
+
+-- | Uses @'coerce'@.
+instance From.From (Semigroup.Max a) a
+
+-- | Uses @'coerce'@.
+instance From.From a (Semigroup.First a)
+
+-- | Uses @'coerce'@.
+instance From.From (Semigroup.First a) a
+
+-- | Uses @'coerce'@.
+instance From.From a (Semigroup.Last a)
+
+-- | Uses @'coerce'@.
+instance From.From (Semigroup.Last a) a
+
 -- NonEmpty
 
 -- | Uses 'NonEmpty.nonEmpty'.
@@ -1073,6 +1165,70 @@
 instance From.From ShortByteString.ShortByteString ByteString.ByteString where
   from = ShortByteString.fromShort
 
+-- OsString
+
+-- | Uses 'OsString.pack'.
+instance From.From [OsString.OsChar] OsString.OsString where
+  from = OsString.pack
+
+-- | Uses 'OsString.unpack'.
+instance From.From OsString.OsString [OsString.OsChar] where
+  from = OsString.unpack
+
+-- | Uses 'OsString.toChar'. Total because an 'OsString.OsChar' is a single code
+-- unit, which always fits in a 'Word'.
+instance From.From OsString.OsChar Word where
+  from = fromIntegral . Char.ord . OsString.toChar
+
+-- | Builds an 'OsString.OsChar' code unit from a 'Word'. Fails when the 'Word'
+-- does not fit in an 'OsString.OsChar', which holds one byte on POSIX (values
+-- above @0xFF@) and two bytes on Windows (values above @0xFFFF@). Guarded by a
+-- round trip, so it never silently truncates.
+instance TryFrom.TryFrom Word OsString.OsChar where
+  tryFrom =
+    Utility.maybeTryFrom $ \w ->
+      if w > 0x10FFFF
+        then Nothing
+        else
+          let oc = OsString.unsafeFromChar (Char.chr (fromIntegral w))
+           in if fromIntegral (Char.ord (OsString.toChar oc)) == w
+                then Just oc
+                else Nothing
+
+-- | Uses 'OsString.encodeUtf'.
+instance TryFrom.TryFrom String OsString.OsString where
+  tryFrom =
+    Utility.eitherTryFrom $ \s ->
+      OsString.encodeUtf s :: Either Exception.SomeException OsString.OsString
+
+-- | Uses 'OsString.decodeUtf'.
+instance TryFrom.TryFrom OsString.OsString String where
+  tryFrom =
+    Utility.eitherTryFrom $ \os ->
+      OsString.decodeUtf os :: Either Exception.SomeException String
+
+-- | Uses 'OsString.unsafeEncodeUtf'. Total because 'Text.Text' cannot contain
+-- lone surrogates, so the underlying encode never fails.
+instance From.From Text.Text OsString.OsString where
+  from = OsString.unsafeEncodeUtf . Text.unpack
+
+-- | Converts via 'String' using 'OsString.decodeUtf'.
+instance TryFrom.TryFrom OsString.OsString Text.Text where
+  tryFrom =
+    Utility.eitherTryFrom $ \os ->
+      fmap Text.pack (OsString.decodeUtf os :: Either Exception.SomeException String)
+
+-- | Uses 'OsString.unsafeEncodeUtf'. Total because 'LazyText.Text' cannot
+-- contain lone surrogates, so the underlying encode never fails.
+instance From.From LazyText.Text OsString.OsString where
+  from = OsString.unsafeEncodeUtf . LazyText.unpack
+
+-- | Converts via 'String' using 'OsString.decodeUtf'.
+instance TryFrom.TryFrom OsString.OsString LazyText.Text where
+  tryFrom =
+    Utility.eitherTryFrom $ \os ->
+      fmap LazyText.pack (OsString.decodeUtf os :: Either Exception.SomeException String)
+
 -- Text
 
 -- | Uses 'LazyText.fromStrict'.
@@ -1235,53 +1391,53 @@
 -- ISO-8859-1
 
 -- | Uses 'Text.decodeLatin1'.
-instance From.From (Encoding.ISO_8859_1 ByteString.ByteString) Text.Text where
+instance From.From Encoding.Latin1S Text.Text where
   from = Text.decodeLatin1 . From.from
 
 -- | Converts via 'Text.Text'.
-instance From.From (Encoding.ISO_8859_1 ByteString.ByteString) LazyText.Text where
+instance From.From Encoding.Latin1S LazyText.Text where
   from = Utility.via @Text.Text
 
 -- | Converts via 'Text.Text'.
-instance From.From (Encoding.ISO_8859_1 ByteString.ByteString) String where
+instance From.From Encoding.Latin1S String where
   from = Utility.via @Text.Text
 
 -- | Uses 'LazyText.decodeLatin1'.
-instance From.From (Encoding.ISO_8859_1 LazyByteString.ByteString) LazyText.Text where
+instance From.From Encoding.Latin1L LazyText.Text where
   from = LazyText.decodeLatin1 . From.from
 
 -- | Converts via 'LazyText.Text'.
-instance From.From (Encoding.ISO_8859_1 LazyByteString.ByteString) Text.Text where
+instance From.From Encoding.Latin1L Text.Text where
   from = Utility.via @LazyText.Text
 
 -- | Converts via 'LazyText.Text'.
-instance From.From (Encoding.ISO_8859_1 LazyByteString.ByteString) String where
+instance From.From Encoding.Latin1L String where
   from = Utility.via @LazyText.Text
 
 -- | Converts via 'String'.
-instance TryFrom.TryFrom Text.Text (Encoding.ISO_8859_1 ByteString.ByteString) where
+instance TryFrom.TryFrom Text.Text Encoding.Latin1S where
   tryFrom = Utility.eitherTryFrom $ TryFrom.tryFrom . Utility.into @String
 
 -- | Converts via 'String'.
-instance TryFrom.TryFrom Text.Text (Encoding.ISO_8859_1 LazyByteString.ByteString) where
+instance TryFrom.TryFrom Text.Text Encoding.Latin1L where
   tryFrom = Utility.eitherTryFrom $ TryFrom.tryFrom . Utility.into @String
 
 -- | Converts via 'String'.
-instance TryFrom.TryFrom LazyText.Text (Encoding.ISO_8859_1 LazyByteString.ByteString) where
+instance TryFrom.TryFrom LazyText.Text Encoding.Latin1L where
   tryFrom = Utility.eitherTryFrom $ TryFrom.tryFrom . Utility.into @String
 
 -- | Converts via 'String'.
-instance TryFrom.TryFrom LazyText.Text (Encoding.ISO_8859_1 ByteString.ByteString) where
+instance TryFrom.TryFrom LazyText.Text Encoding.Latin1S where
   tryFrom = Utility.eitherTryFrom $ TryFrom.tryFrom . Utility.into @String
 
 -- | Uses 'Char8.pack' when each character 'Char.isLatin1'.
-instance TryFrom.TryFrom String (Encoding.ISO_8859_1 ByteString.ByteString) where
+instance TryFrom.TryFrom String Encoding.Latin1S where
   tryFrom = Utility.maybeTryFrom $ \string -> do
     Monad.guard $ all Char.isLatin1 string
     pure . From.from $ Char8.pack string
 
 -- | Uses 'LazyChar8.pack' when each character 'Char.isLatin1'.
-instance TryFrom.TryFrom String (Encoding.ISO_8859_1 LazyByteString.ByteString) where
+instance TryFrom.TryFrom String Encoding.Latin1L where
   tryFrom = Utility.maybeTryFrom $ \string -> do
     Monad.guard $ all Char.isLatin1 string
     pure . From.from $ LazyChar8.pack string
@@ -1289,251 +1445,251 @@
 -- UTF-8
 
 -- | Uses 'Text.decodeUtf8''.
-instance TryFrom.TryFrom (Encoding.UTF_8 ByteString.ByteString) Text.Text where
+instance TryFrom.TryFrom Encoding.Utf8S Text.Text where
   tryFrom = Utility.eitherTryFrom $ Text.decodeUtf8' . From.from
 
 -- | Converts via 'Text.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_8 ByteString.ByteString) LazyText.Text where
+instance TryFrom.TryFrom Encoding.Utf8S LazyText.Text where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @LazyText.Text) . Utility.tryInto @Text.Text
 
 -- | Converts via 'Text.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_8 ByteString.ByteString) String where
+instance TryFrom.TryFrom Encoding.Utf8S String where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @String) . Utility.tryInto @Text.Text
 
 -- | Uses 'LazyText.decodeUtf8''.
-instance TryFrom.TryFrom (Encoding.UTF_8 LazyByteString.ByteString) LazyText.Text where
+instance TryFrom.TryFrom Encoding.Utf8L LazyText.Text where
   tryFrom = Utility.eitherTryFrom $ LazyText.decodeUtf8' . From.from
 
 -- | Converts via 'LazyText.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_8 LazyByteString.ByteString) Text.Text where
+instance TryFrom.TryFrom Encoding.Utf8L Text.Text where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @Text.Text) . Utility.tryInto @LazyText.Text
 
 -- | Converts via 'LazyText.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_8 LazyByteString.ByteString) String where
+instance TryFrom.TryFrom Encoding.Utf8L String where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @String) . Utility.tryInto @LazyText.Text
 
 -- | Uses 'Text.encodeUtf8'.
-instance From.From Text.Text (Encoding.UTF_8 ByteString.ByteString) where
+instance From.From Text.Text Encoding.Utf8S where
   from = From.from . Text.encodeUtf8
 
 -- | Converts via 'ByteString.ByteString'.
-instance From.From Text.Text (Encoding.UTF_8 LazyByteString.ByteString) where
-  from = fmap From.from . Utility.into @(Encoding.UTF_8 ByteString.ByteString)
+instance From.From Text.Text Encoding.Utf8L where
+  from = fmap From.from . Utility.into @Encoding.Utf8S
 
 -- | Uses 'LazyText.encodeUtf8'.
-instance From.From LazyText.Text (Encoding.UTF_8 LazyByteString.ByteString) where
+instance From.From LazyText.Text Encoding.Utf8L where
   from = From.from . LazyText.encodeUtf8
 
 -- | Converts via 'LazyByteString.ByteString'.
-instance From.From LazyText.Text (Encoding.UTF_8 ByteString.ByteString) where
-  from = fmap From.from . Utility.into @(Encoding.UTF_8 LazyByteString.ByteString)
+instance From.From LazyText.Text Encoding.Utf8S where
+  from = fmap From.from . Utility.into @Encoding.Utf8L
 
 -- | Converts via 'Text.Text'.
-instance From.From String (Encoding.UTF_8 ByteString.ByteString) where
+instance From.From String Encoding.Utf8S where
   from = Utility.via @Text.Text
 
 -- | Converts via 'LazyText.Text'.
-instance From.From String (Encoding.UTF_8 LazyByteString.ByteString) where
+instance From.From String Encoding.Utf8L where
   from = Utility.via @LazyText.Text
 
 -- UTF-16LE
 
 -- | Uses 'Text.decodeUtf16LE'.
-instance TryFrom.TryFrom (Encoding.UTF_16LE ByteString.ByteString) Text.Text where
+instance TryFrom.TryFrom Encoding.Utf16LS Text.Text where
   tryFrom = Utility.eitherTryFrom $ tryEvaluate @Text.UnicodeException . Text.decodeUtf16LE . From.from
 
 -- | Converts via 'Text.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_16LE ByteString.ByteString) LazyText.Text where
+instance TryFrom.TryFrom Encoding.Utf16LS LazyText.Text where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @LazyText.Text) . Utility.tryInto @Text.Text
 
 -- | Converts via 'Text.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_16LE ByteString.ByteString) String where
+instance TryFrom.TryFrom Encoding.Utf16LS String where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @String) . Utility.tryInto @Text.Text
 
 -- | Uses 'LazyText.decodeUtf16LE'.
-instance TryFrom.TryFrom (Encoding.UTF_16LE LazyByteString.ByteString) LazyText.Text where
+instance TryFrom.TryFrom Encoding.Utf16LL LazyText.Text where
   tryFrom = Utility.eitherTryFrom $ tryEvaluate @Text.UnicodeException . LazyText.decodeUtf16LE . From.from
 
 -- | Converts via 'LazyText.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_16LE LazyByteString.ByteString) Text.Text where
+instance TryFrom.TryFrom Encoding.Utf16LL Text.Text where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @Text.Text) . Utility.tryInto @LazyText.Text
 
 -- | Converts via 'LazyText.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_16LE LazyByteString.ByteString) String where
+instance TryFrom.TryFrom Encoding.Utf16LL String where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @String) . Utility.tryInto @LazyText.Text
 
 -- | Uses 'Text.encodeUtf16LE'.
-instance From.From Text.Text (Encoding.UTF_16LE ByteString.ByteString) where
+instance From.From Text.Text Encoding.Utf16LS where
   from = From.from . Text.encodeUtf16LE
 
 -- | Converts via 'ByteString.ByteString'.
-instance From.From Text.Text (Encoding.UTF_16LE LazyByteString.ByteString) where
-  from = fmap From.from . Utility.into @(Encoding.UTF_16LE ByteString.ByteString)
+instance From.From Text.Text Encoding.Utf16LL where
+  from = fmap From.from . Utility.into @Encoding.Utf16LS
 
 -- | Uses 'LazyText.encodeUtf16LE'.
-instance From.From LazyText.Text (Encoding.UTF_16LE LazyByteString.ByteString) where
+instance From.From LazyText.Text Encoding.Utf16LL where
   from = From.from . LazyText.encodeUtf16LE
 
 -- | Converts via 'LazyByteString.ByteString'.
-instance From.From LazyText.Text (Encoding.UTF_16LE ByteString.ByteString) where
-  from = fmap From.from . Utility.into @(Encoding.UTF_16LE LazyByteString.ByteString)
+instance From.From LazyText.Text Encoding.Utf16LS where
+  from = fmap From.from . Utility.into @Encoding.Utf16LL
 
 -- | Converts via 'Text.Text'.
-instance From.From String (Encoding.UTF_16LE ByteString.ByteString) where
+instance From.From String Encoding.Utf16LS where
   from = Utility.via @Text.Text
 
 -- | Converts via 'LazyText.Text'.
-instance From.From String (Encoding.UTF_16LE LazyByteString.ByteString) where
+instance From.From String Encoding.Utf16LL where
   from = Utility.via @LazyText.Text
 
 -- UTF-16BE
 
 -- | Uses 'Text.decodeUtf16BE'.
-instance TryFrom.TryFrom (Encoding.UTF_16BE ByteString.ByteString) Text.Text where
+instance TryFrom.TryFrom Encoding.Utf16BS Text.Text where
   tryFrom = Utility.eitherTryFrom $ tryEvaluate @Text.UnicodeException . Text.decodeUtf16BE . From.from
 
 -- | Converts via 'Text.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_16BE ByteString.ByteString) LazyText.Text where
+instance TryFrom.TryFrom Encoding.Utf16BS LazyText.Text where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @LazyText.Text) . Utility.tryInto @Text.Text
 
 -- | Converts via 'Text.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_16BE ByteString.ByteString) String where
+instance TryFrom.TryFrom Encoding.Utf16BS String where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @String) . Utility.tryInto @Text.Text
 
 -- | Uses 'LazyText.decodeUtf16BE'.
-instance TryFrom.TryFrom (Encoding.UTF_16BE LazyByteString.ByteString) LazyText.Text where
+instance TryFrom.TryFrom Encoding.Utf16BL LazyText.Text where
   tryFrom = Utility.eitherTryFrom $ tryEvaluate @Text.UnicodeException . LazyText.decodeUtf16BE . From.from
 
 -- | Converts via 'LazyText.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_16BE LazyByteString.ByteString) Text.Text where
+instance TryFrom.TryFrom Encoding.Utf16BL Text.Text where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @Text.Text) . Utility.tryInto @LazyText.Text
 
 -- | Converts via 'LazyText.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_16BE LazyByteString.ByteString) String where
+instance TryFrom.TryFrom Encoding.Utf16BL String where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @String) . Utility.tryInto @LazyText.Text
 
 -- | Uses 'Text.encodeUtf16BE'.
-instance From.From Text.Text (Encoding.UTF_16BE ByteString.ByteString) where
+instance From.From Text.Text Encoding.Utf16BS where
   from = From.from . Text.encodeUtf16BE
 
 -- | Converts via 'ByteString.ByteString'.
-instance From.From Text.Text (Encoding.UTF_16BE LazyByteString.ByteString) where
-  from = fmap From.from . Utility.into @(Encoding.UTF_16BE ByteString.ByteString)
+instance From.From Text.Text Encoding.Utf16BL where
+  from = fmap From.from . Utility.into @Encoding.Utf16BS
 
 -- | Uses 'LazyText.encodeUtf16BE'.
-instance From.From LazyText.Text (Encoding.UTF_16BE LazyByteString.ByteString) where
+instance From.From LazyText.Text Encoding.Utf16BL where
   from = From.from . LazyText.encodeUtf16BE
 
 -- | Converts via 'LazyByteString.ByteString'.
-instance From.From LazyText.Text (Encoding.UTF_16BE ByteString.ByteString) where
-  from = fmap From.from . Utility.into @(Encoding.UTF_16BE LazyByteString.ByteString)
+instance From.From LazyText.Text Encoding.Utf16BS where
+  from = fmap From.from . Utility.into @Encoding.Utf16BL
 
 -- | Converts via 'Text.Text'.
-instance From.From String (Encoding.UTF_16BE ByteString.ByteString) where
+instance From.From String Encoding.Utf16BS where
   from = Utility.via @Text.Text
 
 -- | Converts via 'LazyText.Text'.
-instance From.From String (Encoding.UTF_16BE LazyByteString.ByteString) where
+instance From.From String Encoding.Utf16BL where
   from = Utility.via @LazyText.Text
 
 -- UTF-32LE
 
 -- | Uses 'Text.decodeUtf32LE'.
-instance TryFrom.TryFrom (Encoding.UTF_32LE ByteString.ByteString) Text.Text where
+instance TryFrom.TryFrom Encoding.Utf32LS Text.Text where
   tryFrom = Utility.eitherTryFrom $ tryEvaluate @Text.UnicodeException . Text.decodeUtf32LE . From.from
 
 -- | Converts via 'Text.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_32LE ByteString.ByteString) LazyText.Text where
+instance TryFrom.TryFrom Encoding.Utf32LS LazyText.Text where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @LazyText.Text) . Utility.tryInto @Text.Text
 
 -- | Converts via 'Text.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_32LE ByteString.ByteString) String where
+instance TryFrom.TryFrom Encoding.Utf32LS String where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @String) . Utility.tryInto @Text.Text
 
 -- | Uses 'LazyText.decodeUtf32LE'.
-instance TryFrom.TryFrom (Encoding.UTF_32LE LazyByteString.ByteString) LazyText.Text where
+instance TryFrom.TryFrom Encoding.Utf32LL LazyText.Text where
   tryFrom = Utility.eitherTryFrom $ tryEvaluate @Text.UnicodeException . LazyText.decodeUtf32LE . From.from
 
 -- | Converts via 'LazyText.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_32LE LazyByteString.ByteString) Text.Text where
+instance TryFrom.TryFrom Encoding.Utf32LL Text.Text where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @Text.Text) . Utility.tryInto @LazyText.Text
 
 -- | Converts via 'LazyText.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_32LE LazyByteString.ByteString) String where
+instance TryFrom.TryFrom Encoding.Utf32LL String where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @String) . Utility.tryInto @LazyText.Text
 
 -- | Uses 'Text.encodeUtf32LE'.
-instance From.From Text.Text (Encoding.UTF_32LE ByteString.ByteString) where
+instance From.From Text.Text Encoding.Utf32LS where
   from = From.from . Text.encodeUtf32LE
 
 -- | Converts via 'ByteString.ByteString'.
-instance From.From Text.Text (Encoding.UTF_32LE LazyByteString.ByteString) where
-  from = fmap From.from . Utility.into @(Encoding.UTF_32LE ByteString.ByteString)
+instance From.From Text.Text Encoding.Utf32LL where
+  from = fmap From.from . Utility.into @Encoding.Utf32LS
 
 -- | Uses 'LazyText.encodeUtf32LE'.
-instance From.From LazyText.Text (Encoding.UTF_32LE LazyByteString.ByteString) where
+instance From.From LazyText.Text Encoding.Utf32LL where
   from = From.from . LazyText.encodeUtf32LE
 
 -- | Converts via 'LazyByteString.ByteString'.
-instance From.From LazyText.Text (Encoding.UTF_32LE ByteString.ByteString) where
-  from = fmap From.from . Utility.into @(Encoding.UTF_32LE LazyByteString.ByteString)
+instance From.From LazyText.Text Encoding.Utf32LS where
+  from = fmap From.from . Utility.into @Encoding.Utf32LL
 
 -- | Converts via 'Text.Text'.
-instance From.From String (Encoding.UTF_32LE ByteString.ByteString) where
+instance From.From String Encoding.Utf32LS where
   from = Utility.via @Text.Text
 
 -- | Converts via 'LazyText.Text'.
-instance From.From String (Encoding.UTF_32LE LazyByteString.ByteString) where
+instance From.From String Encoding.Utf32LL where
   from = Utility.via @LazyText.Text
 
 -- UTF-32BE
 
 -- | Uses 'Text.decodeUtf32BE'.
-instance TryFrom.TryFrom (Encoding.UTF_32BE ByteString.ByteString) Text.Text where
+instance TryFrom.TryFrom Encoding.Utf32BS Text.Text where
   tryFrom = Utility.eitherTryFrom $ tryEvaluate @Text.UnicodeException . Text.decodeUtf32BE . From.from
 
 -- | Converts via 'Text.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_32BE ByteString.ByteString) LazyText.Text where
+instance TryFrom.TryFrom Encoding.Utf32BS LazyText.Text where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @LazyText.Text) . Utility.tryInto @Text.Text
 
 -- | Converts via 'Text.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_32BE ByteString.ByteString) String where
+instance TryFrom.TryFrom Encoding.Utf32BS String where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @String) . Utility.tryInto @Text.Text
 
 -- | Uses 'LazyText.decodeUtf32BE'.
-instance TryFrom.TryFrom (Encoding.UTF_32BE LazyByteString.ByteString) LazyText.Text where
+instance TryFrom.TryFrom Encoding.Utf32BL LazyText.Text where
   tryFrom = Utility.eitherTryFrom $ tryEvaluate @Text.UnicodeException . LazyText.decodeUtf32BE . From.from
 
 -- | Converts via 'LazyText.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_32BE LazyByteString.ByteString) Text.Text where
+instance TryFrom.TryFrom Encoding.Utf32BL Text.Text where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @Text.Text) . Utility.tryInto @LazyText.Text
 
 -- | Converts via 'LazyText.Text'.
-instance TryFrom.TryFrom (Encoding.UTF_32BE LazyByteString.ByteString) String where
+instance TryFrom.TryFrom Encoding.Utf32BL String where
   tryFrom = Utility.eitherTryFrom $ fmap (Utility.into @String) . Utility.tryInto @LazyText.Text
 
 -- | Uses 'Text.encodeUtf32BE'.
-instance From.From Text.Text (Encoding.UTF_32BE ByteString.ByteString) where
+instance From.From Text.Text Encoding.Utf32BS where
   from = From.from . Text.encodeUtf32BE
 
 -- | Converts via 'ByteString.ByteString'.
-instance From.From Text.Text (Encoding.UTF_32BE LazyByteString.ByteString) where
-  from = fmap From.from . Utility.into @(Encoding.UTF_32BE ByteString.ByteString)
+instance From.From Text.Text Encoding.Utf32BL where
+  from = fmap From.from . Utility.into @Encoding.Utf32BS
 
 -- | Uses 'LazyText.encodeUtf32BE'.
-instance From.From LazyText.Text (Encoding.UTF_32BE LazyByteString.ByteString) where
+instance From.From LazyText.Text Encoding.Utf32BL where
   from = From.from . LazyText.encodeUtf32BE
 
 -- | Converts via 'LazyByteString.ByteString'.
-instance From.From LazyText.Text (Encoding.UTF_32BE ByteString.ByteString) where
-  from = fmap From.from . Utility.into @(Encoding.UTF_32BE LazyByteString.ByteString)
+instance From.From LazyText.Text Encoding.Utf32BS where
+  from = fmap From.from . Utility.into @Encoding.Utf32BL
 
 -- | Converts via 'Text.Text'.
-instance From.From String (Encoding.UTF_32BE ByteString.ByteString) where
+instance From.From String Encoding.Utf32BS where
   from = Utility.via @Text.Text
 
 -- | Converts via 'LazyText.Text'.
-instance From.From String (Encoding.UTF_32BE LazyByteString.ByteString) where
+instance From.From String Encoding.Utf32BL where
   from = Utility.via @LazyText.Text
 
 --
diff --git a/source/test-suite/Main.hs b/source/test-suite/Main.hs
--- a/source/test-suite/Main.hs
+++ b/source/test-suite/Main.hs
@@ -1,6 +1,9 @@
 {-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE DerivingVia #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NegativeLiterals #-}
+{-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE TypeApplications #-}
 {-# OPTIONS_GHC -Wno-error=overflowed-literals #-}
@@ -28,12 +31,18 @@
 import qualified Data.Time.Clock.POSIX as Time
 import qualified Data.Time.Clock.System as Time
 import qualified Data.Time.Clock.TAI as Time
+import qualified Data.Tuple as Tuple
+import qualified Data.Void as Void
 import qualified Data.Word as Word
+import qualified GHC.Generics as Generics
 import qualified GHC.Stack as Stack
 import qualified Numeric.Natural as Natural
+import qualified System.Info as Info
+import qualified System.OsString as OsString
 import qualified Test.HUnit as HUnit
 import qualified Witch
 import qualified Witch.Encoding as Encoding
+import qualified Witch.Utility as Utility
 
 main :: IO ()
 main = HUnit.runTestTTAndExit $ specToTest spec
@@ -55,7 +64,7 @@
   describe "Utility" $ do
     describe "as" $ do
       it "works" $ do
-        Witch.as @Int.Int8 1 `shouldBe` 1
+        Utility.as @Int.Int8 1 `shouldBe` 1
 
     describe "into" $ do
       it "works" $ do
@@ -63,7 +72,7 @@
 
     describe "over" $ do
       it "works" $ do
-        Witch.over @Int.Int8 (+ 1) (Age 1) `shouldBe` Age 2
+        Utility.over @Int.Int8 (+ 1) (MkAge 1) `shouldBe` MkAge 2
 
     describe "via" $ do
       it "works" $ do
@@ -1656,16 +1665,16 @@
     describe "From Integer (Fixed a)" $ do
       let f = Witch.from @Integer @Fixed.Deci
       it "works" $ do
-        f 1 `shouldBe` 0.1
-        f 10 `shouldBe` 1
-        f 120 `shouldBe` 12
+        f 1 `shouldBe` 1.0
+        f 10 `shouldBe` 10.0
+        f 120 `shouldBe` 120.0
 
-    describe "From (Fixed a) Integer" $ do
-      let f = Witch.from @Fixed.Deci @Integer
+    describe "TryFrom (Fixed a) Integer" $ do
+      let f = hush . Witch.tryFrom @Fixed.Deci @Integer
       it "works" $ do
-        f 0.1 `shouldBe` 1
-        f 1 `shouldBe` 10
-        f 12 `shouldBe` 120
+        f 0.1 `shouldBe` Nothing
+        f 1 `shouldBe` Just 1
+        f 12 `shouldBe` Just 12
 
     describe "From (Fixed a) Rational" $ do
       let f = Witch.from @Fixed.Deci @Rational
@@ -1843,6 +1852,40 @@
         f (ShortByteString.pack [0x00]) `shouldBe` ByteString.pack [0x00]
         f (ShortByteString.pack [0x0f, 0xf0]) `shouldBe` ByteString.pack [0x0f, 0xf0]
 
+    describe "From [OsChar] OsString" $ do
+      let f = Witch.from @[OsString.OsChar] @OsString.OsString
+      it "works" $ do
+        f [] `shouldBe` OsString.pack []
+        f [OsString.unsafeFromChar 'a'] `shouldBe` OsString.pack [OsString.unsafeFromChar 'a']
+        f [OsString.unsafeFromChar 'a', OsString.unsafeFromChar 'b']
+          `shouldBe` OsString.pack [OsString.unsafeFromChar 'a', OsString.unsafeFromChar 'b']
+
+    describe "From OsString [OsChar]" $ do
+      let f = Witch.from @OsString.OsString @[OsString.OsChar]
+      it "works" $ do
+        f (OsString.pack []) `shouldBe` []
+        f (OsString.pack [OsString.unsafeFromChar 'a']) `shouldBe` [OsString.unsafeFromChar 'a']
+        f (OsString.pack [OsString.unsafeFromChar 'a', OsString.unsafeFromChar 'b'])
+          `shouldBe` [OsString.unsafeFromChar 'a', OsString.unsafeFromChar 'b']
+
+    describe "From OsChar Word" $ do
+      let f = Witch.from @OsString.OsChar @Word
+      it "works" $ do
+        f (OsString.unsafeFromChar 'a') `shouldBe` 97
+        f (OsString.unsafeFromChar '\xFF') `shouldBe` 255
+
+    describe "From Text OsString" $ do
+      let f = Witch.from @Text.Text @OsString.OsString
+      it "works" $ do
+        f (Text.pack "") `shouldBe` OsString.pack []
+        f (Text.pack "hello") `shouldBe` OsString.pack (fmap OsString.unsafeFromChar "hello")
+
+    describe "From LazyText OsString" $ do
+      let f = Witch.from @LazyText.Text @OsString.OsString
+      it "works" $ do
+        f (LazyText.pack "") `shouldBe` OsString.pack []
+        f (LazyText.pack "hello") `shouldBe` OsString.pack (fmap OsString.unsafeFromChar "hello")
+
     describe "From Text LazyText" $ do
       let f = Witch.from @Text.Text @LazyText.Text
       it "works" $ do
@@ -2010,74 +2053,74 @@
       it "works" $ do
         f (Tagged.Tagged False) `shouldBe` Tagged.Tagged False
 
-    describe "From (ISO_8859_1 ByteString) Text" $ do
-      let f = Witch.from @(Encoding.ISO_8859_1 ByteString.ByteString) @Text.Text
+    describe "From Latin1S Text" $ do
+      let f = Witch.from @Encoding.Latin1S @Text.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [0x61])) `shouldBe` Text.pack "a"
 
-    describe "From (ISO_8859_1 ByteString) LazyText" $ do
-      let f = Witch.from @(Encoding.ISO_8859_1 ByteString.ByteString) @LazyText.Text
+    describe "From Latin1S LazyText" $ do
+      let f = Witch.from @Encoding.Latin1S @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [0x61])) `shouldBe` LazyText.pack "a"
 
-    describe "From (ISO_8859_1 ByteString) String" $ do
-      let f = Witch.from @(Encoding.ISO_8859_1 ByteString.ByteString) @String
+    describe "From Latin1S String" $ do
+      let f = Witch.from @Encoding.Latin1S @String
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [0x61])) `shouldBe` "a"
 
-    describe "From (ISO_8859_1 LazyByteString) LazyText" $ do
-      let f = Witch.from @(Encoding.ISO_8859_1 LazyByteString.ByteString) @LazyText.Text
+    describe "From Latin1L LazyText" $ do
+      let f = Witch.from @Encoding.Latin1L @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x61])) `shouldBe` LazyText.pack "a"
 
-    describe "From (ISO_8859_1 LazyByteString) Text" $ do
-      let f = Witch.from @(Encoding.ISO_8859_1 LazyByteString.ByteString) @Text.Text
+    describe "From Latin1L Text" $ do
+      let f = Witch.from @Encoding.Latin1L @Text.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x61])) `shouldBe` Text.pack "a"
 
-    describe "From (ISO_8859_1 LazyByteString) String" $ do
-      let f = Witch.from @(Encoding.ISO_8859_1 LazyByteString.ByteString) @String
+    describe "From Latin1L String" $ do
+      let f = Witch.from @Encoding.Latin1L @String
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x61])) `shouldBe` "a"
 
-    describe "TryFrom Text (ISO_8859_1 ByteString)" $ do
-      let f = hush . Witch.tryFrom @Text.Text @(Encoding.ISO_8859_1 ByteString.ByteString)
+    describe "TryFrom Text Latin1S" $ do
+      let f = hush . Witch.tryFrom @Text.Text @Encoding.Latin1S
       it "works" $ do
         f (Text.pack "a") `shouldBe` Just (Tagged.Tagged $ ByteString.pack [0x61])
         f (Text.pack "\x100") `shouldBe` Nothing
 
-    describe "TryFrom Text (ISO_8859_1 LazyByteString)" $ do
-      let f = hush . Witch.tryFrom @Text.Text @(Encoding.ISO_8859_1 LazyByteString.ByteString)
+    describe "TryFrom Text Latin1L" $ do
+      let f = hush . Witch.tryFrom @Text.Text @Encoding.Latin1L
       it "works" $ do
         f (Text.pack "a") `shouldBe` Just (Tagged.Tagged $ LazyByteString.pack [0x61])
         f (Text.pack "\x100") `shouldBe` Nothing
 
-    describe "TryFrom LazyText (ISO_8859_1 LazyByteString)" $ do
-      let f = hush . Witch.tryFrom @LazyText.Text @(Encoding.ISO_8859_1 LazyByteString.ByteString)
+    describe "TryFrom LazyText Latin1L" $ do
+      let f = hush . Witch.tryFrom @LazyText.Text @Encoding.Latin1L
       it "works" $ do
         f (LazyText.pack "a") `shouldBe` Just (Tagged.Tagged $ LazyByteString.pack [0x61])
         f (LazyText.pack "\x100") `shouldBe` Nothing
 
-    describe "TryFrom LazyText (ISO_8859_1 ByteString)" $ do
-      let f = hush . Witch.tryFrom @LazyText.Text @(Encoding.ISO_8859_1 ByteString.ByteString)
+    describe "TryFrom LazyText Latin1S" $ do
+      let f = hush . Witch.tryFrom @LazyText.Text @Encoding.Latin1S
       it "works" $ do
         f (LazyText.pack "a") `shouldBe` Just (Tagged.Tagged $ ByteString.pack [0x61])
         f (LazyText.pack "\x100") `shouldBe` Nothing
 
-    describe "TryFrom String (ISO_8859_1 ByteString)" $ do
-      let f = hush . Witch.tryFrom @String @(Encoding.ISO_8859_1 ByteString.ByteString)
+    describe "TryFrom String Latin1S" $ do
+      let f = hush . Witch.tryFrom @String @Encoding.Latin1S
       it "works" $ do
         f "a" `shouldBe` Just (Tagged.Tagged $ ByteString.pack [0x61])
         f "\x100" `shouldBe` Nothing
 
-    describe "TryFrom String (ISO_8859_1 LazyByteString)" $ do
-      let f = hush . Witch.tryFrom @String @(Encoding.ISO_8859_1 LazyByteString.ByteString)
+    describe "TryFrom String Latin1L" $ do
+      let f = hush . Witch.tryFrom @String @Encoding.Latin1L
       it "works" $ do
         f "a" `shouldBe` Just (Tagged.Tagged $ LazyByteString.pack [0x61])
         f "\x100" `shouldBe` Nothing
 
-    describe "TryFrom (UTF_8 ByteString) Text" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_8 ByteString.ByteString) @Text.Text
+    describe "TryFrom Utf8S Text" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf8S @Text.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [])) `shouldBe` Just (Text.pack "")
         f (Tagged.Tagged (ByteString.pack [0x61])) `shouldBe` Just (Text.pack "a")
@@ -2087,43 +2130,43 @@
         f (Tagged.Tagged (ByteString.pack [0xe2, 0x82, 0xac])) `shouldBe` Just (Text.pack "\x20ac")
         f (Tagged.Tagged (ByteString.pack [0xf0, 0x90, 0x8d, 0x88])) `shouldBe` Just (Text.pack "\x10348")
 
-    describe "TryFrom (UTF_8 ByteString) LazyText" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_8 ByteString.ByteString) @LazyText.Text
+    describe "TryFrom Utf8S LazyText" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf8S @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [])) `shouldBe` Just (LazyText.pack "")
         f (Tagged.Tagged (ByteString.pack [0x61])) `shouldBe` Just (LazyText.pack "a")
         f (Tagged.Tagged (ByteString.pack [0xff])) `shouldBe` Nothing
 
-    describe "TryFrom (UTF_8 ByteString) String" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_8 ByteString.ByteString) @String
+    describe "TryFrom Utf8S String" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf8S @String
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [])) `shouldBe` Just ""
         f (Tagged.Tagged (ByteString.pack [0x61])) `shouldBe` Just "a"
         f (Tagged.Tagged (ByteString.pack [0xff])) `shouldBe` Nothing
 
-    describe "TryFrom (UTF_8 LazyByteString) LazyText" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_8 LazyByteString.ByteString) @LazyText.Text
+    describe "TryFrom Utf8L LazyText" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf8L @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [])) `shouldBe` Just (LazyText.pack "")
         f (Tagged.Tagged (LazyByteString.pack [0x61])) `shouldBe` Just (LazyText.pack "a")
         f (Tagged.Tagged (LazyByteString.pack [0xff])) `shouldBe` Nothing
 
-    describe "TryFrom (UTF_8 LazyByteString) Text" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_8 LazyByteString.ByteString) @Text.Text
+    describe "TryFrom Utf8L Text" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf8L @Text.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [])) `shouldBe` Just (Text.pack "")
         f (Tagged.Tagged (LazyByteString.pack [0x61])) `shouldBe` Just (Text.pack "a")
         f (Tagged.Tagged (LazyByteString.pack [0xff])) `shouldBe` Nothing
 
-    describe "TryFrom (UTF_8 LazyByteString) String" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_8 LazyByteString.ByteString) @String
+    describe "TryFrom Utf8L String" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf8L @String
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [])) `shouldBe` Just ""
         f (Tagged.Tagged (LazyByteString.pack [0x61])) `shouldBe` Just "a"
         f (Tagged.Tagged (LazyByteString.pack [0xff])) `shouldBe` Nothing
 
-    describe "From Text (UTF_8 ByteString)" $ do
-      let f = Witch.from @Text.Text @(Encoding.UTF_8 ByteString.ByteString)
+    describe "From Text Utf8S" $ do
+      let f = Witch.from @Text.Text @Encoding.Utf8S
       it "works" $ do
         f (Text.pack "") `shouldBe` Tagged.Tagged (ByteString.pack [])
         f (Text.pack "a") `shouldBe` Tagged.Tagged (ByteString.pack [0x61])
@@ -2132,38 +2175,38 @@
         f (Text.pack "\x20ac") `shouldBe` Tagged.Tagged (ByteString.pack [0xe2, 0x82, 0xac])
         f (Text.pack "\x10348") `shouldBe` Tagged.Tagged (ByteString.pack [0xf0, 0x90, 0x8d, 0x88])
 
-    describe "From Text (UTF_8 LazyByteString)" $ do
-      let f = Witch.from @Text.Text @(Encoding.UTF_8 LazyByteString.ByteString)
+    describe "From Text Utf8L" $ do
+      let f = Witch.from @Text.Text @Encoding.Utf8L
       it "works" $ do
         f (Text.pack "") `shouldBe` Tagged.Tagged (LazyByteString.pack [])
         f (Text.pack "a") `shouldBe` Tagged.Tagged (LazyByteString.pack [0x61])
 
-    describe "From LazyText (UTF_8 LazyByteString)" $ do
-      let f = Witch.from @LazyText.Text @(Encoding.UTF_8 LazyByteString.ByteString)
+    describe "From LazyText Utf8L" $ do
+      let f = Witch.from @LazyText.Text @Encoding.Utf8L
       it "works" $ do
         f (LazyText.pack "") `shouldBe` Tagged.Tagged (LazyByteString.pack [])
         f (LazyText.pack "a") `shouldBe` Tagged.Tagged (LazyByteString.pack [0x61])
 
-    describe "From LazyText (UTF_8 ByteString)" $ do
-      let f = Witch.from @LazyText.Text @(Encoding.UTF_8 ByteString.ByteString)
+    describe "From LazyText Utf8S" $ do
+      let f = Witch.from @LazyText.Text @Encoding.Utf8S
       it "works" $ do
         f (LazyText.pack "") `shouldBe` Tagged.Tagged (ByteString.pack [])
         f (LazyText.pack "a") `shouldBe` Tagged.Tagged (ByteString.pack [0x61])
 
-    describe "From String (UTF_8 ByteString)" $ do
-      let f = Witch.from @String @(Encoding.UTF_8 ByteString.ByteString)
+    describe "From String Utf8S" $ do
+      let f = Witch.from @String @Encoding.Utf8S
       it "works" $ do
         f "" `shouldBe` Tagged.Tagged (ByteString.pack [])
         f "a" `shouldBe` Tagged.Tagged (ByteString.pack [0x61])
 
-    describe "From String (UTF_8 LazyByteString)" $ do
-      let f = Witch.from @String @(Encoding.UTF_8 LazyByteString.ByteString)
+    describe "From String Utf8L" $ do
+      let f = Witch.from @String @Encoding.Utf8L
       it "works" $ do
         f "" `shouldBe` Tagged.Tagged (LazyByteString.pack [])
         f "a" `shouldBe` Tagged.Tagged (LazyByteString.pack [0x61])
 
-    describe "TryFrom (UTF_16LE ByteString) Text" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16LE ByteString.ByteString) @Text.Text
+    describe "TryFrom Utf16LS Text" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16LS @Text.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [])) `shouldBe` Just (Text.pack "")
         f (Tagged.Tagged (ByteString.pack [0x24, 0x00])) `shouldBe` Just (Text.pack "\x24")
@@ -2172,33 +2215,33 @@
         f (Tagged.Tagged (ByteString.pack [0x00, 0xd8, 0x48, 0xdf])) `shouldBe` Just (Text.pack "\x10348")
         f (Tagged.Tagged (ByteString.pack [0x00])) `shouldBe` Nothing
 
-    describe "TryFrom (UTF_16LE ByteString) LazyText" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16LE ByteString.ByteString) @LazyText.Text
+    describe "TryFrom Utf16LS LazyText" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16LS @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [0x61, 0x00])) `shouldBe` Just (LazyText.pack "a")
 
-    describe "TryFrom (UTF_16LE ByteString) String" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16LE ByteString.ByteString) @String
+    describe "TryFrom Utf16LS String" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16LS @String
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [0x61, 0x00])) `shouldBe` Just "a"
 
-    describe "TryFrom (UTF_16LE LazyByteString) LazyText" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16LE LazyByteString.ByteString) @LazyText.Text
+    describe "TryFrom Utf16LL LazyText" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16LL @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x61, 0x00])) `shouldBe` Just (LazyText.pack "a")
 
-    describe "TryFrom (UTF_16LE LazyByteString) Text" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16LE LazyByteString.ByteString) @Text.Text
+    describe "TryFrom Utf16LL Text" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16LL @Text.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x61, 0x00])) `shouldBe` Just (Text.pack "a")
 
-    describe "TryFrom (UTF_16LE LazyByteString) String" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16LE LazyByteString.ByteString) @String
+    describe "TryFrom Utf16LL String" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16LL @String
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x61, 0x00])) `shouldBe` Just "a"
 
-    describe "From Text (UTF_16LE ByteString)" $ do
-      let f = Witch.from @Text.Text @(Encoding.UTF_16LE ByteString.ByteString)
+    describe "From Text Utf16LS" $ do
+      let f = Witch.from @Text.Text @Encoding.Utf16LS
       it "works" $ do
         f (Text.pack "") `shouldBe` Tagged.Tagged (ByteString.pack [])
         f (Text.pack "\x24") `shouldBe` Tagged.Tagged (ByteString.pack [0x24, 0x00])
@@ -2206,33 +2249,33 @@
         f (Text.pack "\x20ac") `shouldBe` Tagged.Tagged (ByteString.pack [0xac, 0x20])
         f (Text.pack "\x10348") `shouldBe` Tagged.Tagged (ByteString.pack [0x00, 0xd8, 0x48, 0xdf])
 
-    describe "From Text (UTF_16LE LazyByteString)" $ do
-      let f = Witch.from @Text.Text @(Encoding.UTF_16LE LazyByteString.ByteString)
+    describe "From Text Utf16LL" $ do
+      let f = Witch.from @Text.Text @Encoding.Utf16LL
       it "works" $ do
         f (Text.pack "a") `shouldBe` Tagged.Tagged (LazyByteString.pack [0x61, 0x00])
 
-    describe "From LazyText (UTF_16LE LazyByteString)" $ do
-      let f = Witch.from @LazyText.Text @(Encoding.UTF_16LE LazyByteString.ByteString)
+    describe "From LazyText Utf16LL" $ do
+      let f = Witch.from @LazyText.Text @Encoding.Utf16LL
       it "works" $ do
         f (LazyText.pack "a") `shouldBe` Tagged.Tagged (LazyByteString.pack [0x61, 0x00])
 
-    describe "From LazyText (UTF_16LE ByteString)" $ do
-      let f = Witch.from @LazyText.Text @(Encoding.UTF_16LE ByteString.ByteString)
+    describe "From LazyText Utf16LS" $ do
+      let f = Witch.from @LazyText.Text @Encoding.Utf16LS
       it "works" $ do
         f (LazyText.pack "a") `shouldBe` Tagged.Tagged (ByteString.pack [0x61, 0x00])
 
-    describe "From String (UTF_16LE ByteString)" $ do
-      let f = Witch.from @String @(Encoding.UTF_16LE ByteString.ByteString)
+    describe "From String Utf16LS" $ do
+      let f = Witch.from @String @Encoding.Utf16LS
       it "works" $ do
         f "a" `shouldBe` Tagged.Tagged (ByteString.pack [0x61, 0x00])
 
-    describe "From String (UTF_16LE LazyByteString)" $ do
-      let f = Witch.from @String @(Encoding.UTF_16LE LazyByteString.ByteString)
+    describe "From String Utf16LL" $ do
+      let f = Witch.from @String @Encoding.Utf16LL
       it "works" $ do
         f "a" `shouldBe` Tagged.Tagged (LazyByteString.pack [0x61, 0x00])
 
-    describe "TryFrom (UTF_16BE ByteString) Text" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16BE ByteString.ByteString) @Text.Text
+    describe "TryFrom Utf16BS Text" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16BS @Text.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [])) `shouldBe` Just (Text.pack "")
         f (Tagged.Tagged (ByteString.pack [0x00, 0x24])) `shouldBe` Just (Text.pack "\x24")
@@ -2241,33 +2284,33 @@
         f (Tagged.Tagged (ByteString.pack [0xd8, 0x00, 0xdf, 0x48])) `shouldBe` Just (Text.pack "\x10348")
         f (Tagged.Tagged (ByteString.pack [0x00])) `shouldBe` Nothing
 
-    describe "TryFrom (UTF_16BE ByteString) LazyText" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16BE ByteString.ByteString) @LazyText.Text
+    describe "TryFrom Utf16BS LazyText" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16BS @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [0x00, 0x61])) `shouldBe` Just (LazyText.pack "a")
 
-    describe "TryFrom (UTF_16BE ByteString) String" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16BE ByteString.ByteString) @String
+    describe "TryFrom Utf16BS String" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16BS @String
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [0x00, 0x61])) `shouldBe` Just "a"
 
-    describe "TryFrom (UTF_16BE LazyByteString) LazyText" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16BE LazyByteString.ByteString) @LazyText.Text
+    describe "TryFrom Utf16BL LazyText" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16BL @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x00, 0x61])) `shouldBe` Just (LazyText.pack "a")
 
-    describe "TryFrom (UTF_16BE LazyByteString) Text" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16BE LazyByteString.ByteString) @Text.Text
+    describe "TryFrom Utf16BL Text" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16BL @Text.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x00, 0x61])) `shouldBe` Just (Text.pack "a")
 
-    describe "TryFrom (UTF_16BE LazyByteString) String" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_16BE LazyByteString.ByteString) @String
+    describe "TryFrom Utf16BL String" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf16BL @String
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x00, 0x61])) `shouldBe` Just "a"
 
-    describe "From Text (UTF_16BE ByteString)" $ do
-      let f = Witch.from @Text.Text @(Encoding.UTF_16BE ByteString.ByteString)
+    describe "From Text Utf16BS" $ do
+      let f = Witch.from @Text.Text @Encoding.Utf16BS
       it "works" $ do
         f (Text.pack "") `shouldBe` Tagged.Tagged (ByteString.pack [])
         f (Text.pack "\x24") `shouldBe` Tagged.Tagged (ByteString.pack [0x00, 0x24])
@@ -2275,33 +2318,33 @@
         f (Text.pack "\x20ac") `shouldBe` Tagged.Tagged (ByteString.pack [0x20, 0xac])
         f (Text.pack "\x10348") `shouldBe` Tagged.Tagged (ByteString.pack [0xd8, 0x00, 0xdf, 0x48])
 
-    describe "From Text (UTF_16BE LazyByteString)" $ do
-      let f = Witch.from @Text.Text @(Encoding.UTF_16BE LazyByteString.ByteString)
+    describe "From Text Utf16BL" $ do
+      let f = Witch.from @Text.Text @Encoding.Utf16BL
       it "works" $ do
         f (Text.pack "a") `shouldBe` Tagged.Tagged (LazyByteString.pack [0x00, 0x61])
 
-    describe "From LazyText (UTF_16BE LazyByteString)" $ do
-      let f = Witch.from @LazyText.Text @(Encoding.UTF_16BE LazyByteString.ByteString)
+    describe "From LazyText Utf16BL" $ do
+      let f = Witch.from @LazyText.Text @Encoding.Utf16BL
       it "works" $ do
         f (LazyText.pack "a") `shouldBe` Tagged.Tagged (LazyByteString.pack [0x00, 0x61])
 
-    describe "From LazyText (UTF_16BE ByteString)" $ do
-      let f = Witch.from @LazyText.Text @(Encoding.UTF_16BE ByteString.ByteString)
+    describe "From LazyText Utf16BS" $ do
+      let f = Witch.from @LazyText.Text @Encoding.Utf16BS
       it "works" $ do
         f (LazyText.pack "a") `shouldBe` Tagged.Tagged (ByteString.pack [0x00, 0x61])
 
-    describe "From String (UTF_16BE ByteString)" $ do
-      let f = Witch.from @String @(Encoding.UTF_16BE ByteString.ByteString)
+    describe "From String Utf16BS" $ do
+      let f = Witch.from @String @Encoding.Utf16BS
       it "works" $ do
         f "a" `shouldBe` Tagged.Tagged (ByteString.pack [0x00, 0x61])
 
-    describe "From String (UTF_16BE LazyByteString)" $ do
-      let f = Witch.from @String @(Encoding.UTF_16BE LazyByteString.ByteString)
+    describe "From String Utf16BL" $ do
+      let f = Witch.from @String @Encoding.Utf16BL
       it "works" $ do
         f "a" `shouldBe` Tagged.Tagged (LazyByteString.pack [0x00, 0x61])
 
-    describe "TryFrom (UTF_32LE ByteString) Text" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32LE ByteString.ByteString) @Text.Text
+    describe "TryFrom Utf32LS Text" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32LS @Text.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [])) `shouldBe` Just (Text.pack "")
         f (Tagged.Tagged (ByteString.pack [0x24, 0x00, 0x00, 0x00])) `shouldBe` Just (Text.pack "\x24")
@@ -2310,33 +2353,33 @@
         f (Tagged.Tagged (ByteString.pack [0x48, 0x03, 0x01, 0x00])) `shouldBe` Just (Text.pack "\x10348")
         f (Tagged.Tagged (ByteString.pack [0x00])) `shouldBe` Nothing
 
-    describe "TryFrom (UTF_32LE ByteString) LazyText" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32LE ByteString.ByteString) @LazyText.Text
+    describe "TryFrom Utf32LS LazyText" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32LS @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [0x61, 0x00, 0x00, 0x00])) `shouldBe` Just (LazyText.pack "a")
 
-    describe "TryFrom (UTF_32LE ByteString) String" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32LE ByteString.ByteString) @String
+    describe "TryFrom Utf32LS String" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32LS @String
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [0x61, 0x00, 0x00, 0x00])) `shouldBe` Just "a"
 
-    describe "TryFrom (UTF_32LE LazyByteString) LazyText" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32LE LazyByteString.ByteString) @LazyText.Text
+    describe "TryFrom Utf32LL LazyText" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32LL @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x61, 0x00, 0x00, 0x00])) `shouldBe` Just (LazyText.pack "a")
 
-    describe "TryFrom (UTF_32LE LazyByteString) Text" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32LE LazyByteString.ByteString) @Text.Text
+    describe "TryFrom Utf32LL Text" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32LL @Text.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x61, 0x00, 0x00, 0x00])) `shouldBe` Just (Text.pack "a")
 
-    describe "TryFrom (UTF_32LE LazyByteString) String" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32LE LazyByteString.ByteString) @String
+    describe "TryFrom Utf32LL String" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32LL @String
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x61, 0x00, 0x00, 0x00])) `shouldBe` Just "a"
 
-    describe "From Text (UTF_32LE ByteString)" $ do
-      let f = Witch.from @Text.Text @(Encoding.UTF_32LE ByteString.ByteString)
+    describe "From Text Utf32LS" $ do
+      let f = Witch.from @Text.Text @Encoding.Utf32LS
       it "works" $ do
         f (Text.pack "") `shouldBe` Tagged.Tagged (ByteString.pack [])
         f (Text.pack "\x24") `shouldBe` Tagged.Tagged (ByteString.pack [0x24, 0x00, 0x00, 0x00])
@@ -2344,33 +2387,33 @@
         f (Text.pack "\x20ac") `shouldBe` Tagged.Tagged (ByteString.pack [0xac, 0x20, 0x00, 0x00])
         f (Text.pack "\x10348") `shouldBe` Tagged.Tagged (ByteString.pack [0x48, 0x03, 0x01, 0x00])
 
-    describe "From Text (UTF_32LE LazyByteString)" $ do
-      let f = Witch.from @Text.Text @(Encoding.UTF_32LE LazyByteString.ByteString)
+    describe "From Text Utf32LL" $ do
+      let f = Witch.from @Text.Text @Encoding.Utf32LL
       it "works" $ do
         f (Text.pack "a") `shouldBe` Tagged.Tagged (LazyByteString.pack [0x61, 0x00, 0x00, 0x00])
 
-    describe "From LazyText (UTF_32LE LazyByteString)" $ do
-      let f = Witch.from @LazyText.Text @(Encoding.UTF_32LE LazyByteString.ByteString)
+    describe "From LazyText Utf32LL" $ do
+      let f = Witch.from @LazyText.Text @Encoding.Utf32LL
       it "works" $ do
         f (LazyText.pack "a") `shouldBe` Tagged.Tagged (LazyByteString.pack [0x61, 0x00, 0x00, 0x00])
 
-    describe "From LazyText (UTF_32LE ByteString)" $ do
-      let f = Witch.from @LazyText.Text @(Encoding.UTF_32LE ByteString.ByteString)
+    describe "From LazyText Utf32LS" $ do
+      let f = Witch.from @LazyText.Text @Encoding.Utf32LS
       it "works" $ do
         f (LazyText.pack "a") `shouldBe` Tagged.Tagged (ByteString.pack [0x61, 0x00, 0x00, 0x00])
 
-    describe "From String (UTF_32LE ByteString)" $ do
-      let f = Witch.from @String @(Encoding.UTF_32LE ByteString.ByteString)
+    describe "From String Utf32LS" $ do
+      let f = Witch.from @String @Encoding.Utf32LS
       it "works" $ do
         f "a" `shouldBe` Tagged.Tagged (ByteString.pack [0x61, 0x00, 0x00, 0x00])
 
-    describe "From String (UTF_32LE LazyByteString)" $ do
-      let f = Witch.from @String @(Encoding.UTF_32LE LazyByteString.ByteString)
+    describe "From String Utf32LL" $ do
+      let f = Witch.from @String @Encoding.Utf32LL
       it "works" $ do
         f "a" `shouldBe` Tagged.Tagged (LazyByteString.pack [0x61, 0x00, 0x00, 0x00])
 
-    describe "TryFrom (UTF_32BE ByteString) Text" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32BE ByteString.ByteString) @Text.Text
+    describe "TryFrom Utf32BS Text" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32BS @Text.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [])) `shouldBe` Just (Text.pack "")
         f (Tagged.Tagged (ByteString.pack [0x00, 0x00, 0x00, 0x24])) `shouldBe` Just (Text.pack "\x24")
@@ -2379,33 +2422,33 @@
         f (Tagged.Tagged (ByteString.pack [0x00, 0x01, 0x03, 0x48])) `shouldBe` Just (Text.pack "\x10348")
         f (Tagged.Tagged (ByteString.pack [0x00])) `shouldBe` Nothing
 
-    describe "TryFrom (UTF_32BE ByteString) LazyText" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32BE ByteString.ByteString) @LazyText.Text
+    describe "TryFrom Utf32BS LazyText" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32BS @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [0x00, 0x00, 0x00, 0x61])) `shouldBe` Just (LazyText.pack "a")
 
-    describe "TryFrom (UTF_32BE ByteString) String" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32BE ByteString.ByteString) @String
+    describe "TryFrom Utf32BS String" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32BS @String
       it "works" $ do
         f (Tagged.Tagged (ByteString.pack [0x00, 0x00, 0x00, 0x61])) `shouldBe` Just "a"
 
-    describe "TryFrom (UTF_32BE LazyByteString) LazyText" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32BE LazyByteString.ByteString) @LazyText.Text
+    describe "TryFrom Utf32BL LazyText" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32BL @LazyText.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x00, 0x00, 0x00, 0x61])) `shouldBe` Just (LazyText.pack "a")
 
-    describe "TryFrom (UTF_32BE LazyByteString) Text" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32BE LazyByteString.ByteString) @Text.Text
+    describe "TryFrom Utf32BL Text" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32BL @Text.Text
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x00, 0x00, 0x00, 0x61])) `shouldBe` Just (Text.pack "a")
 
-    describe "TryFrom (UTF_32BE LazyByteString) String" $ do
-      let f = hush . Witch.tryFrom @(Encoding.UTF_32BE LazyByteString.ByteString) @String
+    describe "TryFrom Utf32BL String" $ do
+      let f = hush . Witch.tryFrom @Encoding.Utf32BL @String
       it "works" $ do
         f (Tagged.Tagged (LazyByteString.pack [0x00, 0x00, 0x00, 0x61])) `shouldBe` Just "a"
 
-    describe "From Text (UTF_32BE ByteString)" $ do
-      let f = Witch.from @Text.Text @(Encoding.UTF_32BE ByteString.ByteString)
+    describe "From Text Utf32BS" $ do
+      let f = Witch.from @Text.Text @Encoding.Utf32BS
       it "works" $ do
         f (Text.pack "") `shouldBe` Tagged.Tagged (ByteString.pack [])
         f (Text.pack "\x24") `shouldBe` Tagged.Tagged (ByteString.pack [0x00, 0x00, 0x00, 0x24])
@@ -2413,33 +2456,147 @@
         f (Text.pack "\x20ac") `shouldBe` Tagged.Tagged (ByteString.pack [0x00, 0x00, 0x20, 0xac])
         f (Text.pack "\x10348") `shouldBe` Tagged.Tagged (ByteString.pack [0x00, 0x01, 0x03, 0x48])
 
-    describe "From Text (UTF_32BE LazyByteString)" $ do
-      let f = Witch.from @Text.Text @(Encoding.UTF_32BE LazyByteString.ByteString)
+    describe "From Text Utf32BL" $ do
+      let f = Witch.from @Text.Text @Encoding.Utf32BL
       it "works" $ do
         f (Text.pack "a") `shouldBe` Tagged.Tagged (LazyByteString.pack [0x00, 0x00, 0x00, 0x61])
 
-    describe "From LazyText (UTF_32BE LazyByteString)" $ do
-      let f = Witch.from @LazyText.Text @(Encoding.UTF_32BE LazyByteString.ByteString)
+    describe "From LazyText Utf32BL" $ do
+      let f = Witch.from @LazyText.Text @Encoding.Utf32BL
       it "works" $ do
         f (LazyText.pack "a") `shouldBe` Tagged.Tagged (LazyByteString.pack [0x00, 0x00, 0x00, 0x61])
 
-    describe "From LazyText (UTF_32BE ByteString)" $ do
-      let f = Witch.from @LazyText.Text @(Encoding.UTF_32BE ByteString.ByteString)
+    describe "From LazyText Utf32BS" $ do
+      let f = Witch.from @LazyText.Text @Encoding.Utf32BS
       it "works" $ do
         f (LazyText.pack "a") `shouldBe` Tagged.Tagged (ByteString.pack [0x00, 0x00, 0x00, 0x61])
 
-    describe "From String (UTF_32BE ByteString)" $ do
-      let f = Witch.from @String @(Encoding.UTF_32BE ByteString.ByteString)
+    describe "From String Utf32BS" $ do
+      let f = Witch.from @String @Encoding.Utf32BS
       it "works" $ do
         f "a" `shouldBe` Tagged.Tagged (ByteString.pack [0x00, 0x00, 0x00, 0x61])
 
-    describe "From String (UTF_32BE LazyByteString)" $ do
-      let f = Witch.from @String @(Encoding.UTF_32BE LazyByteString.ByteString)
+    describe "From String Utf32BL" $ do
+      let f = Witch.from @String @Encoding.Utf32BL
       it "works" $ do
         f "a" `shouldBe` Tagged.Tagged (LazyByteString.pack [0x00, 0x00, 0x00, 0x61])
 
+    describe "TryFrom Word OsChar" $ do
+      let f = hush . Witch.tryFrom @Word @OsString.OsChar
+      it "works" $ do
+        f 97 `shouldBe` Just (OsString.unsafeFromChar 'a')
+        f 255 `shouldBe` Just (OsString.unsafeFromChar '\xFF')
+        -- Above @0x10FFFF@, so it fails on both POSIX and Windows.
+        f 0x110000 `shouldBe` Nothing
+
+    describe "TryFrom String OsString" $ do
+      let f = hush . Witch.tryFrom @String @OsString.OsString
+      it "works" $ do
+        f "" `shouldBe` Just (OsString.pack [])
+        f "hello" `shouldBe` Just (OsString.pack (fmap OsString.unsafeFromChar "hello"))
+        f "\xD800" `shouldBe` Nothing
+
+    describe "TryFrom OsString String" $ do
+      let f = hush . Witch.tryFrom @OsString.OsString @String
+      it "works" $ do
+        f (OsString.pack []) `shouldBe` Just ""
+        f (OsString.pack (fmap OsString.unsafeFromChar "hello")) `shouldBe` Just "hello"
+        f invalidOsString `shouldBe` Nothing
+
+    describe "TryFrom OsString Text" $ do
+      let f = hush . Witch.tryFrom @OsString.OsString @Text.Text
+      it "works" $ do
+        f (OsString.pack []) `shouldBe` Just (Text.pack "")
+        f (OsString.pack (fmap OsString.unsafeFromChar "hello")) `shouldBe` Just (Text.pack "hello")
+        f invalidOsString `shouldBe` Nothing
+
+    describe "TryFrom OsString LazyText" $ do
+      let f = hush . Witch.tryFrom @OsString.OsString @LazyText.Text
+      it "works" $ do
+        f (OsString.pack []) `shouldBe` Just (LazyText.pack "")
+        f (OsString.pack (fmap OsString.unsafeFromChar "hello")) `shouldBe` Just (LazyText.pack "hello")
+        f invalidOsString `shouldBe` Nothing
+
+  describe "Generically" $ do
+    it "converts into empty" $ do
+      -- This only needs to type check.
+      let _ = Witch.from @Void.Void @Empty
+      pure ()
+
+    it "converts into unit" $ do
+      let f = Witch.from @() @Unit
+      f () `shouldBe` MkUnit
+
+    it "converts into only" $ do
+      let f = Witch.from @(Tuple.Solo Int) @(Only Integer)
+      f (Tuple.MkSolo 1) `shouldBe` MkOnly 1
+
+    it "converts into pair" $ do
+      let f = Witch.from @(Int, Int.Int8) @(Pair Integer Age)
+      f (1, 2) `shouldBe` MkPair 1 (MkAge 2)
+
+    it "converts into result" $ do
+      let f = Witch.from @(Either Int Int.Int8) @(Result Integer Age)
+      f (Left 1) `shouldBe` Failure 1
+      f (Right 2) `shouldBe` Success (MkAge 2)
+
+    it "converts into list" $ do
+      let f = Witch.from @[Int] @(List Integer)
+      f [] `shouldBe` Nil
+      f [1] `shouldBe` Cons 1 Nil
+      f [1, 2] `shouldBe` Cons 1 (Cons 2 Nil)
+
+data Empty
+  deriving (Generics.Generic)
+
+deriving via Generics.Generically Empty instance Witch.From Void.Void Empty
+
+data Unit
+  = MkUnit
+  deriving (Eq, Generics.Generic, Show)
+
+deriving via Generics.Generically Unit instance Witch.From () Unit
+
+newtype Only a
+  = MkOnly a
+  deriving (Eq, Generics.Generic, Show)
+
+deriving via
+  Generics.Generically (Only b)
+  instance
+    (Witch.From a b) => Witch.From (Tuple.Solo a) (Only b)
+
+data Pair a b
+  = MkPair a b
+  deriving (Eq, Generics.Generic, Show)
+
+deriving via
+  Generics.Generically (Pair c d)
+  instance
+    (Witch.From a c, Witch.From b d) => Witch.From (a, b) (Pair c d)
+
+data Result a b
+  = Failure a
+  | Success b
+  deriving (Eq, Generics.Generic, Show)
+
+deriving via
+  Generics.Generically (Result c d)
+  instance
+    (Witch.From a c, Witch.From b d) => Witch.From (Either a b) (Result c d)
+
+data List a
+  = Nil
+  | Cons a (List a)
+  deriving (Eq, Generics.Generic, Show)
+
+deriving via
+  Generics.Generically (List b)
+  instance
+    (Witch.From a b) => Witch.From [a] (List b)
+
 newtype Age
-  = Age Int.Int8
+  = MkAge Int.Int8
   deriving (Eq, Show)
 
 instance Witch.From Age Int.Int8
@@ -2458,6 +2615,14 @@
 
 hush :: Either x a -> Maybe a
 hush = either (const Nothing) Just
+
+-- | An 'OsString.OsString' that 'OsString.decodeUtf' cannot decode. On POSIX
+-- this is the lone byte @0xFF@ (invalid UTF-8); on Windows it is the
+-- unpaired surrogate @0xD800@ (invalid UTF-16).
+invalidOsString :: OsString.OsString
+invalidOsString =
+  let c = if Info.os == "mingw32" then '\xD800' else '\xFF'
+   in OsString.pack [OsString.unsafeFromChar c]
 
 it :: (Stack.HasCallStack) => String -> HUnit.Assertion -> Spec
 it label = testToSpec . HUnit.TestLabel label . HUnit.TestCase
diff --git a/witch.cabal b/witch.cabal
--- a/witch.cabal
+++ b/witch.cabal
@@ -1,14 +1,15 @@
 cabal-version: 2.2
-
 name: witch
-version: 1.1.6.1
+version: 1.4.0.0
 synopsis: Convert values from one type into another.
 description: Witch converts values from one type into another.
-
 build-type: Simple
 category: Data
-extra-source-files: CHANGELOG.markdown README.markdown
-license-file: LICENSE.markdown
+extra-doc-files:
+  CHANGELOG.md
+  README.md
+
+license-file: LICENSE.txt
 license: MIT
 maintainer: Taylor Fausak
 
@@ -18,17 +19,18 @@
 
 flag pedantic
   default: False
-  description: Enables @-Werror@, which turns warnings into errors.
   manual: True
 
 common library
+  build-depends: base ^>=4.20.0 || ^>=4.21.0 || ^>=4.22.0
   build-depends:
-    , base >= 4.15 && < 4.18
-    , bytestring >= 0.10.12 && < 0.12
-    , containers >= 0.6.4 && < 0.7
-    , tagged >= 0.8.6 && < 0.9
-    , text >= 1.2.5 && < 1.3 || >= 2.0 && < 2.1
-    , time >= 1.9.3 && < 1.13
+    bytestring ^>=0.12.0,
+    containers ^>=0.7 || ^>=0.8,
+    os-string ^>=2.0,
+    tagged ^>=0.8.8,
+    text ^>=2.1,
+    time ^>=1.12.2 || ^>=1.14 || ^>=1.15,
+
   default-language: Haskell2010
   ghc-options:
     -Weverything
@@ -38,23 +40,20 @@
     -Wno-missing-deriving-strategies
     -Wno-missing-export-lists
     -Wno-missing-exported-signatures
+    -Wno-missing-kind-signatures
+    -Wno-missing-role-annotations
     -Wno-missing-safe-haskell-mode
     -Wno-prepositive-qualified-module
     -Wno-redundant-constraints
     -Wno-safe
     -Wno-unsafe
 
-  if impl(ghc >= 9.2)
-    ghc-options:
-      -Wno-missing-kind-signatures
-
   if flag(pedantic)
     ghc-options:
       -Werror
 
 common executable
   import: library
-
   build-depends: witch
   ghc-options:
     -rtsopts
@@ -62,26 +61,39 @@
 
 library
   import: library
-
   build-depends:
-    , template-haskell >= 2.17 && < 2.20
+    template-haskell ^>=2.22.0 || ^>=2.23.0 || ^>=2.24.0
+
+  -- cabal-gild: discover source/library
   exposed-modules:
     Witch
     Witch.Encoding
     Witch.From
+    Witch.Generic
     Witch.Instances
     Witch.Lift
     Witch.TryFrom
     Witch.TryFromException
     Witch.Utility
+
   hs-source-dirs: source/library
 
 test-suite witch-test-suite
   import: executable
-
   build-depends:
-    , HUnit >= 1.6.1 && < 1.7
-    , transformers >= 0.5.2 && < 0.7
+    HUnit ^>=1.6.2,
+    transformers ^>=0.6.1,
+
   hs-source-dirs: source/test-suite
+  main-is: Main.hs
+  type: exitcode-stdio-1.0
+
+test-suite witch-hedgehog
+  import: executable
+  build-depends:
+    hedgehog ^>=1.7,
+    transformers ^>=0.6.1,
+
+  hs-source-dirs: source/hedgehog
   main-is: Main.hs
   type: exitcode-stdio-1.0
