diff --git a/.travis.yml b/.travis.yml
new file mode 100644
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,115 @@
+# This Travis job script has been generated by a script via
+#
+#   haskell-ci 'winery.cabal' '--output' '.travis.yml'
+#
+# For more information, see https://github.com/haskell-CI/haskell-ci
+#
+# version: 0.2.1
+#
+language: c
+dist: xenial
+
+git:
+  submodules: false  # whether to recursively clone submodules
+
+cache:
+  directories:
+    - $HOME/.cabal/packages
+    - $HOME/.cabal/store
+
+before_cache:
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
+  # remove files that are regenerated by 'cabal update'
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
+  - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
+
+  - rm -rfv $CABALHOME/packages/head.hackage
+
+matrix:
+  include:
+    - compiler: ghc-head
+      addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-head","cabal-install-head"]}}
+      env: GHCHEAD=true
+    - compiler: "ghc-8.6.3"
+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.6.3], sources: [hvr-ghc]}}
+    - compiler: "ghc-8.4.4"
+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.4,ghc-8.4.4], sources: [hvr-ghc]}}
+  allow_failures:
+    - compiler: ghc-head
+
+before_install:
+  - HC=/opt/ghc/bin/${CC}
+  - HCPKG=${HC/ghc/ghc-pkg}
+  - unset CC
+  - CABAL=/opt/ghc/bin/cabal
+  - CABALHOME=$HOME/.cabal
+  - export PATH="$CABALHOME/bin:$PATH"
+  - ROOTDIR=$(pwd)
+  - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))
+  - echo $HCNUMVER
+
+install:
+  - ${CABAL} --version
+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
+  - TEST=--enable-tests
+  - BENCH=--enable-benchmarks
+  - GHCHEAD=${GHCHEAD-false}
+  - travis_retry ${CABAL} update -v
+  - sed -i.bak 's/^jobs:/-- jobs:/' $CABALHOME/config
+  - rm -fv cabal.project cabal.project.local
+  - grep -Ev -- '^\s*--' $CABALHOME/config | grep -Ev '^\s*$'
+  - rm -f cabal.project
+  - touch cabal.project
+  - "printf 'packages: \".\"\\n' >> cabal.project"
+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"
+  - touch cabal.project.local
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(winery)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  - if [ -f "./configure.ac" ]; then (cd "." && autoreconf -i); fi
+  - rm -f cabal.project.freeze
+  - ${CABAL} new-freeze -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dry
+  - "cat \"cabal.project.freeze\" | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
+  - rm  "cabal.project.freeze"
+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dep -j2 all
+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project" --dep -j2 all
+  - rm -rf .ghc.environment.* "."/dist
+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
+
+# Here starts the actual work to be performed for the package under test;
+# any command which exits with a non-zero exit code causes the build to fail.
+script:
+  # test that source-distributions can be generated
+  - ${CABAL} new-sdist all
+  - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
+  - cd ${DISTDIR} || false
+  - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;
+  - rm -f cabal.project
+  - touch cabal.project
+  - "printf 'packages: \"winery-*/*.cabal\"\\n' >> cabal.project"
+  - "printf 'write-ghc-environment-files: always\\n' >> cabal.project"
+  - touch cabal.project.local
+  - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | grep -vE -- '^(winery)$' | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
+  - cat cabal.project || true
+  - cat cabal.project.local || true
+  # this builds all libraries and executables (without tests/benchmarks)
+  - ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all
+
+  # build & run tests, build benchmarks
+  - ${CABAL} new-build -w ${HC} ${TEST} ${BENCH} all
+  - if [ "x$TEST" = "x--enable-tests" ]; then ${CABAL} new-test -w ${HC} ${TEST} ${BENCH} all; fi
+
+  # cabal check
+  - (cd winery-* && ${CABAL} check)
+
+  # haddock
+  - ${CABAL} new-haddock -w ${HC} ${TEST} ${BENCH} all
+
+  # Build without installed constraints for packages in global-db
+  - rm -f cabal.project.local; ${CABAL} new-build -w ${HC} --disable-tests --disable-benchmarks all;
+
+# REGENDATA ["winery.cabal","--output",".travis.yml"]
+# EOF
diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,18 +1,30 @@
-# 1
+## 1.1
 
+* Renamed `Data.Winery` to `Codec.Winery`
+
+## 1.0.2
+
+* `bootstrapSchema` returns `UnsupportedSchemaVersion` rather than an error
+
+## 1.0.1
+
+* Added `bundleSerialise`
+
+## 1
+
 * Changed the encoding more compact
 * Decoders are now stateful
 * Significantly improved the performance
 * `decodeCurrent` is now a method of `Serialise`
 * Added `STag`
 
-# 0.3
+## 0.3
 
 * Supported `UTCTime`
 * Added an instance for lazy `ByteString`
 * Added `toEncodingWithSchema`
 
-# 0.2
+## 0.2
 
 * Renamed `extract*With` to `extract*By` for consistency
 * Added `hPut`
@@ -20,15 +32,15 @@
 * Added `-J` option to `winery` which exports a JSON
 * Decoder now throws `DecodeException` rather than error calls
 
-# 0.1.1
+## 0.1.1
 
 * Add `Data.Winery.Query`
 * The command line tool supports a simple query language
 
-# 0.1
+## 0.1
 
 Overhauled the encoding; Sorry, incompatible with 0
 
-# 0
+## 0
 
 Initial release
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -7,9 +7,9 @@
 import qualified Data.ByteString.Lazy as BL
 import Data.Text.Prettyprint.Doc
 import Data.Text.Prettyprint.Doc.Render.Terminal
-import qualified Data.Winery.Query as Q
-import Data.Winery.Query.Parser
-import Data.Winery
+import qualified Codec.Winery.Query as Q
+import Codec.Winery.Query.Parser
+import Codec.Winery
 import System.Console.GetOpt
 import System.Environment
 import System.Exit
diff --git a/art/logo.png b/art/logo.png
new file mode 100644
Binary files /dev/null and b/art/logo.png differ
diff --git a/art/logo.svg b/art/logo.svg
new file mode 100644
--- /dev/null
+++ b/art/logo.svg
@@ -0,0 +1,1 @@
+<svg id="レイヤー_1" data-name="レイヤー 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{font-size:35.43px;fill:#9a8b5c;font-family:Cardo-Bold, Cardo;font-weight:700;}.cls-2{fill:#4d4545;}.cls-3{fill:#404040;}.cls-4{fill:#643f33;}.cls-5{fill:#bc6974;}.cls-6{fill:#4d4d4d;}.cls-7{fill:#975e4d;}</style></defs><title>logo</title><text class="cls-1" transform="translate(158.38 497.91) scale(1.03 1)">SINCE 2018</text><path class="cls-2" d="M97.13,455c-.69,0-1.15-.42-1.36-1.27q-5-15.6-10-32.12-4.64,15.15-9.3,31.24a3.44,3.44,0,0,1-1,1.81A2.7,2.7,0,0,1,74,455H67.72a1,1,0,0,1-.82-.35,3,3,0,0,1-.53-1.11c-7.69-26.45-15.26-54.8-22.63-85.41a12.21,12.21,0,0,0-1.36-3.4,14.47,14.47,0,0,0-1.88-2.53,17.35,17.35,0,0,0-3.31-2.71,6.21,6.21,0,0,1-.71-.49c-.28-.21-.56-.41-.84-.59l-.74-.5a2.56,2.56,0,0,0-.4-.24c-.22-.08-.33-.3-.33-.68v-3.12c0-.37.11-.52.33-.44q13.85,4.92,27.85,9.2c.17.06.27.14.29.26a1.36,1.36,0,0,1,0,.36c0,.94,0,1.88,0,2.83a1,1,0,0,1-.06.3c0,.11-.13.15-.27.11l-.77-.22A4.52,4.52,0,0,0,59,366.1a2.62,2.62,0,0,0-1.41,1,3.71,3.71,0,0,0-.58,1.69,15.77,15.77,0,0,0-.1,1.74,13.73,13.73,0,0,0,.29,2.76c.19.88.36,1.79.51,2.74C63,396.25,68.23,415.4,73.56,433.66a.92.92,0,0,0,.83.68.43.43,0,0,0,.39-.17,2.79,2.79,0,0,0,.25-.47q3.6-12.36,7.17-24.14-4.89-16.55-9.73-34.1a14.08,14.08,0,0,0-1.74-3.88,8.11,8.11,0,0,0-2.23-2.49,12.88,12.88,0,0,0-1.36-.95,6.12,6.12,0,0,0-1-.53c-.23-.07-.34-.27-.35-.61,0-.93,0-1.86,0-2.8,0-.33.11-.47.33-.4q20.19,6,40.63,10.76a.35.35,0,0,1,.3.24,1.26,1.26,0,0,1,0,.29l0,2.46a1,1,0,0,1,0,.3c0,.09-.13.11-.3.07l-1.59-.35a5.85,5.85,0,0,0-2.72-.05,4.23,4.23,0,0,0-2.1,1.28,9.85,9.85,0,0,0-1.7,2.65,36.12,36.12,0,0,0-1.51,4q-2.52,7.69-5.05,15.63,5.36,17.67,10.76,34.27a.9.9,0,0,0,.83.62c.29,0,.5-.18.64-.59,5.48-17.29,10.94-33.72,16.41-49.44a6.94,6.94,0,0,0,.47-2.44,2.6,2.6,0,0,0-1-2.15,9.3,9.3,0,0,0-3.61-1.3l-2.68-.56c-.23,0-.34-.21-.35-.51l0-2.42a.92.92,0,0,1,0-.26c0-.1.13-.14.3-.1q10.25,2.25,20.53,4.16a.36.36,0,0,1,.31.21,1,1,0,0,1,0,.27c0,.76,0,1.52,0,2.29a.77.77,0,0,1,0,.27c0,.09-.12.11-.3.08l-2-.37a3,3,0,0,0-1.81.17,3.79,3.79,0,0,0-1.43,1.26,12.1,12.1,0,0,0-1.25,2.33c-.4,1-.82,2.07-1.26,3.37-7,19.75-13.9,40.59-20.87,62.84a3,3,0,0,1-1,1.66,2.89,2.89,0,0,1-1.5.31Zm-5.3-76.27a8,8,0,0,0,.34-1.32,6.64,6.64,0,0,0,0-1c0-1.24-1-2.1-2.94-2.59a4.23,4.23,0,0,0-2-.11,2.56,2.56,0,0,0-1.21.65,2.42,2.42,0,0,0-.6,1.13,5.56,5.56,0,0,0-.16,1.33,9,9,0,0,0,.15,1.4c.09.5.25,1.18.47,2.05s.54,2,.94,3.38.93,3.21,1.59,5.43Q90.17,383.84,91.83,378.75Z"/><path class="cls-2" d="M168.63,447.3a4.51,4.51,0,0,0,1.33,1.8,5.19,5.19,0,0,0,2.09,1,12.17,12.17,0,0,0,2.75.31c.23,0,.35.13.35.39,0,.86,0,1.71,0,2.57a.77.77,0,0,1,0,.27c0,.08-.13.11-.3.11l-25.56-.07a.27.27,0,0,1-.28-.15.56.56,0,0,1-.07-.25l-.05-2.72a.74.74,0,0,1,.06-.25.27.27,0,0,1,.28-.15A15.44,15.44,0,0,0,152,450a4.24,4.24,0,0,0,2.09-.95,4.64,4.64,0,0,0,1.3-2.11,11.87,11.87,0,0,0,.41-3.76q-.41-25-.83-49.92a8.41,8.41,0,0,0-.5-2.89,5.76,5.76,0,0,0-1.34-2A6.33,6.33,0,0,0,151,387a12.88,12.88,0,0,0-2.77-.73.41.41,0,0,1-.35-.46c0-.9,0-1.81,0-2.72,0-.26.11-.38.34-.34q12.84,2.1,25.74,3.7a.34.34,0,0,1,.29.18.8.8,0,0,1,.07.25c0,.86,0,1.72,0,2.57a.46.46,0,0,1-.07.23c0,.1-.13.13-.28.11a16.72,16.72,0,0,0-2.76-.11,3.83,3.83,0,0,0-2.1.68,3.73,3.73,0,0,0-1.32,1.91,10.44,10.44,0,0,0-.42,3.61q.39,24.33.77,48.67A7.4,7.4,0,0,0,168.63,447.3Z"/><path class="cls-2" d="M190.76,453.65a.38.38,0,0,1-.14-.25c0-.69,0-1.37,0-2,0-.25.11-.37.34-.37H192c.4,0,.8,0,1.19,0l1.06-.09a2,2,0,0,0,.73-.18,4.93,4.93,0,0,0,1.76-1.46,6.69,6.69,0,0,0,1-2.11,12.86,12.86,0,0,0,.47-2.62c.07-.95.11-2,.09-3q-.27-23-.55-45.93a2.71,2.71,0,0,0-1-2.08,7.77,7.77,0,0,0-2.2-1.34,15.52,15.52,0,0,0-2.55-.76c-.86-.17-1.51-.27-1.94-.32a.31.31,0,0,1-.29-.16.75.75,0,0,1-.07-.24c0-.68,0-1.36,0-2.05a.56.56,0,0,1,.06-.22c0-.09.13-.13.28-.11q9.9,1,19.83,1.65c12.73,15.27,25.37,29.61,37.88,43.74a3.74,3.74,0,0,1,.31.33.26.26,0,0,0,.21.11c.12,0,.19,0,.22-.13a.84.84,0,0,0,0-.27l0-26.3a66.87,66.87,0,0,0-.32-7,10.48,10.48,0,0,0-1.15-4,4,4,0,0,0-2.24-1.86,12.42,12.42,0,0,0-3.6-.51l-2.23,0a.32.32,0,0,1-.29-.14.6.6,0,0,1-.06-.23c0-.65,0-1.3,0-2a.56.56,0,0,1,.06-.22.29.29,0,0,1,.29-.13q12.06.28,24.14.14c.17,0,.28,0,.3.13a.68.68,0,0,1,.05.22v1.95a.67.67,0,0,1-.07.22.29.29,0,0,1-.29.13,10.15,10.15,0,0,0-2.26.38,13.59,13.59,0,0,0-2.69,1,8.32,8.32,0,0,0-2.26,1.64,3.11,3.11,0,0,0-.95,2.22v52.35a2.13,2.13,0,0,1-.35,1.26,2.66,2.66,0,0,1-.88.82,4.26,4.26,0,0,1-1.17.46,4.53,4.53,0,0,1-1.15.16,6.68,6.68,0,0,1-2-.38,5.34,5.34,0,0,1-2.27-1.66c-13.64-15.46-27.44-31.06-41.35-47.75a3.15,3.15,0,0,0-.44-.41.85.85,0,0,0-.35-.09c-.15,0-.22.14-.22.45q.22,20.34.44,40.7a4.14,4.14,0,0,0,.61,2.22,5.75,5.75,0,0,0,1.51,1.6,7.69,7.69,0,0,0,2,1.06,17,17,0,0,0,2.17.62,12.73,12.73,0,0,0,1.9.3c.57.05,1,.08,1.28.08a.3.3,0,0,1,.3.18.41.41,0,0,1,.05.18c0,.66,0,1.32,0,2a.46.46,0,0,1-.07.23c0,.09-.13.13-.28.13q-11.89,0-23.78,0A.35.35,0,0,1,190.76,453.65Z"/><path class="cls-2" d="M274.07,451.56a.82.82,0,0,1,0-.2c0-.11.13-.16.31-.16h.95c1.21-.09,2.45-.15,3.72-.17a12.11,12.11,0,0,0,3.47-.5,5.25,5.25,0,0,0,2.56-1.66,5.71,5.71,0,0,0,1-3.7l.33-45.86a5,5,0,0,0-.68-2.82A5.09,5.09,0,0,0,284,394.8a9.14,9.14,0,0,0-2.58-.9q-1.45-.27-2.94-.45l-.92,0c-.15,0-.24,0-.28-.12a.46.46,0,0,1-.07-.22c0-.58,0-1.16,0-1.74a.46.46,0,0,1,.07-.22.28.28,0,0,1,.28-.14q21.85-.77,43.64-3a1.6,1.6,0,0,1,1.13.19,1.82,1.82,0,0,1,.42,1.28q.28,7.44.58,14.89c0,.15-.13.28-.37.38a2.93,2.93,0,0,1-.68.17,3.29,3.29,0,0,1-.7,0,.73.73,0,0,1-.47-.25,3.15,3.15,0,0,1-.42-1.34c-.08-.6-.17-1.26-.26-2s-.23-1.5-.4-2.29a7.88,7.88,0,0,0-.83-2.16,4.87,4.87,0,0,0-1.52-1.65,5.11,5.11,0,0,0-2.5-.83q-7.8.66-15.62,1.15a.55.55,0,0,0-.57.62l-.21,21.6c0,.31.14.45.43.44q6.22-.24,12.46-.55a8.24,8.24,0,0,0,2.16-.41,4.72,4.72,0,0,0,1.88-1.18,6.4,6.4,0,0,0,1.34-2.28,11.62,11.62,0,0,0,.54-3.67c0-.24.12-.38.36-.39l1.7-.12c.23,0,.34.11.34.35q-.14,10.66-.28,21.31c0,.16-.05.26-.14.31a.49.49,0,0,1-.22.08l-1.69.06c-.14,0-.24,0-.28-.13a.6.6,0,0,1-.06-.23,14.23,14.23,0,0,0-.45-4.18,6.1,6.1,0,0,0-1.29-2.44,3.71,3.71,0,0,0-1.88-1.12,8.17,8.17,0,0,0-2.23-.21q-6.17.27-12.32.46c-.29,0-.43.17-.43.47q-.1,9.9-.2,19.79a4.84,4.84,0,0,0,.37,2.11,2.85,2.85,0,0,0,1.05,1.19,4.21,4.21,0,0,0,1.53.53,10.77,10.77,0,0,0,1.82.12l11.82-.1a7.07,7.07,0,0,0,4.22-1.28,10.34,10.34,0,0,0,2.77-3.05,15,15,0,0,0,1.59-3.72,22.15,22.15,0,0,0,.67-3.3,1.45,1.45,0,0,1,.58-1,1.93,1.93,0,0,1,1.09-.39,1.2,1.2,0,0,1,.52.17.49.49,0,0,1,.29.42q-.84,8.64-1.67,17.23a1.61,1.61,0,0,1-.25.44.43.43,0,0,1-.37.22q-25.06,0-50.13.06-.25,0-.3-.15a.92.92,0,0,1,0-.2v-.63C274.06,452.42,274.07,452,274.07,451.56Z"/><path class="cls-2" d="M341.17,451.21a1.16,1.16,0,0,1,.05-.22c0-.11.13-.17.31-.17a5.3,5.3,0,0,0,.82-.11l1.17-.2c.41-.07.78-.15,1.13-.23l.74-.18a5.77,5.77,0,0,0,3.47-2.12,6.4,6.4,0,0,0,1-3.63q.42-25,.83-50a6.45,6.45,0,0,0-.85-3.76,5.18,5.18,0,0,0-2.08-1.85,5.89,5.89,0,0,0-2.29-.57,14.27,14.27,0,0,0-1.5,0l-1.66.22a.25.25,0,0,1-.28-.11.6.6,0,0,1-.06-.23c0-.71,0-1.42,0-2.13a.64.64,0,0,1,0-.22c0-.09.13-.16.31-.21l.2,0,.63-.11,1.39-.24,2.58-.43c1.59-.26,3.3-.56,5.11-.9l5.51-1.05,5.5-1.08,5.1-1,4.38-.79a17.69,17.69,0,0,1,6.95.1,14.93,14.93,0,0,1,6.35,3,16.33,16.33,0,0,1,4.6,6.16,22.07,22.07,0,0,1,1.67,9.46,25.43,25.43,0,0,1-.88,6.51,21.11,21.11,0,0,1-2.22,5.2,20,20,0,0,1-3.3,4.11,28.9,28.9,0,0,1-4.13,3.24q6.33,12.08,12.67,25a32.85,32.85,0,0,0,3.83,6.11,11.91,11.91,0,0,0,5.17,3.87c.23.08.37.18.41.31a1.65,1.65,0,0,1,.06.48,1.46,1.46,0,0,1-.36,1.13,1.73,1.73,0,0,1-1.09.28,32.19,32.19,0,0,1-4.12-.3,31,31,0,0,1-4.64-1,24.61,24.61,0,0,1-4.4-1.75,11.54,11.54,0,0,1-3.48-2.65,24.41,24.41,0,0,1-2.75-3.73q-1.38-2.25-2.79-4.82c-.94-1.7-1.86-3.47-2.76-5.29s-1.79-3.59-2.64-5.31-1.66-3.3-2.44-4.76-1.5-2.69-2.15-3.7l-6.74,0-.35,0a.73.73,0,0,0-.43.13.67.67,0,0,0-.18.22,1.13,1.13,0,0,0,0,.4q-.18,10.77-.37,21.53a8.43,8.43,0,0,0,.26,2.37,4,4,0,0,0,1,1.72,5.06,5.06,0,0,0,1.84,1.17,13.3,13.3,0,0,0,2.78.68l.75.14,1.08.22c.39.08.77.16,1.14.22a6.22,6.22,0,0,0,.95.09q.27,0,.3.15a1,1,0,0,1,0,.26l0,2.28a.6.6,0,0,1-.07.26.28.28,0,0,1-.28.16l-30.49.09c-.14,0-.23-.23-.27-.68s0-.87,0-1.25Zm21.61-34.59a2.25,2.25,0,0,0,.19.71.62.62,0,0,0,.62.33l1.16.07a14.19,14.19,0,0,0,2.17-.06,13.55,13.55,0,0,0,6.3-2,12.46,12.46,0,0,0,4-4.18,17.7,17.7,0,0,0,2.06-5.72,37.85,37.85,0,0,0,.65-6.54,22.44,22.44,0,0,0-.79-6.54,14.48,14.48,0,0,0-2.44-5,9.52,9.52,0,0,0-3.84-3,8.72,8.72,0,0,0-5-.48c-.41.06-.73.13-1,.18l-.67.16-.74.18-1.15.26a2.8,2.8,0,0,0-.68.24.75.75,0,0,0-.42.75q-.25,14.55-.5,29.1Z"/><path class="cls-2" d="M436,422.67a1.28,1.28,0,0,0-.12-.6c-5.73-12.92-11.42-25.1-17.1-36.67q-.71-1.42-1.53-2.85a17.8,17.8,0,0,0-1.8-2.62,10.59,10.59,0,0,0-2.15-2,5.37,5.37,0,0,0-2.54-.93l-.68,0c-.31,0-.64,0-1,0h-1l-.68,0c-.29,0-.56-.14-.81-.52a1.85,1.85,0,0,1-.37-1.07c0-.07,0-.21,0-.4a3.44,3.44,0,0,1,.09-.56,2.18,2.18,0,0,1,.2-.5.57.57,0,0,1,.35-.28Q421.52,370.12,436,366c.31-.09.51.06.59.45a5.4,5.4,0,0,1,.12,1.08c0,.41,0,.85-.08,1.32s-.21.74-.5.82l-2.17.84a5.88,5.88,0,0,0-1.76,1,4.67,4.67,0,0,0-1.16,1.68,6.85,6.85,0,0,0-.46,2.67,5.59,5.59,0,0,0,.48,2.49q6.36,13.38,12.75,27.9c.31.67.51,1.09.61,1.24a.43.43,0,0,0,.49.18c.2,0,.38-.23.54-.59s.36-.85.59-1.44q5.27-13.95,10.45-28.85c.4-1.12.81-2.36,1.23-3.71a14.15,14.15,0,0,0,.63-4,10.58,10.58,0,0,0-.3-2.87,2.48,2.48,0,0,0-1-1.41,2.7,2.7,0,0,0-1.54-.39,17.53,17.53,0,0,0-2.09.18c-.31.05-.49-.16-.55-.62a9.91,9.91,0,0,1-.07-1.29,8.72,8.72,0,0,1,.11-1.18,1,1,0,0,1,.62-.88q10.64-3.37,21.19-7.12c.22-.08.38.13.46.65a7.16,7.16,0,0,1,.13,1.12,3.09,3.09,0,0,1-.27,1.3,4.45,4.45,0,0,1-.68,1,5.12,5.12,0,0,1-.84.78l-.82.59a14.53,14.53,0,0,0-3.64,3.73,42.54,42.54,0,0,0-3,5.31c-.14.27-.34.7-.61,1.27s-.42.92-.45,1q-8.25,25.08-16.72,47.52-.07,11.42-.17,22.81a11.16,11.16,0,0,0,1.3,6q1.32,2.1,4.73,2.57a8.5,8.5,0,0,0,1.21,0l1.25,0a.26.26,0,0,1,.28.2,1.16,1.16,0,0,1,.06.33c0,1,0,2,0,2.92a1,1,0,0,1-.07.34.27.27,0,0,1-.28.2l-29.44.16a.27.27,0,0,1-.28-.18,1,1,0,0,1-.06-.3l0-2.66a1.05,1.05,0,0,1,.07-.3.3.3,0,0,1,.28-.19l1.24,0a8.14,8.14,0,0,0,1.23-.08,6.61,6.61,0,0,0,4.78-2.61,10.79,10.79,0,0,0,1.39-5.81Q435.93,432,436,422.67Z"/><path class="cls-3" d="M51.11,81.26a6.26,6.26,0,0,1-1,2.52,7.52,7.52,0,0,1-2.07,2.11,14,14,0,0,1-3,1.58,16.53,16.53,0,0,1-2.61.8,11.41,11.41,0,0,1-1.91.26,7.31,7.31,0,0,1-1.23,0,1.49,1.49,0,0,0-.51,0c-.06,0-.15.2-.26.51s-.2.61-.28.88L38,90q-1.2-2.88-2.38-5.76l.3-.12a11.08,11.08,0,0,0,1.3,1.26,15.75,15.75,0,0,0,1.48,1,9.13,9.13,0,0,0,1.51.74,5.93,5.93,0,0,0,1.37.34,10.18,10.18,0,0,0,1.57,0,6.32,6.32,0,0,0,1.74-.37,5.88,5.88,0,0,0,3.19-2.56,4.26,4.26,0,0,0,.21-3.73,3.51,3.51,0,0,0-2-2.13,5.19,5.19,0,0,0-1.42-.36,13.83,13.83,0,0,0-1.6-.06l-1.46,0-1.16.06-1.11,0c-.38,0-.84,0-1.38,0a7.88,7.88,0,0,1-1.85-.2,6.86,6.86,0,0,1-1.76-.69,6.43,6.43,0,0,1-1.49-1.16,5,5,0,0,1-1-1.63,6.09,6.09,0,0,1-.46-3,6,6,0,0,1,.91-2.54,7.68,7.68,0,0,1,2-2.06,11.41,11.41,0,0,1,2.74-1.47,12.34,12.34,0,0,1,2.5-.7,10.88,10.88,0,0,1,1.84-.13,5.31,5.31,0,0,1,1.15.12,3.22,3.22,0,0,0,.45.09c.06,0,.15-.19.26-.5s.21-.61.29-.91l.35-.13L46,69l-.35.13A11.5,11.5,0,0,0,44,67.58a8.94,8.94,0,0,0-2-1.19,7.14,7.14,0,0,0-2.25-.55,5.52,5.52,0,0,0-2.4.38,6.68,6.68,0,0,0-1.74,1,4.53,4.53,0,0,0-1.2,1.36,4,4,0,0,0-.5,1.69,4.41,4.41,0,0,0,.33,1.91,3.5,3.5,0,0,0,2,2.09,7.71,7.71,0,0,0,3.14.5c.47,0,.91,0,1.31,0l1.2-.07c.39,0,.78,0,1.19-.06l1.27,0a7.58,7.58,0,0,1,4,.93,5.57,5.57,0,0,1,2.43,3.06A5.71,5.71,0,0,1,51.11,81.26Z"/><path class="cls-3" d="M75.06,76.7q-9.41,3-18.72,6.37l-.11-.3a6.75,6.75,0,0,0,1.28-.89,2.92,2.92,0,0,0,.82-1.12,1.52,1.52,0,0,0,.07-.6c0-.25-.06-.53-.11-.85a9.37,9.37,0,0,0-.22-1c-.1-.34-.2-.66-.31-1s-.22-.66-.38-1.13l-.51-1.56c-.19-.57-.39-1.14-.6-1.74s-.41-1.18-.6-1.71l-2-5.76c-.12-.35-.26-.71-.4-1.08s-.29-.72-.43-1a5.15,5.15,0,0,0-.48-.85,1.27,1.27,0,0,0-.5-.47,2.45,2.45,0,0,0-1.23-.25,13.81,13.81,0,0,0-1.48.25l-.1-.3q8.71-3.12,17.51-6,1.89,2.1,3.75,4.22l-.27.25a15.54,15.54,0,0,0-6.13-2.48,8.25,8.25,0,0,0-2.14.25,28.14,28.14,0,0,0-3.62,1c-.44.15-.9.32-1.36.51s-.8.35-1,.46c.07.33.26,1,.57,2s.69,2.15,1.14,3.45l.65,1.9c.18.51.33.93.45,1.25s.22.57.28.75l.11.32.62-.21c.31-.11.67-.24,1.07-.4l1.19-.49a8.77,8.77,0,0,0,1-.48A5.66,5.66,0,0,0,64.18,67a3.43,3.43,0,0,0,.73-1.2,4.34,4.34,0,0,0,.24-1.38,16.11,16.11,0,0,0-.07-1.64l.37-.12Q67,67.33,68.55,72l-.38.12a9.82,9.82,0,0,0-1.41-1.71,5.26,5.26,0,0,0-1.58-1.15A4.22,4.22,0,0,0,63.76,69a6,6,0,0,0-1.75.22l-.8.23-.62.19-.63.22-.81.28a11.2,11.2,0,0,0,.36,1.23c.19.53.38,1.09.57,1.66l.31.89.35,1q.16.48.33.9l.26.72c.24.62.48,1.21.73,1.75a2.89,2.89,0,0,0,.78,1.14,2.09,2.09,0,0,0,1.52.14A15.31,15.31,0,0,0,66.69,79L68,78.49a16.54,16.54,0,0,0,1.65-.72,6.94,6.94,0,0,0,1.66-1.06,6.51,6.51,0,0,0,1.29-1.49,10.46,10.46,0,0,0,1-2,23.06,23.06,0,0,0,.8-2.68l.37,0Q74.92,73.61,75.06,76.7Z"/><path class="cls-3" d="M95.88,70.43l-.52-.3a3.74,3.74,0,0,1-.37-.24c-.13-.09-.31-.23-.53-.41s-.56-.47-1-.83L92,67.43c-.44-.37-.87-.73-1.31-1.08s-.91-.7-1.4-1-1.08-.73-1.74-1.14a12.51,12.51,0,0,0-1.75-.89A3.54,3.54,0,0,0,84,63a5.58,5.58,0,0,0-.94.15c-.19.06-.44.12-.73.19l1,3.39c.29,1,.54,1.76.76,2.42s.4,1.17.56,1.63a2.3,2.3,0,0,0,.68,1,3,3,0,0,0,1.2.51,4.67,4.67,0,0,0,2.12-.12l.09.3q-5,1.45-9.87,3l-.09-.3a9.26,9.26,0,0,0,1.36-.82A2.54,2.54,0,0,0,81,73.31a1.37,1.37,0,0,0,.08-.61,5.51,5.51,0,0,0-.11-.85c-.06-.31-.13-.64-.22-1s-.17-.67-.27-1-.2-.66-.33-1.14-.29-1-.46-1.58-.34-1.16-.52-1.76-.37-1.2-.54-1.73c-.59-1.95-1.19-3.89-1.79-5.84-.11-.36-.23-.72-.35-1.09s-.26-.7-.39-1a4.82,4.82,0,0,0-.44-.85,1.19,1.19,0,0,0-.48-.49,2.46,2.46,0,0,0-1.27-.31,11.23,11.23,0,0,0-1.54.17l-.09-.3,1.31-.41,2.45-.78,2.75-.85,2.24-.67c1.43-.43,2.72-.76,3.85-1a8.09,8.09,0,0,1,3.28-.07A6.3,6.3,0,0,1,91,51.39a5.09,5.09,0,0,1,1.7,2.76,4.84,4.84,0,0,1,.14,2.12,5.66,5.66,0,0,1-.7,1.89,7.55,7.55,0,0,1-1.33,1.63,15.16,15.16,0,0,1-1.76,1.39l0,.09a3.78,3.78,0,0,1,1.26.48,10.06,10.06,0,0,1,1.3.86l2.48,2c.88.71,1.67,1.33,2.36,1.87a9.84,9.84,0,0,0,2.87,1.68,6.5,6.5,0,0,0,2.81.24l.08.3Q99.06,69.52,95.88,70.43ZM87.43,52.55a5.6,5.6,0,0,0-2.88-1.18,7.39,7.39,0,0,0-1.76,0,10.37,10.37,0,0,0-1.82.38c-.45.13-.81.25-1.08.35l-.62.25a2.24,2.24,0,0,1,0,.34q0,.14.06.36c0,.14.08.34.14.59s.16.61.28,1.08c.18.71.41,1.5.66,2.38l.75,2.55c.25.82.47,1.54.65,2.16s.3,1,.35,1.14c.86-.26,1.65-.53,2.37-.82a11.25,11.25,0,0,0,2-1.08,6.25,6.25,0,0,0,1.5-1.31,4.92,4.92,0,0,0,1.13-3.1A5.78,5.78,0,0,0,89,55,4.84,4.84,0,0,0,87.43,52.55Z"/><path class="cls-3" d="M103.35,68.37l-.08-.3a6.46,6.46,0,0,0,1.34-.78,3.13,3.13,0,0,0,.93-1.09,1.08,1.08,0,0,0,.1-.57,5.25,5.25,0,0,0-.08-.82c0-.31-.11-.64-.19-1s-.15-.67-.24-1-.17-.67-.29-1.16-.24-1-.38-1.59-.29-1.17-.45-1.78-.32-1.21-.46-1.76c-.52-2-1-3.93-1.55-5.9l-.28-1.09a9.84,9.84,0,0,0-.32-1,5.15,5.15,0,0,0-.36-.81,1.38,1.38,0,0,0-.45-.52,2.74,2.74,0,0,0-1.31-.45,7.32,7.32,0,0,0-1.58.09l-.08-.31q4.81-1.29,9.65-2.5l.08.31a8.09,8.09,0,0,0-1.37.7,2.08,2.08,0,0,0-1,1.27,3,3,0,0,0,0,1.38q.18.8.33,1.5c.13.51.25,1,.37,1.51s.24,1,.37,1.5l.4,1.58c.14.53.28,1.1.44,1.73.59,2.28,1.17,4.57,1.76,6.85.15.59.3,1.15.46,1.69a2.22,2.22,0,0,0,.58,1.08,2.38,2.38,0,0,0,1.39.49,6.44,6.44,0,0,0,1.54,0l.08.3Q108.06,67.11,103.35,68.37Z"/><path class="cls-3" d="M129,62.11l-.07-.31a2.49,2.49,0,0,0,.45-.16,3.73,3.73,0,0,0,.7-.38,2.21,2.21,0,0,0,.6-.58.92.92,0,0,0,.14-.76,3.68,3.68,0,0,0-.37-.87c-.2-.39-.48-.87-.82-1.42s-.73-1.17-1.16-1.85-.9-1.37-1.4-2.09c-2.81.62-5.63,1.26-8.44,1.93-.13.84-.26,1.65-.39,2.42s-.25,1.55-.38,2.33a7.78,7.78,0,0,0-.1,2.47.91.91,0,0,0,.41.59,1.87,1.87,0,0,0,.74.28,3.83,3.83,0,0,0,.9,0l.9-.07.07.31q-3.33.78-6.65,1.61l-.08-.34a3.58,3.58,0,0,0,1.28-.77,2.83,2.83,0,0,0,.56-.62,6.9,6.9,0,0,0,.48-1.18,23,23,0,0,0,.65-2.64c.21-1,.45-2.26.71-3.61s.52-2.73.81-4.16.55-2.87.83-4.31.54-2.8.79-4.06c-.16-.19-.32-.39-.47-.59a5.57,5.57,0,0,0,.91-.82,5.76,5.76,0,0,0,.67-.89,6.89,6.89,0,0,0,.44-.84c.11-.26.2-.47.25-.63l.26-.06c1.05,1.54,2.05,3,3,4.39s1.84,2.72,2.69,4,1.67,2.53,2.46,3.74,1.58,2.4,2.36,3.58c.37.58.69,1.06,1,1.44l1,1.28.37.37a3.92,3.92,0,0,0,.72.5,3.43,3.43,0,0,0,1,.39,3.38,3.38,0,0,0,1.31,0l.08.37Q133.56,61.11,129,62.11Zm-8.32-17.57c-.07.29-.16.75-.28,1.38s-.26,1.38-.44,2.28-.36,1.91-.56,3-.41,2.35-.63,3.67q3.94-.93,7.91-1.81L125,50.6c-.58-.84-1.14-1.64-1.69-2.4l-1.48-2.11Z"/><path class="cls-3" d="M159.2,56.24Q149.07,57.93,139,60l-.06-.31a8.73,8.73,0,0,0,1.48-.71,3,3,0,0,0,1.06-1,1.61,1.61,0,0,0,.16-.59,4.73,4.73,0,0,0,0-.85c0-.32,0-.64-.08-1a8.48,8.48,0,0,0-.15-1q-.09-.42-.21-1.17c-.09-.49-.19-1-.29-1.62s-.22-1.18-.34-1.8-.24-1.22-.35-1.78l-1.17-6-.21-1.07c-.08-.37-.16-.71-.26-1a5.89,5.89,0,0,0-.31-.82,1.38,1.38,0,0,0-.41-.52,3,3,0,0,0-1.38-.56,7.23,7.23,0,0,0-1.68,0l-.06-.31q5.19-1.05,10.4-2l.06.31c-.28.1-.6.22-1,.38a4.08,4.08,0,0,0-1,.6,2.77,2.77,0,0,0-.75,1,2.46,2.46,0,0,0-.15,1.41c.12.72.22,1.38.33,2s.2,1.18.3,1.76.21,1.17.32,1.79.25,1.3.4,2.06.25,1.33.36,1.9.21,1.1.31,1.63.21,1.08.33,1.64.25,1.2.38,1.89.29,1.27.44,1.86a2.74,2.74,0,0,0,.58,1.26,1.21,1.21,0,0,0,.56.21,4.64,4.64,0,0,0,1,.09q.56,0,1.2,0a10.75,10.75,0,0,0,1.27-.16l.8-.16c.37-.07.77-.17,1.2-.28s.88-.24,1.34-.38a9.11,9.11,0,0,0,1.18-.46,7.64,7.64,0,0,0,1.95-1.26,7,7,0,0,0,1.22-1.53,7.76,7.76,0,0,0,.75-1.75c.18-.61.35-1.24.5-1.9l.34,0Z"/><path class="cls-3" d="M162.45,55.71l0-.31a6.5,6.5,0,0,0,1.41-.64,3.25,3.25,0,0,0,1-1,1.34,1.34,0,0,0,.15-.56,5.58,5.58,0,0,0,0-.82,8.67,8.67,0,0,0-.09-1c0-.34-.09-.67-.14-1l-.17-1.17c-.06-.5-.14-1-.22-1.63s-.17-1.19-.27-1.81-.19-1.24-.28-1.8c-.31-2-.63-4-.94-6-.06-.37-.12-.74-.17-1.11a8.83,8.83,0,0,0-.22-1,5.16,5.16,0,0,0-.28-.84,1.27,1.27,0,0,0-.39-.56,2.58,2.58,0,0,0-1.25-.58,7.14,7.14,0,0,0-1.57-.08l-.05-.31c3.27-.53,6.53-1,9.81-1.5l0,.31a8.32,8.32,0,0,0-1.43.55A2.14,2.14,0,0,0,166.31,34a2.9,2.9,0,0,0-.11,1.38q.11.81.18,1.53t.21,1.53c.07.51.14,1,.22,1.54s.16,1,.24,1.61.17,1.12.27,1.76l1.05,7c.09.59.19,1.17.29,1.72a2.28,2.28,0,0,0,.46,1.14,2.4,2.4,0,0,0,1.33.62,6.66,6.66,0,0,0,1.54.13l0,.31C168.84,54.7,165.64,55.19,162.45,55.71Z"/><path class="cls-3" d="M191.08,48.28a6,6,0,0,1-1.49,2.22,7.59,7.59,0,0,1-2.47,1.55,13.47,13.47,0,0,1-3.28.81,16.7,16.7,0,0,1-2.69.15,9.43,9.43,0,0,1-1.89-.21,6.94,6.94,0,0,1-1.16-.33,1.46,1.46,0,0,0-.49-.15c-.07,0-.19.15-.36.42s-.34.54-.48.8l-.28,0c-.32-2-.63-4.1-1-6.15l.32-.05a10.28,10.28,0,0,0,1,1.53A14.13,14.13,0,0,0,178,50.26a8.26,8.26,0,0,0,1.28,1.07,5.76,5.76,0,0,0,1.23.66,9.52,9.52,0,0,0,1.5.38,6.2,6.2,0,0,0,5.41-1.66,4.36,4.36,0,0,0,1.07-3.58,3.84,3.84,0,0,0-.47-1.49,3.54,3.54,0,0,0-.92-1,5,5,0,0,0-1.27-.69,13.49,13.49,0,0,0-1.52-.44q-.81-.19-1.41-.3L181.76,43c-.35-.07-.7-.15-1.07-.21s-.82-.17-1.33-.29a7.25,7.25,0,0,1-1.73-.64,6.87,6.87,0,0,1-1.53-1.09,6.72,6.72,0,0,1-1.16-1.48,5,5,0,0,1-.61-1.83,6.17,6.17,0,0,1,.25-3A6,6,0,0,1,176,32.18a7.43,7.43,0,0,1,2.36-1.52,12.63,12.63,0,0,1,5.53-.85,9.94,9.94,0,0,1,1.79.31,5.39,5.39,0,0,1,1.07.39,2.6,2.6,0,0,0,.41.19c.07,0,.19-.15.37-.42s.34-.54.49-.81l.36,0c.22,1.92.43,3.84.65,5.75l-.36,0a12.74,12.74,0,0,0-1.24-1.92,9.47,9.47,0,0,0-1.66-1.63,6.87,6.87,0,0,0-2-1.07,5.31,5.31,0,0,0-2.4-.21,6.29,6.29,0,0,0-1.88.52A4.5,4.5,0,0,0,178,32a3.9,3.9,0,0,0-.87,1.52A4.53,4.53,0,0,0,177,35.4a3.52,3.52,0,0,0,1.39,2.5,7.71,7.71,0,0,0,2.89,1.24c.45.11.87.2,1.27.28l1.16.22,1.15.22,1.23.26A7.42,7.42,0,0,1,189.79,42a5.59,5.59,0,0,1,1.62,3.55A5.65,5.65,0,0,1,191.08,48.28Z"/><path class="cls-3" d="M208.48,50.08l0-.32a2.19,2.19,0,0,0,.45-.1,3.65,3.65,0,0,0,.75-.28,2,2,0,0,0,.66-.49.94.94,0,0,0,.25-.74,3.85,3.85,0,0,0-.25-.91c-.15-.42-.36-.92-.62-1.52s-.56-1.26-.9-2-.71-1.48-1.1-2.27q-4.29.36-8.58.78c-.24.82-.48,1.6-.71,2.35s-.45,1.49-.68,2.25a8.08,8.08,0,0,0-.43,2.44,1,1,0,0,0,.32.64,2,2,0,0,0,.7.37,3.61,3.61,0,0,0,.88.16l.89.06,0,.31c-2.25.22-4.51.45-6.76.7l0-.34a3.81,3.81,0,0,0,1.37-.59,2.88,2.88,0,0,0,.63-.54A6.61,6.61,0,0,0,196,49a24.73,24.73,0,0,0,1-2.52c.34-1,.74-2.19,1.17-3.49s.88-2.64,1.35-4,.93-2.77,1.39-4.16.91-2.7,1.33-3.91l-.39-.66a5.28,5.28,0,0,0,1-.69,5.8,5.8,0,0,0,.78-.79,6.1,6.1,0,0,0,.54-.77,5.79,5.79,0,0,0,.33-.59l.27,0,2.36,4.75q1.11,2.25,2.11,4.34c.67,1.39,1.31,2.74,1.93,4L213,44.32a16.07,16.07,0,0,0,.78,1.56l.79,1.4c0,.08.16.22.32.42a4.17,4.17,0,0,0,.64.59,3.37,3.37,0,0,0,.94.52,3.52,3.52,0,0,0,1.3.19l0,.38Q213.14,49.7,208.48,50.08Zm-5.87-18.54c-.1.28-.26.73-.45,1.33s-.45,1.34-.74,2.21-.61,1.84-1,2.93-.71,2.28-1.11,3.55q4-.39,8-.72c-.45-.91-.9-1.81-1.36-2.72s-.9-1.77-1.33-2.6-.83-1.59-1.19-2.28S202.85,32,202.61,31.54Z"/><path class="cls-3" d="M240.69,31.61c-.19-.37-.41-.76-.66-1.16s-.51-.77-.78-1.12-.51-.66-.77-1a4.94,4.94,0,0,0-.64-.65,3.6,3.6,0,0,0-1.53-.78,9.49,9.49,0,0,0-2.08-.16l-1.09,0-.92,0-1,0-1.22.06c0,.52.05,1.23.08,2.12s.07,1.84.11,2.82.09,1.95.13,2.91.08,1.73.11,2.37c.1,2.32.21,4.63.31,7,0,.6.07,1.18.13,1.73a2.29,2.29,0,0,0,.36,1.16,2.39,2.39,0,0,0,1.4.88c.59.14,1.12.24,1.59.31v.31q-5.18.21-10.35.5l0-.31a10.15,10.15,0,0,0,1.58-.4,3.27,3.27,0,0,0,1.44-1.11,1,1,0,0,0,.21-.53c0-.24.07-.52.09-.82s0-.63,0-1,0-.7,0-1,0-.68,0-1.16,0-1-.05-1.59,0-1.19-.07-1.82-.06-1.22-.09-1.78q-.27-5.18-.53-10.35l-1.22.06-1,.06-.91.06c-.32,0-.68.06-1.1.08a7.7,7.7,0,0,0-2.05.41,3.84,3.84,0,0,0-1.44,1,4.22,4.22,0,0,0-.57.7c-.21.31-.43.64-.66,1a10.62,10.62,0,0,0-.65,1.16,6.31,6.31,0,0,0-.46,1.19l-.3-.08c.19-2,.39-4,.58-6,.52.07,1,.13,1.42.16a16,16,0,0,0,1.88,0l2.25-.09,1.91-.09,1.89-.1,2.21-.11,2.18-.1,1.92-.1,1.91-.11c.66,0,1.41-.07,2.25-.1a10.63,10.63,0,0,0,1.8-.23c.47-.11,1-.24,1.46-.4L241,31.51Z"/><path class="cls-3" d="M243.29,48.2v-.31a7.5,7.5,0,0,0,1.48-.44,3.32,3.32,0,0,0,1.15-.84,1.35,1.35,0,0,0,.23-.54c0-.23.08-.5.11-.82s0-.64,0-1,0-.69,0-1,0-.69,0-1.19V40.42c0-.6,0-1.21,0-1.84s0-1.25,0-1.81l-.12-6.1c0-.38,0-.76,0-1.13s0-.73-.07-1.05a6.39,6.39,0,0,0-.17-.87,1.4,1.4,0,0,0-.31-.61,2.69,2.69,0,0,0-1.15-.74,6.89,6.89,0,0,0-1.55-.29v-.31c3.3-.09,6.6-.14,9.9-.17v.31a9.69,9.69,0,0,0-1.49.36,2.11,2.11,0,0,0-1.2,1,2.75,2.75,0,0,0-.3,1.35q0,.81,0,1.53c0,.53,0,1,0,1.55s0,1,0,1.55,0,1.07,0,1.63,0,1.14,0,1.79l.09,7.07c0,.61,0,1.19.06,1.75a2.26,2.26,0,0,0,.3,1.19,2.39,2.39,0,0,0,1.23.8,6.82,6.82,0,0,0,1.5.33V48Q248.12,48.09,243.29,48.2Z"/><path class="cls-3" d="M279.46,41.6a11.73,11.73,0,0,1-6.64,5.91,13.42,13.42,0,0,1-9.24-.14,11.62,11.62,0,0,1-3.8-2.37,11.69,11.69,0,0,1-2.55-13.12A10.78,10.78,0,0,1,260,28.25,12,12,0,0,1,264.05,26a15,15,0,0,1,4.93-.73,12.66,12.66,0,0,1,5,1,11,11,0,0,1,3.7,2.63,10.64,10.64,0,0,1,2.24,3.72A11.45,11.45,0,0,1,280.6,37,11,11,0,0,1,279.46,41.6ZM276.18,33a11.78,11.78,0,0,0-1.44-3.56,8.34,8.34,0,0,0-2.52-2.63,6.53,6.53,0,0,0-3.65-1.06,6.77,6.77,0,0,0-3.73.93,8.13,8.13,0,0,0-2.59,2.53,11.26,11.26,0,0,0-1.5,3.54,17.7,17.7,0,0,0-.49,4,16.39,16.39,0,0,0,.5,4.1,11.57,11.57,0,0,0,1.51,3.48,8,8,0,0,0,2.51,2.44,6.81,6.81,0,0,0,3.51.95,6.09,6.09,0,0,0,3.52-.93,8.62,8.62,0,0,0,2.55-2.52A12.23,12.23,0,0,0,276,40.83a16.09,16.09,0,0,0,.62-3.93A15,15,0,0,0,276.18,33Z"/><path class="cls-3" d="M308.71,28.46a2.78,2.78,0,0,0-1.24,1.25,4.94,4.94,0,0,0-.44,1.71c-.11.84-.23,1.73-.34,2.69s-.24,1.94-.37,3.16-.25,2.51-.36,3.91c0,.58-.1,1.25-.16,2s-.11,1.47-.16,2.23-.1,1.51-.16,2.26-.11,1.43-.16,2a.3.3,0,0,1-.1.2A.4.4,0,0,1,305,50a.93.93,0,0,1-.55-.36l-4.54-6-4-5.17Q294,36,292.12,33.66c-1.25-1.56-2.58-3.16-4-4.82q-.33,6.6-.65,13.2-.08,1.59-.06,2.88a5,5,0,0,0,.31,1.92,2.32,2.32,0,0,0,1,1.14,6.8,6.8,0,0,0,2,.62l0,.31c-2.61-.14-5.23-.26-7.84-.37v-.32a6.58,6.58,0,0,0,1.55-.32,2.55,2.55,0,0,0,1.26-.93,4.29,4.29,0,0,0,.67-1.91q.18-1.28.33-3.06c.09-.89.17-2,.25-3.17s.16-2.52.22-3.92c0-.61.05-1.11.07-1.5s0-.78.06-1.16,0-.76.05-1.16,0-.92,0-1.53a3.32,3.32,0,0,0-.39-1.51,2.88,2.88,0,0,0-.81-.94,3.22,3.22,0,0,0-1.05-.52,10.63,10.63,0,0,0-1.1-.25V26c2.24.09,4.48.2,6.71.31q7.38,9.07,14.31,18.32c.27-3.54.55-7.07.83-10.61.06-.83.11-1.63.15-2.39a5.39,5.39,0,0,0-.15-1.82,2.94,2.94,0,0,0-1.06-1.51,6.14,6.14,0,0,0-2.37-.94l0-.31c2.73.19,5.46.41,8.19.64l0,.31A5.26,5.26,0,0,0,308.71,28.46Z"/><path class="cls-3" d="M346.89,54.65q-10.14-1.51-20.33-2.7l0-.31a8.19,8.19,0,0,0,1.62-.22,2.91,2.91,0,0,0,1.32-.63,1.5,1.5,0,0,0,.33-.51,4.65,4.65,0,0,0,.28-.8c.08-.31.16-.63.23-1s.13-.67.17-1,.09-.69.16-1.18.15-1,.23-1.63.16-1.19.23-1.82.16-1.24.22-1.8q.38-3,.73-6l.14-1.09a9.9,9.9,0,0,0,.07-1,6,6,0,0,0,0-.88,1.39,1.39,0,0,0-.23-.62,2.91,2.91,0,0,0-1.13-1,7.29,7.29,0,0,0-1.59-.56l0-.31c3.5.4,7,.84,10.49,1.3l0,.31c-.29,0-.63,0-1,.06a4.29,4.29,0,0,0-1.17.25,2.66,2.66,0,0,0-1,.68,2.42,2.42,0,0,0-.59,1.3l-.3,2c-.08.6-.17,1.19-.25,1.76s-.17,1.18-.25,1.8-.17,1.32-.26,2.08-.18,1.35-.25,1.93-.14,1.11-.21,1.65-.13,1.09-.19,1.66-.14,1.21-.23,1.91-.12,1.3-.16,1.91a2.72,2.72,0,0,0,.16,1.37,1.31,1.31,0,0,0,.47.38,5.05,5.05,0,0,0,.89.38c.35.12.73.24,1.15.34a10.63,10.63,0,0,0,1.25.25l.81.09c.37,0,.78.08,1.23.11s.91,0,1.38,0a9.61,9.61,0,0,0,1.27-.07,7.37,7.37,0,0,0,2.24-.6,6.93,6.93,0,0,0,1.64-1.07A8.12,8.12,0,0,0,347.66,50c.36-.52.72-1.08,1.07-1.66l.3.14C348.32,50.52,347.6,52.58,346.89,54.65Z"/><path class="cls-3" d="M350.15,55.15l.05-.31a6.83,6.83,0,0,0,1.53-.17,3.12,3.12,0,0,0,1.28-.62,1.24,1.24,0,0,0,.33-.49,6,6,0,0,0,.25-.78c.08-.3.16-.63.22-1s.13-.68.18-1,.11-.67.21-1.17.18-1,.29-1.61.21-1.19.31-1.81.2-1.24.29-1.79q.48-3,1-6l.18-1.11q.09-.55.12-1a8.4,8.4,0,0,0,0-.88,1.43,1.43,0,0,0-.2-.65,2.61,2.61,0,0,0-1-.94,6.63,6.63,0,0,0-1.47-.57l.05-.31q4.9.77,9.79,1.61l-.05.31a8.23,8.23,0,0,0-1.53.09,2.12,2.12,0,0,0-1.38.78A2.9,2.9,0,0,0,360,37q-.15.8-.3,1.5T359.45,40c-.1.5-.19,1-.28,1.52s-.17,1.05-.26,1.61-.19,1.12-.3,1.76l-1.17,7c-.1.59-.18,1.17-.25,1.73a2.22,2.22,0,0,0,.09,1.22,2.32,2.32,0,0,0,1.06,1,6.79,6.79,0,0,0,1.43.59l-.06.31Q354.94,55.9,350.15,55.15Z"/><path class="cls-3" d="M384.1,57.22a5.69,5.69,0,0,1-1.25,1.37,6.34,6.34,0,0,1-1.5.88,5.9,5.9,0,0,1-1.53.43,10.38,10.38,0,0,1-2.78,0q-1.5-.21-2.88-.48-5.42-1.08-10.85-2l.05-.31a6.8,6.8,0,0,0,1.57-.13,2.92,2.92,0,0,0,1.29-.56,1.29,1.29,0,0,0,.35-.49c.11-.22.22-.49.33-.78s.2-.62.29-.95.15-.67.21-1,.13-.67.24-1.17l.33-1.61c.11-.58.23-1.18.34-1.79s.23-1.23.33-1.79.22-1.16.3-1.63.17-.92.25-1.36.17-.91.24-1.38.17-1,.29-1.64c.07-.37.12-.74.17-1.13a10.81,10.81,0,0,0,.09-1.11c0-.36,0-.69,0-1a1.28,1.28,0,0,0-.2-.65,2.62,2.62,0,0,0-.86-.84,5.68,5.68,0,0,0-1.32-.51l.05-.31q5.5,1,11,2.07a21.37,21.37,0,0,1,2.33.61,10.44,10.44,0,0,1,2.06,1,6.56,6.56,0,0,1,2.36,2.35,4.44,4.44,0,0,1,.43,3.26,4.35,4.35,0,0,1-2.06,3,7.41,7.41,0,0,1-3.89.94l0,.12a9.59,9.59,0,0,1,2.16,1A7.28,7.28,0,0,1,383.77,51a5.6,5.6,0,0,1,1.05,2,4.57,4.57,0,0,1,.05,2.3A5.76,5.76,0,0,1,384.1,57.22Zm-2.26-16.43a4.86,4.86,0,0,0-1.71-2.14,10.06,10.06,0,0,0-3.63-1.35,10.75,10.75,0,0,0-1.25-.18,5.27,5.27,0,0,0-.88,0q-.06.18-.12.33a2,2,0,0,0-.13.37c0,.16-.08.34-.14.57s-.13.51-.22.88c-.16.71-.32,1.5-.5,2.36l-.48,2.45c-.15.76-.27,1.42-.38,2s-.17.88-.19,1l1.8.34c.49.1.89.16,1.19.2a6.83,6.83,0,0,0,4.69-.69,5,5,0,0,0,1.95-6.09Zm-.7,12.34a5.44,5.44,0,0,0-.53-1.61,5.33,5.33,0,0,0-1-1.39,6.18,6.18,0,0,0-1.43-1.08,9,9,0,0,0-1.33-.57,15.31,15.31,0,0,0-1.61-.39l-3.1-.6c-.13.65-.25,1.31-.38,2s-.24,1.28-.36,1.87-.2,1.1-.28,1.59-.16.9-.22,1.25c-.13.78-.22,1.43-.26,1.94a2.46,2.46,0,0,0,.22,1.33,2.26,2.26,0,0,0,.74.74,4.85,4.85,0,0,0,1.59.54,18.16,18.16,0,0,0,2,.27,6.14,6.14,0,0,0,2.2-.22,5.28,5.28,0,0,0,2.42-1.38,4.85,4.85,0,0,0,1.28-2.53A4.6,4.6,0,0,0,381.14,53.13Z"/><path class="cls-3" d="M404.76,66.29l-.3-.51c-.06-.11-.13-.24-.2-.39s-.16-.36-.26-.63-.25-.68-.47-1.23-.48-1.27-.67-1.8-.39-1.06-.59-1.58-.44-1.06-.69-1.6-.57-1.17-.94-1.86a13.08,13.08,0,0,0-1.06-1.64,3.61,3.61,0,0,0-1.39-1.13,4.9,4.9,0,0,0-.9-.34l-.72-.21-.81,3.45c-.22,1-.41,1.8-.54,2.48s-.24,1.21-.33,1.69a2.31,2.31,0,0,0,.07,1.24,3,3,0,0,0,.78,1,4.63,4.63,0,0,0,1.89.95l-.07.3q-5-1.19-10-2.3l.07-.31a10.5,10.5,0,0,0,1.59,0,2.6,2.6,0,0,0,1.29-.48,1.46,1.46,0,0,0,.38-.49,5.87,5.87,0,0,0,.33-.79q.15-.45.3-1c.1-.34.18-.68.26-1s.16-.67.28-1.16l.39-1.6c.15-.57.29-1.17.43-1.78s.27-1.22.4-1.77l1.35-6c.09-.37.17-.74.24-1.12s.13-.74.18-1.08a6.38,6.38,0,0,0,0-.95,1.38,1.38,0,0,0-.18-.67,2.45,2.45,0,0,0-.94-.9,11,11,0,0,0-1.41-.62l.07-.31,1.33.3,2.5.55c.94.2,1.87.41,2.8.63l2.27.54c1.45.34,2.72.69,3.82,1.05a8.09,8.09,0,0,1,2.87,1.58A6.21,6.21,0,0,1,410,47.36a5.14,5.14,0,0,1,.1,3.24,4.77,4.77,0,0,1-.95,1.91,5.57,5.57,0,0,1-1.54,1.28,7.06,7.06,0,0,1-2,.75,13.26,13.26,0,0,1-2.2.33l0,.09a4.15,4.15,0,0,1,.85,1,11.4,11.4,0,0,1,.69,1.4c.36.9.74,1.88,1.16,2.93s.78,2,1.11,2.81A9.76,9.76,0,0,0,408.91,66a6.43,6.43,0,0,0,2.31,1.61l-.08.3Q408,67.1,404.76,66.29Zm1.6-19.7a5.58,5.58,0,0,0-1.89-2.47,7.36,7.36,0,0,0-1.52-.88,10.37,10.37,0,0,0-1.76-.58c-.45-.11-.82-.18-1.11-.23a6.2,6.2,0,0,0-.66-.09,2.15,2.15,0,0,1-.14.3c0,.09-.08.2-.13.34l-.17.59-.3,1.07c-.19.71-.39,1.51-.61,2.4s-.43,1.75-.62,2.59-.37,1.56-.52,2.19-.23,1-.27,1.16c.87.2,1.69.36,2.46.47a11.73,11.73,0,0,0,2.29.08,6.2,6.2,0,0,0,1.95-.4,5,5,0,0,0,1.48-.87,5.21,5.21,0,0,0,1-1.25,5.63,5.63,0,0,0,.61-1.52A4.84,4.84,0,0,0,406.36,46.59Z"/><path class="cls-3" d="M424.59,71.67l.09-.3a3.79,3.79,0,0,0,.47.07,4.22,4.22,0,0,0,.8,0,2.43,2.43,0,0,0,.81-.22,1,1,0,0,0,.49-.61,4.31,4.31,0,0,0,.09-.93c0-.45,0-1,0-1.65s-.08-1.37-.14-2.17-.14-1.64-.22-2.51q-4.17-1.22-8.36-2.36l-1.51,1.94c-.48.61-1,1.23-1.45,1.86a7.72,7.72,0,0,0-1.27,2.12.94.94,0,0,0,.07.72,2,2,0,0,0,.52.59,4,4,0,0,0,.77.47l.82.37-.08.3q-3.3-.9-6.62-1.77l.09-.34a3.82,3.82,0,0,0,2.29-.33,6.52,6.52,0,0,0,1-.81,21.49,21.49,0,0,0,1.84-2c.7-.83,1.48-1.77,2.35-2.83L420.09,58c.94-1.12,1.87-2.24,2.8-3.38s1.82-2.2,2.65-3.18c-.05-.25-.09-.5-.14-.75a5.78,5.78,0,0,0,1.21-.28,6.28,6.28,0,0,0,1-.46,6.77,6.77,0,0,0,.79-.52c.23-.18.4-.32.53-.44l.25.08c.19,1.85.36,3.61.52,5.28s.31,3.27.44,4.8.26,3,.38,4.47.24,2.87.36,4.28c.05.68.1,1.26.18,1.73s.15,1,.25,1.6a2.56,2.56,0,0,0,.15.5,4.3,4.3,0,0,0,.38.79,3.81,3.81,0,0,0,.72.82,3.42,3.42,0,0,0,1.15.64l-.11.36C430.61,73.44,427.6,72.55,424.59,71.67Zm1.1-19.41c-.2.22-.5.58-.9,1.07s-.9,1.1-1.49,1.8-1.23,1.5-1.95,2.4L419,60.44q3.91,1.08,7.83,2.21c-.1-1-.2-2-.31-3s-.22-2-.33-2.91l-.3-2.56C425.84,53.39,425.76,52.75,425.69,52.26Z"/><path class="cls-3" d="M451.57,80.19c-.13-.24-.21-.42-.27-.54s-.1-.25-.17-.4a5.28,5.28,0,0,1-.2-.65c-.08-.28-.2-.7-.38-1.27s-.37-1.3-.52-1.84-.31-1.09-.47-1.63-.35-1.09-.56-1.66-.48-1.2-.79-1.92a13.18,13.18,0,0,0-.94-1.73A3.68,3.68,0,0,0,446,67.3a6.1,6.1,0,0,0-.87-.41l-.71-.26c-.41,1.29-.77,2.41-1.08,3.37s-.55,1.76-.74,2.42-.34,1.2-.47,1.66a2.29,2.29,0,0,0,0,1.24,3,3,0,0,0,.7,1.1,4.69,4.69,0,0,0,1.82,1.1l-.1.3q-4.9-1.6-9.84-3.13l.1-.3a9.44,9.44,0,0,0,1.59.1,2.56,2.56,0,0,0,1.33-.37,1.47,1.47,0,0,0,.42-.46,6.7,6.7,0,0,0,.39-.76c.13-.29.25-.6.38-.94s.24-.65.34-1,.21-.66.37-1.13.34-1,.53-1.56.38-1.14.56-1.74l.55-1.73L443,59c.12-.36.23-.73.33-1.1s.2-.73.27-1.06a5.74,5.74,0,0,0,.12-1,1.32,1.32,0,0,0-.12-.68,2.49,2.49,0,0,0-.87-1,10.84,10.84,0,0,0-1.36-.74l.09-.3,1.31.41,2.47.75c.91.28,1.83.57,2.74.87l2.23.72c1.43.46,2.67.92,3.75,1.36a8.25,8.25,0,0,1,2.75,1.82,6.3,6.3,0,0,1,1.61,2.61A5.13,5.13,0,0,1,458.2,65a4.79,4.79,0,0,1-1.1,1.83A5.57,5.57,0,0,1,455.45,68a7.34,7.34,0,0,1-2,.58,12.67,12.67,0,0,1-2.23.14l0,.09a4.33,4.33,0,0,1,.77,1.12,12.88,12.88,0,0,1,.58,1.45c.28.94.59,1.94.92,3s.63,2,.89,2.88a9.78,9.78,0,0,0,1.43,3,6.27,6.27,0,0,0,2.18,1.79l-.11.3C455.74,81.63,453.65,80.91,451.57,80.19Zm3.18-19.51a5.74,5.74,0,0,0-1.7-2.62,7.78,7.78,0,0,0-1.45-1,10.11,10.11,0,0,0-1.71-.73c-.45-.14-.82-.25-1.1-.32l-.65-.15c-.06.12-.12.21-.17.3a2,2,0,0,0-.15.32c-.06.14-.13.33-.22.57s-.22.6-.39,1.05q-.37,1-.81,2.34c-.29.87-.57,1.71-.83,2.52l-.69,2.15-.36,1.13c.85.28,1.66.5,2.42.67a10.6,10.6,0,0,0,2.29.27,5.92,5.92,0,0,0,2-.23,4.91,4.91,0,0,0,1.56-.75,5,5,0,0,0,1.14-1.15,5.63,5.63,0,0,0,.74-1.47A4.8,4.8,0,0,0,454.75,60.68Z"/><path class="cls-3" d="M484.73,69.16a5.37,5.37,0,0,0-1.46.31,8,8,0,0,0-1.44.71c-.49.3-1,.66-1.61,1.06l-1.63,1.1c-.69.46-1.39.94-2.12,1.45l-2.09,1.45-1.58,1.07-2.22,5.89c-.21.57-.4,1.13-.57,1.67a2.06,2.06,0,0,0,.72,2.54c.44.32.86.61,1.27.85l-.11.3q-4.67-1.78-9.35-3.49l.11-.3a8.23,8.23,0,0,0,1.49.23,3.34,3.34,0,0,0,1.6-.46,1,1,0,0,0,.42-.42,8.2,8.2,0,0,0,.41-.75c.14-.28.28-.58.41-.91s.26-.65.37-1c.23-.54.48-1.18.77-1.93s.64-1.66,1-2.74c0-.07-.07-.31-.16-.7s-.2-.86-.33-1.44l-.43-1.9c-.15-.7-.31-1.39-.47-2.06s-.3-1.29-.45-1.87-.26-1.07-.37-1.44l-.52-2a8.34,8.34,0,0,0-.56-1.56,5.66,5.66,0,0,0-.71-1.15,2.52,2.52,0,0,0-1-.72l.11-.3q4.78,1.7,9.57,3.46l-.11.3c-.33-.1-.65-.19-1-.26a4.75,4.75,0,0,0-1-.14,2.1,2.1,0,0,0-.79.11.84.84,0,0,0-.48.51,2.88,2.88,0,0,0,0,1.33c.11.63.23,1.27.37,1.92.1.44.22,1,.35,1.58s.27,1.27.44,2,.33,1.41.49,2.14.31,1.42.44,2.07q.62-.41,1.53-1l1.86-1.3,1.8-1.27c.57-.41,1-.73,1.32-1l.55-.41c.2-.16.41-.33.61-.51a7.53,7.53,0,0,0,.56-.57,2,2,0,0,0,.37-.59,1.09,1.09,0,0,0,0-.83,1.86,1.86,0,0,0-.48-.66A6,6,0,0,0,480,67l-.86-.48.11-.29q3.63,1.38,7.25,2.82l-.12.29A5.64,5.64,0,0,0,484.73,69.16Z"/><path class="cls-4" d="M80,344.89a537.5,537.5,0,0,0,80,17.59v-293A537.5,537.5,0,0,0,80,87.11Z"/><path class="cls-5" d="M361,360.11a514.16,514.16,0,0,0,73-17.75V89.64a514.16,514.16,0,0,0-73-17.75Z"/><path class="cls-6" d="M448,94.48v243c10.9-4,21.26-8.28,31-12.88V107.36C469.26,102.76,458.9,98.46,448,94.48Z"/><path class="cls-6" d="M66,91.64c-12,4.09-23.34,8.57-34,13.4V327c10.66,4.83,22,9.31,34,13.4Z"/><path class="cls-7" d="M347,69.67A667.24,667.24,0,0,0,173,67.8V364.2a659.88,659.88,0,0,0,80,4.8,654,654,0,0,0,94-6.67Z"/></svg>
diff --git a/benchmarks/bench.hs b/benchmarks/bench.hs
--- a/benchmarks/bench.hs
+++ b/benchmarks/bench.hs
@@ -6,7 +6,7 @@
 import qualified Data.ByteString as B
 import qualified Data.Binary as B
 import Data.Either
-import Data.Winery
+import Codec.Winery
 import Data.Text (Text)
 import qualified Data.Text.Encoding as TE
 import qualified Data.Serialize as C
diff --git a/src/Codec/Winery.hs b/src/Codec/Winery.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/Winery.hs
@@ -0,0 +1,1291 @@
+{-# LANGUAGE ApplicativeDo #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedLists #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE TypeApplications #-}
+#if __GLASGOW_HASKELL__ < 806
+{-# LANGUAGE TypeInType #-}
+#endif
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE StandaloneDeriving #-}
+----------------------------------------------------------------------------
+-- |
+-- Module      :  Codec.Winery
+-- Copyright   :  (c) Fumiaki Kinoshita 2019
+-- License     :  BSD3
+-- Stability   :  Provisional
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+--
+-----------------------------------------------------------------------------
+module Codec.Winery
+  ( Schema
+  , SchemaP(..)
+  , Tag(..)
+  , Serialise(..)
+  , testSerialise
+  , DecodeException(..)
+  , schema
+  -- * Standalone serialisation
+  , toBuilderWithSchema
+  , serialise
+  , deserialise
+  , deserialiseBy
+  , deserialiseTerm
+  , splitSchema
+  , writeFileSerialise
+  -- * Separate serialisation
+  , serialiseSchema
+  , deserialiseSchema
+  , Extractor(..)
+  , unwrapExtractor
+  , Decoder
+  , evalDecoder
+  , serialiseOnly
+  , getDecoder
+  , getDecoderBy
+  -- * Decoding combinators
+  , Term(..)
+  , Subextractor(..)
+  , buildExtractor
+  , extractListBy
+  , extractField
+  , extractFieldBy
+  , extractConstructor
+  , extractConstructorBy
+  , extractVoid
+  , ExtractException(..)
+  -- * Variable-length quantity
+  , VarInt(..)
+  -- * Internal
+  , WineryException(..)
+  , prettyWineryException
+  , unexpectedSchema
+  , SchemaGen
+  , getSchema
+  , Plan(..)
+  , mkPlan
+  -- * DerivingVia
+  , WineryRecord(..)
+  , WineryVariant(..)
+  , WineryProduct(..)
+  -- * Generic implementations (for old GHC / custom instances)
+  , GSerialiseRecord
+  , gschemaGenRecord
+  , GEncodeProduct
+  , gtoBuilderRecord
+  , gextractorRecord
+  , gdecodeCurrentRecord
+  , GSerialiseVariant
+  , gschemaGenVariant
+  , gtoBuilderVariant
+  , gextractorVariant
+  , gschemaGenProduct
+  , gtoBuilderProduct
+  , gdecodeCurrentVariant
+  , gextractorProduct
+  , gdecodeCurrentProduct
+  , decodeCurrentDefault
+  -- * Bundles
+  , BundleSerialise(..)
+  , bundleRecord
+  , bundleRecordDefault
+  , bundleVariant
+  -- * Preset schema
+  , bootstrapSchema
+  )where
+
+import Control.Applicative
+import Control.Exception
+import Control.Monad.Reader
+import qualified Data.ByteString as B
+import qualified Data.ByteString.FastBuilder as BB
+import qualified Data.ByteString.Lazy as BL
+import Data.Bits
+import Data.Complex
+import Data.Dynamic
+import Data.Fixed
+import Data.Functor.Compose
+import Data.Functor.Identity
+import Data.List (elemIndex)
+import Data.Monoid as M
+import Data.Proxy
+import Data.Ratio
+import Data.Scientific (Scientific, scientific, coefficient, base10Exponent)
+import Data.Semigroup as S
+import Data.Hashable (Hashable)
+import qualified Data.HashMap.Strict as HM
+import Data.Int
+import qualified Data.IntMap as IM
+import qualified Data.IntSet as IS
+import qualified Data.Map as M
+import Data.Ord
+import Data.Word
+import Codec.Winery.Base as W
+import Codec.Winery.Internal
+import qualified Data.Sequence as Seq
+import qualified Data.Set as S
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Data.Text.Encoding.Error as T
+import qualified Data.Vector as V
+import qualified Data.Vector.Storable as SV
+import qualified Data.Vector.Unboxed as UV
+import Data.Text.Prettyprint.Doc hiding ((<>), SText, SChar)
+import Data.Text.Prettyprint.Doc.Render.Terminal
+import Data.Time.Clock
+import Data.Time.Clock.POSIX
+import Data.Typeable
+import Data.Void
+import Unsafe.Coerce
+import GHC.Float (castWord32ToFloat, castWord64ToDouble)
+import GHC.Natural
+import GHC.Generics
+import GHC.TypeLits
+import System.IO
+import qualified Test.QuickCheck as QC
+
+-- | Deserialiser for a 'Term'.
+--
+-- /"I will read anything rather than work."/
+decodeTerm :: Schema -> Decoder Term
+decodeTerm = go [] where
+  go points = \case
+    SBool -> TBool <$> decodeCurrent
+    W.SChar -> TChar <$> decodeCurrent
+    SWord8 -> TWord8 <$> getWord8
+    SWord16 -> TWord16 <$> getWord16
+    SWord32 -> TWord32 <$> getWord32
+    SWord64 -> TWord64 <$> getWord64
+    SInt8 -> TInt8 <$> decodeCurrent
+    SInt16 -> TInt16 <$> decodeCurrent
+    SInt32 -> TInt32 <$> decodeCurrent
+    SInt64 -> TInt64 <$> decodeCurrent
+    SInteger -> TInteger <$> decodeVarInt
+    SFloat -> TFloat <$> decodeCurrent
+    SDouble -> TDouble <$> decodeCurrent
+    SBytes -> TBytes <$> decodeCurrent
+    W.SText -> TText <$> decodeCurrent
+    SUTCTime -> TUTCTime <$> decodeCurrent
+    SVector sch -> do
+      n <- decodeVarInt
+      TVector <$> V.replicateM n (go points sch)
+    SProduct schs -> TProduct <$> traverse (go points) schs
+    SRecord schs -> TRecord <$> traverse (\(k, s) -> (,) k <$> go points s) schs
+    SVariant schs -> do
+      let !decoders = V.map (\(name, sch) -> let !m = go points sch in (name, m)) schs
+      tag <- decodeVarInt
+      let (name, dec) = maybe (throw InvalidTag) id $ decoders V.!? tag
+      TVariant tag name <$> dec
+    SVar i -> indexDefault (throw InvalidTag) points i
+    SFix s' -> fix $ \a -> go (a : points) s'
+    STag _ s -> go points s
+    SLet s t -> go (go points s : points) t
+
+-- | Deserialise a 'serialise'd 'B.Bytestring'.
+deserialiseTerm :: B.ByteString -> Either WineryException (Schema, Term)
+deserialiseTerm bs_ = do
+  (sch, bs) <- splitSchema bs_
+  return (sch, decodeTerm sch `evalDecoder` bs)
+
+-- | This may be thrown if illegal 'Term' is passed to an extractor.
+data ExtractException = InvalidTerm !Term deriving Show
+instance Exception ExtractException
+
+-- | Serialisable datatype
+--
+class Typeable a => Serialise a where
+  -- | Obtain the schema of the datatype.
+  schemaGen :: Proxy a -> SchemaGen Schema
+  schemaGen = bundleSchemaGen bundleSerialise
+  {-# INLINE schemaGen #-}
+
+  -- | Serialise a value.
+  toBuilder :: a -> BB.Builder
+  toBuilder = bundleToBuilder bundleSerialise
+  {-# INLINE toBuilder #-}
+
+  -- | A value of 'Extractor a' interprets a schema and builds a function from
+  -- 'Term' to @a@. This must be equivalent to 'decodeCurrent' when the schema
+  -- is the current one.
+  --
+  -- If @'extractor' s@ returns a function, the function must return a
+  -- non-bottom for any 'Term' @'decodeTerm' s@ returns.
+  --
+  -- It must not return a function if an unsupported schema is supplied.
+  --
+  -- @getDecoderBy extractor (schema (Proxy @ a))@ must be @Right d@
+  -- where @d@ is equivalent to 'decodeCurrent'.
+  --
+  extractor :: Extractor a
+  extractor = bundleExtractor bundleSerialise
+  {-# INLINE extractor #-}
+
+  -- | Decode a value with the current schema.
+  --
+  -- @'decodeCurrent' `evalDecoder` 'toBuilder' x@ ≡ x
+  decodeCurrent :: Decoder a
+  decodeCurrent = bundleDecodeCurrent bundleSerialise
+  {-# INLINE decodeCurrent #-}
+
+  -- | Instead of the four methods above, you can supply a bundle.
+  bundleSerialise :: BundleSerialise a
+  bundleSerialise = BundleSerialise
+    { bundleSchemaGen = schemaGen
+    , bundleToBuilder = toBuilder
+    , bundleExtractor = extractor
+    , bundleDecodeCurrent = decodeCurrent
+    }
+
+  {-# MINIMAL schemaGen, toBuilder, extractor, decodeCurrent | bundleSerialise #-}
+
+-- | A bundle of 'Serialise' methods
+data BundleSerialise a = BundleSerialise
+  { bundleSchemaGen :: Proxy a -> SchemaGen Schema
+  , bundleToBuilder :: a -> BB.Builder
+  , bundleExtractor :: Extractor a
+  , bundleDecodeCurrent :: Decoder a
+  }
+
+-- | A bundle of generic implementations for records
+bundleRecord :: (GEncodeProduct (Rep a), GSerialiseRecord (Rep a), GDecodeProduct (Rep a), Generic a, Typeable a)
+  => (Extractor a -> Extractor a) -- extractor modifier
+  -> BundleSerialise a
+bundleRecord f = BundleSerialise
+  { bundleSchemaGen = gschemaGenRecord
+  , bundleToBuilder = gtoBuilderRecord
+  , bundleExtractor = f $ gextractorRecord Nothing
+  , bundleDecodeCurrent = gdecodeCurrentRecord
+  }
+{-# INLINE bundleRecord #-}
+
+-- | A bundle of generic implementations for records, with a default value
+bundleRecordDefault :: (GEncodeProduct (Rep a), GSerialiseRecord (Rep a), GDecodeProduct (Rep a), Generic a, Typeable a)
+  => a -- default value
+  -> (Extractor a -> Extractor a) -- extractor modifier
+  -> BundleSerialise a
+bundleRecordDefault def f = BundleSerialise
+  { bundleSchemaGen = gschemaGenRecord
+  , bundleToBuilder = gtoBuilderRecord
+  , bundleExtractor = f $ gextractorRecord $ Just def
+  , bundleDecodeCurrent = gdecodeCurrentRecord
+  }
+{-# INLINE bundleRecordDefault #-}
+
+-- | A bundle of generic implementations for variants
+bundleVariant :: (GSerialiseVariant (Rep a), Generic a, Typeable a)
+  => (Extractor a -> Extractor a) -- extractor modifier
+  -> BundleSerialise a
+bundleVariant f = BundleSerialise
+  { bundleSchemaGen = gschemaGenVariant
+  , bundleToBuilder = gtoBuilderVariant
+  , bundleExtractor = f $ gextractorVariant
+  , bundleDecodeCurrent = gdecodeCurrentVariant
+  }
+{-# INLINE bundleVariant #-}
+
+-- | Check the integrity of a Serialise instance.
+--
+-- /"No tears in the writer, no tears in the reader. No surprise in the writer, no surprise in the reader."/
+testSerialise :: forall a. (Eq a, Show a, Serialise a) => a -> QC.Property
+testSerialise x = case getDecoderBy extractor (schema (Proxy @ a)) of
+  Left e -> QC.counterexample (show e) False
+  Right f -> QC.counterexample "extractor" (evalDecoder f b QC.=== x)
+    QC..&&. QC.counterexample "decodeCurrent" (evalDecoder decodeCurrent b QC.=== x)
+  where
+    b = serialiseOnly x
+
+-- | 'decodeCurrent' in terms of 'extractor'; note that it's very slow.
+decodeCurrentDefault :: forall a. Serialise a => Decoder a
+decodeCurrentDefault = case getDecoderBy extractor (schema (Proxy @ a)) of
+  Left err -> error $ "decodeCurrentDefault: failed to get a decoder from the current schema"
+    ++ show err
+  Right a -> a
+
+-- | Schema generator
+newtype SchemaGen a = SchemaGen { unSchemaGen :: S.Set TypeRep -> (S.Set TypeRep, [TypeRep] -> a) }
+
+instance Functor SchemaGen where
+  fmap f m = SchemaGen $ \s -> case unSchemaGen m s of
+    (rep, k) -> (rep, f . k)
+
+instance Applicative SchemaGen where
+  pure a = SchemaGen $ const (S.empty, const a)
+  m <*> n = SchemaGen $ \s -> case unSchemaGen m s of
+    (rep, f) -> case unSchemaGen n s of
+      (rep', g) -> (mappend rep rep', f <*> g)
+
+-- | Obtain a schema on 'SchemaGen', binding a fixpoint when necessary.
+-- If you are hand-rolling a definition of 'schemaGen', you should call this
+-- instead of 'schemaGen'.
+getSchema :: forall proxy a. Serialise a => proxy a -> SchemaGen Schema
+getSchema p = SchemaGen $ \seen -> if S.member rep seen
+  then (S.singleton rep, \xs -> case elemIndex rep xs of
+    Just i -> SVar i
+    Nothing -> error $ "getSchema: impossible " ++ show (rep, seen, xs))
+    -- request a fixpoint for rep when it detects a recursion
+  else case unSchemaGen (schemaGen (Proxy @ a)) (S.insert rep seen) of
+    (reps, f)
+      | S.member rep reps -> (reps, \xs -> SFix $ f (rep : xs))
+      | otherwise -> (reps, f)
+  where
+    rep = typeRep p
+
+-- | Obtain the schema of the datatype.
+--
+-- /"Tell me what you drink, and I will tell you what you are."/
+schema :: forall proxy a. Serialise a => proxy a -> Schema
+schema p = case unSchemaGen (schemaGen (Proxy @ a)) (S.singleton rep) of
+  (reps, f)
+    | S.member rep reps -> SFix $ f [rep]
+    | otherwise -> f []
+  where
+    rep = typeRep p
+
+-- | Obtain a decoder from a schema.
+--
+-- /"A reader lives a thousand lives before he dies... The man who never reads lives only one."/
+getDecoder :: forall a. Serialise a => Schema -> Either WineryException (Decoder a)
+getDecoder sch
+  | sch == schema (Proxy @ a) = Right decodeCurrent
+  | otherwise = getDecoderBy extractor sch
+{-# INLINE getDecoder #-}
+
+-- | Get a decoder from a `Extractor` and a schema.
+getDecoderBy :: Extractor a -> Schema -> Either WineryException (Decoder a)
+getDecoderBy (Extractor plan) sch = (\f -> f <$> decodeTerm sch)
+  <$> unPlan plan sch `unStrategy` StrategyEnv 0 []
+{-# INLINE getDecoderBy #-}
+
+-- | Serialise a value along with its schema.
+--
+-- /"Write the vision, and make it plain upon tables, that he may run that readeth it."/
+serialise :: Serialise a => a -> B.ByteString
+serialise = BL.toStrict . BB.toLazyByteString . toBuilderWithSchema
+{-# INLINE serialise #-}
+
+-- | 'serialise' then write it to a file.
+writeFileSerialise :: Serialise a => FilePath -> a -> IO ()
+writeFileSerialise path a = withBinaryFile path WriteMode
+  $ \h -> BB.hPutBuilder h $ toBuilderWithSchema a
+{-# INLINE writeFileSerialise #-}
+
+-- | Serialise a value with the schema.
+toBuilderWithSchema :: forall a. Serialise a => a -> BB.Builder
+toBuilderWithSchema a = mappend (BB.word8 currentSchemaVersion)
+  $ toBuilder (schema (Proxy @ a), a)
+{-# INLINE toBuilderWithSchema #-}
+
+-- | Split a 'Schema' from a 'B.ByteString'.
+splitSchema :: B.ByteString -> Either WineryException (Schema, B.ByteString)
+splitSchema bs_ = case B.uncons bs_ of
+  Just (ver, bs) -> do
+    m <- bootstrapSchema ver >>= getDecoder
+    return $ flip evalDecoder bs $ do
+      sch <- m
+      State $ \bs' -> ((sch, bs'), mempty)
+  Nothing -> Left EmptyInput
+
+-- | Serialise a schema.
+serialiseSchema :: Schema -> B.ByteString
+serialiseSchema = BL.toStrict . BB.toLazyByteString
+  . mappend (BB.word8 currentSchemaVersion) . toBuilder
+
+-- | Deserialise a 'serialise'd 'B.Bytestring'.
+--
+-- /"Old wood to burn! Old wine to drink! Old friends to trust! Old authors to read!"/
+deserialise :: Serialise a => B.ByteString -> Either WineryException a
+deserialise bs_ = do
+  (sch, bs) <- splitSchema bs_
+  dec <- getDecoder sch
+  return $ evalDecoder dec bs
+{-# INLINE deserialise #-}
+
+-- | Deserialise a 'serialise'd 'B.Bytestring' using an 'Extractor'.
+deserialiseBy :: Extractor a -> B.ByteString -> Either WineryException a
+deserialiseBy e bs_ = do
+  (sch, bs) <- splitSchema bs_
+  dec <- getDecoderBy e sch
+  return $ evalDecoder dec bs
+
+-- | Deserialise a schema.
+deserialiseSchema :: B.ByteString -> Either WineryException Schema
+deserialiseSchema bs_ = case B.uncons bs_ of
+  Just (ver, bs) -> do
+    m <- bootstrapSchema ver >>= getDecoder
+    return $ evalDecoder m bs
+  Nothing -> Left EmptyInput
+
+-- | Serialise a value without its schema.
+--
+-- /"Any unsaved progress will be lost."/
+serialiseOnly :: Serialise a => a -> B.ByteString
+serialiseOnly = BL.toStrict . BB.toLazyByteString . toBuilder
+{-# INLINE serialiseOnly #-}
+
+unexpectedSchema :: forall f a. Serialise a => Doc AnsiStyle -> Schema -> Strategy' (f a)
+unexpectedSchema subject actual = throwStrategy
+  $ UnexpectedSchema subject (pretty $ schema (Proxy @ a)) actual
+
+instance Serialise Tag where
+  schemaGen = gschemaGenVariant
+  toBuilder = gtoBuilderVariant
+  extractor = gextractorVariant
+  decodeCurrent = gdecodeCurrentVariant
+
+instance Serialise Schema where
+  schemaGen = gschemaGenVariant
+  toBuilder = gtoBuilderVariant
+  extractor = gextractorVariant
+  decodeCurrent = gdecodeCurrentVariant
+
+instance Serialise () where
+  schemaGen _ = pure $ SProduct []
+  toBuilder = mempty
+  {-# INLINE toBuilder #-}
+  extractor = pure ()
+  decodeCurrent = pure ()
+
+instance Serialise Bool where
+  schemaGen _ = pure SBool
+  toBuilder False = BB.word8 0
+  toBuilder True = BB.word8 1
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SBool -> pure $ \case
+      TBool b -> b
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Bool" s
+  decodeCurrent = (/=0) <$> getWord8
+
+instance Serialise Word8 where
+  schemaGen _ = pure SWord8
+  toBuilder = BB.word8
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SWord8 -> pure $ \case
+      TWord8 i -> i
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Word8" s
+  decodeCurrent = getWord8
+
+instance Serialise Word16 where
+  schemaGen _ = pure SWord16
+  toBuilder = BB.word16LE
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SWord16 -> pure $ \case
+      TWord16 i -> i
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Word16" s
+  decodeCurrent = getWord16
+
+instance Serialise Word32 where
+  schemaGen _ = pure SWord32
+  toBuilder = BB.word32LE
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SWord32 -> pure $ \case
+      TWord32 i -> i
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Word32" s
+  decodeCurrent = getWord32
+
+instance Serialise Word64 where
+  schemaGen _ = pure SWord64
+  toBuilder = BB.word64LE
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SWord64 -> pure $ \case
+      TWord64 i -> i
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Word64" s
+  decodeCurrent = getWord64
+
+instance Serialise Word where
+  schemaGen _ = pure SWord64
+  toBuilder = BB.word64LE . fromIntegral
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SWord64 -> pure $ \case
+      TWord64 i -> fromIntegral i
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Word" s
+  decodeCurrent = fromIntegral <$> getWord64
+
+instance Serialise Int8 where
+  schemaGen _ = pure SInt8
+  toBuilder = BB.word8 . fromIntegral
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SInt8 -> pure $ \case
+      TInt8 i -> i
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Int8" s
+  decodeCurrent = fromIntegral <$> getWord8
+
+instance Serialise Int16 where
+  schemaGen _ = pure SInt16
+  toBuilder = BB.word16LE . fromIntegral
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SInt16 -> pure $ \case
+      TInt16 i -> i
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Int16" s
+  decodeCurrent = fromIntegral <$> getWord16
+
+instance Serialise Int32 where
+  schemaGen _ = pure SInt32
+  toBuilder = BB.word32LE . fromIntegral
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SInt32 -> pure $ \case
+      TInt32 i -> i
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Int32" s
+  decodeCurrent = fromIntegral <$> getWord32
+
+instance Serialise Int64 where
+  schemaGen _ = pure SInt64
+  toBuilder = BB.word64LE . fromIntegral
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SInt64 -> pure $ \case
+      TInt64 i -> i
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Int64" s
+  decodeCurrent = fromIntegral <$> getWord64
+
+instance Serialise Int where
+  schemaGen _ = pure SInteger
+  toBuilder = toBuilder . VarInt
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SInteger -> pure $ \case
+      TInteger i -> fromIntegral i
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Int" s
+  decodeCurrent = decodeVarIntFinite
+
+instance Serialise Float where
+  schemaGen _ = pure SFloat
+  toBuilder = BB.floatLE
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SFloat -> pure $ \case
+      TFloat x -> x
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Float" s
+  decodeCurrent = castWord32ToFloat <$> getWord32
+
+instance Serialise Double where
+  schemaGen _ = pure SDouble
+  toBuilder = BB.doubleLE
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SDouble -> pure $ \case
+      TDouble x -> x
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Double" s
+  decodeCurrent = castWord64ToDouble <$> getWord64
+
+instance Serialise T.Text where
+  schemaGen _ = pure SText
+  toBuilder = toBuilder . T.encodeUtf8
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SText -> pure $ \case
+      TText t -> t
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Text" s
+  decodeCurrent = do
+    len <- decodeVarInt
+    T.decodeUtf8With T.lenientDecode <$> State (B.splitAt len)
+
+-- | Encoded in variable-length quantity.
+newtype VarInt a = VarInt { getVarInt :: a } deriving (Show, Read, Eq, Ord, Enum
+  , Bounded, Num, Real, Integral, Bits, Typeable)
+
+instance (Typeable a, Bits a, Integral a) => Serialise (VarInt a) where
+  schemaGen _ = pure SInteger
+  toBuilder = varInt . getVarInt
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SInteger -> pure $ \case
+      TInteger i -> fromIntegral i
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise (VarInt a)" s
+  decodeCurrent = VarInt <$> decodeVarInt
+
+instance Serialise Integer where
+  schemaGen _ = pure SInteger
+  toBuilder = toBuilder . VarInt
+  {-# INLINE toBuilder #-}
+  extractor = getVarInt <$> extractor
+  decodeCurrent = getVarInt <$> decodeCurrent
+
+instance Serialise Natural where
+  schemaGen _ = pure SInteger
+  toBuilder = toBuilder . toInteger
+  extractor = naturalFromInteger <$> extractor
+  decodeCurrent = naturalFromInteger <$> decodeCurrent
+
+instance Serialise Char where
+  schemaGen _ = pure SChar
+  toBuilder = toBuilder . fromEnum
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SChar -> pure $ \case
+      TChar c -> c
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise Char" s
+  decodeCurrent = toEnum <$> decodeVarInt
+
+instance Serialise a => Serialise (Maybe a) where
+  schemaGen = gschemaGenVariant
+  toBuilder = gtoBuilderVariant
+  extractor = gextractorVariant
+  decodeCurrent = gdecodeCurrentVariant
+
+instance Serialise B.ByteString where
+  schemaGen _ = pure SBytes
+  toBuilder bs = varInt (B.length bs) <> BB.byteString bs
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ mkPlan $ \case
+    SBytes -> pure $ \case
+      TBytes bs -> bs
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise ByteString" s
+  decodeCurrent = do
+    len <- decodeVarInt
+    State (B.splitAt len)
+
+instance Serialise BL.ByteString where
+  schemaGen _ = pure SBytes
+  toBuilder = toBuilder . BL.toStrict
+  {-# INLINE toBuilder #-}
+  extractor = BL.fromStrict <$> extractor
+  decodeCurrent = BL.fromStrict <$> decodeCurrent
+
+-- | time-1.9.1
+nanosecondsToNominalDiffTime :: Int64 -> NominalDiffTime
+nanosecondsToNominalDiffTime = unsafeCoerce . MkFixed . (*1000) . fromIntegral
+
+instance Serialise UTCTime where
+  schemaGen _ = pure SUTCTime
+  toBuilder = toBuilder . utcTimeToPOSIXSeconds
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ Plan $ \case
+    SUTCTime -> pure $ \case
+      TUTCTime bs -> bs
+      t -> throw $ InvalidTerm t
+    s -> unexpectedSchema "Serialise UTCTime" s
+  decodeCurrent = posixSecondsToUTCTime <$> decodeCurrent
+
+instance Serialise NominalDiffTime where
+  schemaGen _ = pure SInt64
+  toBuilder x = case unsafeCoerce x of
+    MkFixed p -> toBuilder (fromIntegral (p `div` 1000) :: Int64)
+  {-# INLINE toBuilder #-}
+  extractor = nanosecondsToNominalDiffTime <$> extractor
+  decodeCurrent = nanosecondsToNominalDiffTime <$> decodeCurrent
+
+instance Serialise a => Serialise [a] where
+  schemaGen _ = SVector <$> getSchema (Proxy @ a)
+  toBuilder xs = varInt (length xs)
+      <> foldMap toBuilder xs
+  {-# INLINE toBuilder #-}
+  extractor = V.toList <$> extractListBy extractor
+  decodeCurrent = do
+    n <- decodeVarInt
+    replicateM n decodeCurrent
+
+instance Serialise a => Serialise (V.Vector a) where
+  schemaGen _ = SVector <$> getSchema (Proxy @ a)
+  toBuilder xs = varInt (V.length xs)
+    <> foldMap toBuilder xs
+  {-# INLINE toBuilder #-}
+  extractor = extractListBy extractor
+  decodeCurrent = do
+    n <- decodeVarInt
+    V.replicateM n decodeCurrent
+
+instance (SV.Storable a, Serialise a) => Serialise (SV.Vector a) where
+  schemaGen _ = SVector <$> getSchema (Proxy @ a)
+  toBuilder = toBuilder . (SV.convert :: SV.Vector a -> V.Vector a)
+  {-# INLINE toBuilder #-}
+  extractor = SV.convert <$> extractListBy extractor
+  decodeCurrent = do
+    n <- decodeVarInt
+    SV.replicateM n decodeCurrent
+
+instance (UV.Unbox a, Serialise a) => Serialise (UV.Vector a) where
+  schemaGen _ = SVector <$> getSchema (Proxy @ a)
+  toBuilder = toBuilder . (UV.convert :: UV.Vector a -> V.Vector a)
+  {-# INLINE toBuilder #-}
+  extractor = UV.convert <$> extractListBy extractor
+  decodeCurrent = do
+    n <- decodeVarInt
+    UV.replicateM n decodeCurrent
+
+-- | Extract a list or an array of values.
+extractListBy :: Typeable a => Extractor a -> Extractor (V.Vector a)
+extractListBy (Extractor plan) = Extractor $ mkPlan $ \case
+  SVector s -> do
+    getItem <- unPlan plan s
+    return $ \case
+      TVector xs -> V.map getItem xs
+      t -> throw $ InvalidTerm t
+  s -> throwStrategy $ UnexpectedSchema "extractListBy ..." "[a]" s
+{-# INLINE extractListBy #-}
+
+instance (Ord k, Serialise k, Serialise v) => Serialise (M.Map k v) where
+  schemaGen _ = schemaGen (Proxy @ [(k, v)])
+  toBuilder m = toBuilder (M.size m)
+    <> M.foldMapWithKey (curry toBuilder) m
+  {-# INLINE toBuilder #-}
+  extractor = M.fromList <$> extractor
+  decodeCurrent = M.fromList <$> decodeCurrent
+
+instance (Eq k, Hashable k, Serialise k, Serialise v) => Serialise (HM.HashMap k v) where
+  schemaGen _ = schemaGen (Proxy @ [(k, v)])
+  toBuilder m = toBuilder (HM.size m)
+    <> HM.foldrWithKey (\k v r -> toBuilder (k, v) <> r) mempty m
+  {-# INLINE toBuilder #-}
+  extractor = HM.fromList <$> extractor
+  decodeCurrent = HM.fromList <$> decodeCurrent
+
+instance (Serialise v) => Serialise (IM.IntMap v) where
+  schemaGen _ = schemaGen (Proxy @ [(Int, v)])
+  toBuilder m = toBuilder (IM.size m)
+    <> IM.foldMapWithKey (curry toBuilder) m
+  {-# INLINE toBuilder #-}
+  extractor = IM.fromList <$> extractor
+  decodeCurrent = IM.fromList <$> decodeCurrent
+
+instance (Ord a, Serialise a) => Serialise (S.Set a) where
+  schemaGen _ = schemaGen (Proxy @ [a])
+  toBuilder s = toBuilder (S.size s) <> foldMap toBuilder s
+  {-# INLINE toBuilder #-}
+  extractor = S.fromList <$> extractor
+  decodeCurrent = S.fromList <$> decodeCurrent
+
+instance Serialise IS.IntSet where
+  schemaGen _ = schemaGen (Proxy @ [Int])
+  toBuilder s = toBuilder (IS.size s) <> IS.foldr (mappend . toBuilder) mempty s
+  {-# INLINE toBuilder #-}
+  extractor = IS.fromList <$> extractor
+  decodeCurrent = IS.fromList <$> decodeCurrent
+
+instance Serialise a => Serialise (Seq.Seq a) where
+  schemaGen _ = schemaGen (Proxy @ [a])
+  toBuilder s = toBuilder (length s) <> foldMap toBuilder s
+  {-# INLINE toBuilder #-}
+  extractor = Seq.fromList <$> extractor
+  decodeCurrent = Seq.fromList <$> decodeCurrent
+
+instance (Integral a, Serialise a) => Serialise (Ratio a) where
+  schemaGen _ = schemaGen (Proxy @ (a, a))
+  toBuilder x = toBuilder (numerator x, denominator x)
+  {-# INLINE toBuilder #-}
+  extractor = uncurry (%) <$> extractor
+  decodeCurrent = uncurry (%) <$> decodeCurrent
+
+instance Serialise Scientific where
+  schemaGen _ = schemaGen (Proxy @ (Integer, Int))
+  toBuilder s = toBuilder (coefficient s, base10Exponent s)
+  {-# INLINE toBuilder #-}
+  extractor = Extractor $ Plan $ \s -> case s of
+    SWord8 -> f (fromIntegral :: Word8 -> Scientific) s
+    SWord16 -> f (fromIntegral :: Word16 -> Scientific) s
+    SWord32 -> f (fromIntegral :: Word32 -> Scientific) s
+    SWord64 -> f (fromIntegral :: Word64 -> Scientific) s
+    SInt8 -> f (fromIntegral :: Int8 -> Scientific) s
+    SInt16 -> f (fromIntegral :: Int16 -> Scientific) s
+    SInt32 -> f (fromIntegral :: Int32 -> Scientific) s
+    SInt64 -> f (fromIntegral :: Int64 -> Scientific) s
+    SInteger -> f fromInteger s
+    SFloat -> f (realToFrac :: Float -> Scientific) s
+    SDouble -> f (realToFrac :: Double -> Scientific) s
+    _ -> f (uncurry scientific) s
+    where
+      f c = unwrapExtractor (c <$> extractor)
+  decodeCurrent = decodeCurrentDefault
+
+-- | Build an extractor from a 'Subextractor'.
+buildExtractor :: Typeable a => Subextractor a -> Extractor a
+buildExtractor (Subextractor e) = Extractor $ mkPlan $ unwrapExtractor e
+{-# INLINE buildExtractor #-}
+
+-- | An extractor for individual fields. This distinction is required for
+-- handling recursions correctly.
+--
+-- Recommended extension: ApplicativeDo
+newtype Subextractor a = Subextractor { unSubextractor :: Extractor a }
+  deriving (Functor, Applicative, Alternative)
+
+-- | Extract a field of a record.
+extractField :: Serialise a => T.Text -> Subextractor a
+extractField = extractFieldBy extractor
+{-# INLINE extractField #-}
+
+-- | Extract a field using the supplied 'Extractor'.
+extractFieldBy :: Extractor a -> T.Text -> Subextractor a
+extractFieldBy (Extractor g) name = Subextractor $ Extractor $ Plan $ \case
+  SRecord schs -> case lookupWithIndexV name schs of
+    Just (i, sch) -> do
+      m <- unPlan g sch
+      return $ \case
+        TRecord xs -> maybe (error msg) (m . snd) $ xs V.!? i
+        t -> throw $ InvalidTerm t
+    _ -> throwStrategy $ FieldNotFound rep name (map fst $ V.toList schs)
+  s -> throwStrategy $ UnexpectedSchema rep "a record" s
+  where
+    rep = "extractFieldBy ... " <> dquotes (pretty name)
+    msg = "Codec.Winery.extractFieldBy ... " <> show name <> ": impossible"
+
+-- | Construct a plan, expanding fixpoints and let bindings.
+mkPlan :: forall a. Typeable a => (Schema -> Strategy' (Term -> a)) -> Plan (Term -> a)
+mkPlan k = Plan $ \sch -> Strategy $ \(StrategyEnv ofs decs) -> case sch of
+  SVar i
+    | point : _ <- drop i decs -> case point of
+      BoundSchema ofs' sch' -> unPlan (mkPlan k) sch' `unStrategy` StrategyEnv ofs' (drop (ofs - ofs') decs)
+      DynDecoder dyn -> case fromDynamic dyn of
+        Nothing -> Left $ TypeMismatch i
+          (typeRep (Proxy @ (Term -> a)))
+          (dynTypeRep dyn)
+        Just a -> Right a
+    | otherwise -> Left $ UnboundVariable i
+  SFix s -> mfix $ \a -> unPlan (mkPlan k) s `unStrategy` StrategyEnv (ofs + 1) (DynDecoder (toDyn a) : decs)
+  SLet s t -> unPlan (mkPlan k) t `unStrategy` StrategyEnv (ofs + 1) (BoundSchema ofs s : decs)
+  s -> k s `unStrategy` StrategyEnv ofs decs
+
+instance (Serialise a, Serialise b) => Serialise (a, b) where
+  schemaGen = gschemaGenProduct
+  toBuilder = gtoBuilderProduct
+  extractor = gextractorProduct
+  decodeCurrent = gdecodeCurrentProduct
+
+instance (Serialise a, Serialise b, Serialise c) => Serialise (a, b, c) where
+  schemaGen = gschemaGenProduct
+  toBuilder = gtoBuilderProduct
+  extractor = gextractorProduct
+  decodeCurrent = gdecodeCurrentProduct
+
+instance (Serialise a, Serialise b, Serialise c, Serialise d) => Serialise (a, b, c, d) where
+  schemaGen = gschemaGenProduct
+  toBuilder = gtoBuilderProduct
+  extractor = gextractorProduct
+  decodeCurrent = gdecodeCurrentProduct
+
+instance (Serialise a, Serialise b, Serialise c, Serialise d, Serialise e) => Serialise (a, b, c, d, e) where
+  schemaGen = gschemaGenProduct
+  toBuilder = gtoBuilderProduct
+  extractor = gextractorProduct
+  decodeCurrent = gdecodeCurrentProduct
+
+instance (Serialise a, Serialise b, Serialise c, Serialise d, Serialise e, Serialise f) => Serialise (a, b, c, d, e, f) where
+  schemaGen = gschemaGenProduct
+  toBuilder = gtoBuilderProduct
+  extractor = gextractorProduct
+  decodeCurrent = gdecodeCurrentProduct
+
+instance (Serialise a, Serialise b) => Serialise (Either a b) where
+  schemaGen = gschemaGenVariant
+  toBuilder = gtoBuilderVariant
+  extractor = gextractorVariant
+  decodeCurrent = gdecodeCurrentVariant
+
+-- | Tries to extract a specific constructor of a variant. Useful for
+-- implementing backward-compatible extractors.
+extractConstructorBy :: Typeable a => (Extractor a, T.Text, a -> r) -> Subextractor r -> Subextractor r
+extractConstructorBy (d, name, f) cont = Subextractor $ Extractor $ Plan $ \case
+  SVariant schs0 -> Strategy $ \decs -> do
+    let run :: Extractor x -> Schema -> Either WineryException (Term -> x)
+        run e s = unwrapExtractor e s `unStrategy` decs
+    case lookupWithIndexV name schs0 of
+      Just (i, s) -> do
+        (j, dec) <- fmap ((,) i) $ run d $ case s of
+          SProduct [s'] -> s'
+          s' -> s'
+        let rest = SVariant $ V.filter ((/=name) . fst) schs0
+        k <- run (unSubextractor cont) rest
+        return $ \case
+          TVariant tag _ v
+            | tag == j -> f $ dec v
+          t -> k t
+      _ -> run (unSubextractor cont) (SVariant schs0)
+  s -> throwStrategy $ UnexpectedSchema rep "a variant" s
+  where
+    rep = "extractConstructorBy ... " <> dquotes (pretty name)
+
+-- | Tries to match on a constructor. If it doesn't match (or constructor
+-- doesn't exist at all), leave it to the successor.
+--
+-- @extractor = ("Just", Just) `extractConstructor` ("Nothing", \() -> Nothing) `extractConstructor` extractVoid@
+extractConstructor :: (Serialise a) => (T.Text, a -> r) -> Subextractor r -> Subextractor r
+extractConstructor (name, f) = extractConstructorBy (extractor, name, f)
+{-# INLINE extractConstructor #-}
+
+-- | No constructors remaining.
+extractVoid :: Typeable r => Subextractor r
+extractVoid = Subextractor $ Extractor $ mkPlan $ \case
+  SVariant schs0
+    | V.null schs0 -> return $ throw . InvalidTerm
+  s -> throwStrategy $ UnexpectedSchema "extractVoid" "no constructors" s
+
+infixr 1 `extractConstructorBy`
+infixr 1 `extractConstructor`
+
+-- | Generic implementation of 'schemaGen' for a record.
+gschemaGenRecord :: forall proxy a. (GSerialiseRecord (Rep a), Generic a, Typeable a) => proxy a -> SchemaGen Schema
+gschemaGenRecord _ = SRecord . V.fromList <$> recordSchema (Proxy @ (Rep a))
+
+-- | Generic implementation of 'toBuilder' for a record.
+gtoBuilderRecord :: (GEncodeProduct (Rep a), Generic a) => a -> BB.Builder
+gtoBuilderRecord = productEncoder . from
+{-# INLINE gtoBuilderRecord #-}
+
+data FieldDecoder i a = FieldDecoder !i !(Maybe a) !(Plan (Term -> a))
+
+-- | Generic implementation of 'extractor' for a record.
+gextractorRecord :: forall a. (GSerialiseRecord (Rep a), Generic a, Typeable a)
+  => Maybe a -- ^ default value (optional)
+  -> Extractor a
+gextractorRecord def = Extractor $ mkPlan
+  $ fmap (fmap (to .)) $ extractorRecord'
+  ("gextractorRecord :: Extractor " <> viaShow (typeRep (Proxy @ a)))
+  (from <$> def)
+
+-- | Generic implementation of 'extractor' for a record.
+extractorRecord' :: (GSerialiseRecord f)
+  => Doc AnsiStyle
+  -> Maybe (f x) -- ^ default value (optional)
+  -> Schema -> Strategy' (Term -> f x)
+extractorRecord' rep def (SRecord schs) = Strategy $ \decs -> do
+    let go :: FieldDecoder T.Text x -> Either WineryException (Term -> x)
+        go (FieldDecoder name def' p) = case lookupWithIndexV name schs of
+          Nothing -> case def' of
+            Just d -> Right (const d)
+            Nothing -> Left $ FieldNotFound rep name (map fst $ V.toList schs)
+          Just (i, sch) -> case p `unPlan` sch `unStrategy` decs of
+            Right getItem -> Right $ \case
+              TRecord xs -> maybe (error (show rep)) (getItem . snd) $ xs V.!? i
+              t -> throw $ InvalidTerm t
+            Left e -> Left e
+    unTransFusion (recordExtractor def) go
+extractorRecord' rep _ s = throwStrategy $ UnexpectedSchema rep "a record" s
+{-# INLINE gextractorRecord #-}
+
+-- | Synonym for 'gdecodeCurrentProduct'
+gdecodeCurrentRecord :: (GDecodeProduct (Rep a), Generic a) => Decoder a
+gdecodeCurrentRecord = to <$> productDecoder
+{-# INLINE gdecodeCurrentRecord #-}
+
+-- | The 'Serialise' instance is generically defined for records.
+--
+-- /"Remember thee! Yea, from the table of my memory I'll wipe away all trivial fond records."/
+newtype WineryRecord a = WineryRecord { unWineryRecord :: a }
+
+instance (GEncodeProduct (Rep a), GSerialiseRecord (Rep a), GDecodeProduct (Rep a), Generic a, Typeable a) => Serialise (WineryRecord a) where
+  schemaGen _ = gschemaGenRecord (Proxy @ a)
+  toBuilder = gtoBuilderRecord . unWineryRecord
+  extractor = WineryRecord <$> gextractorRecord Nothing
+  decodeCurrent = WineryRecord <$> gdecodeCurrentRecord
+
+-- | Encode all the fields
+class GEncodeProduct f where
+  productEncoder :: f x -> BB.Builder
+
+instance GEncodeProduct U1 where
+  productEncoder _ = mempty
+  {-# INLINE productEncoder #-}
+
+instance (GEncodeProduct f, GEncodeProduct g) => GEncodeProduct (f :*: g) where
+  productEncoder (f :*: g) = productEncoder f <> productEncoder g
+  {-# INLINE productEncoder #-}
+
+instance Serialise a => GEncodeProduct (S1 c (K1 i a)) where
+  productEncoder (M1 (K1 a)) = toBuilder a
+  {-# INLINE productEncoder #-}
+
+instance GEncodeProduct f => GEncodeProduct (C1 c f) where
+  productEncoder (M1 a) = productEncoder a
+  {-# INLINE productEncoder #-}
+
+instance GEncodeProduct f => GEncodeProduct (D1 c f) where
+  productEncoder (M1 a) = productEncoder a
+  {-# INLINE productEncoder #-}
+
+class GDecodeProduct f where
+  productDecoder :: Decoder (f x)
+
+instance GDecodeProduct U1 where
+  productDecoder = pure U1
+
+instance Serialise a => GDecodeProduct (K1 i a) where
+  productDecoder = K1 <$> decodeCurrent
+  {-# INLINE productDecoder #-}
+
+instance GDecodeProduct f => GDecodeProduct (M1 i c f) where
+  productDecoder = M1 <$> productDecoder
+  {-# INLINE productDecoder #-}
+
+instance (GDecodeProduct f, GDecodeProduct g) => GDecodeProduct (f :*: g) where
+  productDecoder = (:*:) <$> productDecoder <*> productDecoder
+  {-# INLINE productDecoder #-}
+
+class GSerialiseRecord f where
+  recordSchema :: proxy f -> SchemaGen [(T.Text, Schema)]
+  recordExtractor :: Maybe (f x) -> TransFusion (FieldDecoder T.Text) ((->) Term) (Term -> f x)
+
+instance (GSerialiseRecord f, GSerialiseRecord g) => GSerialiseRecord (f :*: g) where
+  recordSchema _ = (++) <$> recordSchema (Proxy @ f) <*> recordSchema (Proxy @ g)
+  recordExtractor def = (\f g -> (:*:) <$> f <*> g)
+    <$> recordExtractor ((\(x :*: _) -> x) <$> def)
+    <*> recordExtractor ((\(_ :*: x) -> x) <$> def)
+  {-# INLINE recordExtractor #-}
+
+instance (Serialise a, Selector c) => GSerialiseRecord (S1 c (K1 i a)) where
+  recordSchema _ = do
+    s <- getSchema (Proxy @ a)
+    pure [(T.pack $ selName (M1 undefined :: M1 i c (K1 i a) x), s)]
+  recordExtractor def = TransFusion $ \k -> fmap (fmap (M1 . K1)) $ k $ FieldDecoder
+    (T.pack $ selName (M1 undefined :: M1 i c (K1 i a) x))
+    (unK1 . unM1 <$> def)
+    (getExtractor extractor)
+  {-# INLINE recordExtractor #-}
+
+instance (GSerialiseRecord f) => GSerialiseRecord (C1 c f) where
+  recordSchema _ = recordSchema (Proxy @ f)
+  recordExtractor def = fmap M1 <$> recordExtractor (unM1 <$> def)
+
+instance (GSerialiseRecord f) => GSerialiseRecord (D1 c f) where
+  recordSchema _ = recordSchema (Proxy @ f)
+  recordExtractor def = fmap M1 <$> recordExtractor (unM1 <$> def)
+
+class GSerialiseProduct f where
+  productSchema :: proxy f -> SchemaGen [Schema]
+  productExtractor :: Compose (State Int) (TransFusion (FieldDecoder Int) ((->) Term)) (Term -> f x)
+
+instance GSerialiseProduct U1 where
+  productSchema _ = pure []
+  productExtractor = pure (pure U1)
+
+instance (Serialise a) => GSerialiseProduct (K1 i a) where
+  productSchema _ = pure <$> getSchema (Proxy @ a)
+  productExtractor = Compose $ State $ \i ->
+    ( TransFusion $ \k -> fmap (fmap K1) $ k $ FieldDecoder i Nothing (getExtractor extractor)
+    , i + 1)
+
+instance GSerialiseProduct f => GSerialiseProduct (M1 i c f) where
+  productSchema _ = productSchema (Proxy @ f)
+  productExtractor = fmap M1 <$> productExtractor
+
+instance (GSerialiseProduct f, GSerialiseProduct g) => GSerialiseProduct (f :*: g) where
+  productSchema _ = (++) <$> productSchema (Proxy @ f) <*> productSchema (Proxy @ g)
+  productExtractor = liftA2 (:*:) <$> productExtractor <*> productExtractor
+
+-- | Serialise a value as a product (omits field names).
+--
+-- /"I get ideas about what's essential when packing my suitcase."/
+newtype WineryProduct a = WineryProduct { unWineryProduct :: a }
+
+instance (GEncodeProduct (Rep a), GSerialiseProduct (Rep a), GDecodeProduct (Rep a), Generic a, Typeable a) => Serialise (WineryProduct a) where
+  schemaGen _ = gschemaGenProduct (Proxy @ a)
+  toBuilder = gtoBuilderProduct . unWineryProduct
+  extractor = WineryProduct <$> gextractorProduct
+  decodeCurrent = WineryProduct <$> gdecodeCurrentProduct
+
+gschemaGenProduct :: forall proxy a. (Generic a, GSerialiseProduct (Rep a)) => proxy a -> SchemaGen Schema
+gschemaGenProduct _ = SProduct . V.fromList <$> productSchema (Proxy @ (Rep a))
+{-# INLINE gschemaGenProduct #-}
+
+gtoBuilderProduct :: (Generic a, GEncodeProduct (Rep a)) => a -> BB.Builder
+gtoBuilderProduct = productEncoder . from
+{-# INLINE gtoBuilderProduct #-}
+
+-- | Generic implementation of 'extractor' for a record.
+gextractorProduct :: forall a. (GSerialiseProduct (Rep a), Generic a, Typeable a)
+  => Extractor a
+gextractorProduct = Extractor $ mkPlan $ fmap (to .) . extractorProduct'
+{-# INLINE gextractorProduct #-}
+
+-- | Generic implementation of 'extractor' for a record.
+gdecodeCurrentProduct :: forall a. (GDecodeProduct (Rep a), Generic a)
+  => Decoder a
+gdecodeCurrentProduct = to <$> productDecoder
+{-# INLINE gdecodeCurrentProduct #-}
+
+extractorProduct' :: GSerialiseProduct f => Schema -> Strategy' (Term -> f x)
+extractorProduct' sch
+  | Just schs <- strip sch = Strategy $ \recs -> do
+    let go :: FieldDecoder Int x -> Either WineryException (Term -> x)
+        go (FieldDecoder i _ p) = do
+          getItem <- if i < length schs
+            then unPlan p (schs V.! i) `unStrategy` recs
+            else Left $ ProductTooSmall $ length schs
+          return $ \case
+            TProduct xs -> getItem $ maybe (throw $ InvalidTerm (TProduct xs)) id
+              $ xs V.!? i
+            t -> throw $ InvalidTerm t
+    unTransFusion (getCompose productExtractor `evalState` 0) go
+  where
+    strip (SProduct xs) = Just xs
+    strip (SRecord xs) = Just $ V.map snd xs
+    strip _ = Nothing
+extractorProduct' sch = throwStrategy $ UnexpectedSchema "extractorProduct'" "a product" sch
+
+-- | The 'Serialise' instance is generically defined for variants.
+--
+-- /"The one so like the other as could not be distinguish'd but by names."/
+newtype WineryVariant a = WineryVariant { unWineryVariant :: a }
+
+instance (GSerialiseVariant (Rep a), Generic a, Typeable a) => Serialise (WineryVariant a) where
+  schemaGen _ = gschemaGenVariant (Proxy @ a)
+  toBuilder = gtoBuilderVariant . unWineryVariant
+  extractor = WineryVariant <$> gextractorVariant
+  decodeCurrent = WineryVariant <$> gdecodeCurrentVariant
+
+-- | Generic implementation of 'schemaGen' for an ADT.
+gschemaGenVariant :: forall proxy a. (GSerialiseVariant (Rep a), Typeable a, Generic a) => proxy a -> SchemaGen Schema
+gschemaGenVariant _ = SVariant . V.fromList <$> variantSchema (Proxy @ (Rep a))
+
+-- | Generic implementation of 'toBuilder' for an ADT.
+gtoBuilderVariant :: (GSerialiseVariant (Rep a), Generic a) => a -> BB.Builder
+gtoBuilderVariant = variantEncoder 0 . from
+{-# INLINE gtoBuilderVariant #-}
+
+-- | Generic implementation of 'extractor' for an ADT.
+gextractorVariant :: forall a. (GSerialiseVariant (Rep a), Generic a, Typeable a)
+  => Extractor a
+gextractorVariant = Extractor $ mkPlan $ \case
+  SVariant schs0 -> Strategy $ \decs -> do
+    ds' <- traverse (\(name, sch) -> case lookup name variantExtractor of
+      Nothing -> Left $ FieldNotFound rep name (map fst $ V.toList schs0)
+      Just f -> f sch `unStrategy` decs) schs0
+    return $ \case
+      TVariant i _ v -> to $ maybe (throw InvalidTag) ($ v) $ ds' V.!? i
+      t -> throw $ InvalidTerm t
+  s -> throwStrategy $ UnexpectedSchema rep "a variant" s
+  where
+    rep = "gextractorVariant :: Extractor "
+      <> viaShow (typeRep (Proxy @ a))
+
+gdecodeCurrentVariant :: (GSerialiseVariant (Rep a), Generic a) => Decoder a
+gdecodeCurrentVariant = decodeVarInt >>= maybe (throw InvalidTag) (fmap to) . (decs V.!?)
+  where
+    decs = V.fromList variantDecoder
+
+class GSerialiseVariant f where
+  variantCount :: proxy f -> Int
+  variantSchema :: proxy f -> SchemaGen [(T.Text, Schema)]
+  variantEncoder :: Int -> f x -> BB.Builder
+  variantExtractor :: [(T.Text, Schema -> Strategy' (Term -> f x))]
+  variantDecoder :: [Decoder (f x)]
+
+instance (GSerialiseVariant f, GSerialiseVariant g) => GSerialiseVariant (f :+: g) where
+  variantCount _ = variantCount (Proxy @ f) + variantCount (Proxy @ g)
+  variantSchema _ = (++) <$> variantSchema (Proxy @ f) <*> variantSchema (Proxy @ g)
+  variantEncoder i (L1 f) = variantEncoder i f
+  variantEncoder i (R1 g) = variantEncoder (i + variantCount (Proxy @ f)) g
+  variantExtractor = fmap (fmap (fmap (fmap (fmap L1)))) variantExtractor
+    ++ fmap (fmap (fmap (fmap (fmap R1)))) variantExtractor
+  variantDecoder = fmap (fmap L1) variantDecoder ++ fmap (fmap R1) variantDecoder
+
+instance (GSerialiseProduct f, GEncodeProduct f, GDecodeProduct f, KnownSymbol name) => GSerialiseVariant (C1 ('MetaCons name fixity 'False) f) where
+  variantCount _ = 1
+  variantSchema _ = do
+    s <- productSchema (Proxy @ f)
+    return [(T.pack $ symbolVal (Proxy @ name), SProduct $ V.fromList s)]
+  variantEncoder i (M1 a) = varInt i <> productEncoder a
+  variantExtractor = [(T.pack $ symbolVal (Proxy @ name), fmap (fmap M1) . extractorProduct') ]
+  variantDecoder = [M1 <$> productDecoder]
+
+instance (GSerialiseRecord f, GEncodeProduct f, GDecodeProduct f, KnownSymbol name) => GSerialiseVariant (C1 ('MetaCons name fixity 'True) f) where
+  variantCount _ = 1
+  variantSchema _ = do
+    s <- recordSchema (Proxy @ f)
+    return [(T.pack $ symbolVal (Proxy @ name), SRecord $ V.fromList s)]
+  variantEncoder i (M1 a) = varInt i <> productEncoder a
+  variantExtractor = [(T.pack $ symbolVal (Proxy @ name), fmap (fmap M1) . extractorRecord' "" Nothing) ]
+  variantDecoder = [M1 <$> productDecoder]
+
+instance (GSerialiseVariant f) => GSerialiseVariant (S1 c f) where
+  variantCount _ = variantCount (Proxy @ f)
+  variantSchema _ = variantSchema (Proxy @ f)
+  variantEncoder i (M1 a) = variantEncoder i a
+  variantExtractor = fmap (fmap (fmap (fmap M1))) <$> variantExtractor
+  variantDecoder = fmap M1 <$> variantDecoder
+
+instance (GSerialiseVariant f) => GSerialiseVariant (D1 c f) where
+  variantCount _ = variantCount (Proxy @ f)
+  variantSchema _ = variantSchema (Proxy @ f)
+  variantEncoder i (M1 a) = variantEncoder i a
+  variantExtractor = fmap (fmap (fmap (fmap M1))) <$> variantExtractor
+  variantDecoder = fmap M1 <$> variantDecoder
+
+instance Serialise Ordering where
+  schemaGen = gschemaGenVariant
+  toBuilder = gtoBuilderVariant
+  extractor = gextractorVariant
+  decodeCurrent = gdecodeCurrentVariant
+
+deriving instance Serialise a => Serialise (Identity a)
+deriving instance (Serialise a, Typeable b, Typeable k) => Serialise (Const a (b :: k))
+
+deriving instance Serialise Any
+deriving instance Serialise All
+deriving instance Serialise a => Serialise (Down a)
+deriving instance Serialise a => Serialise (Product a)
+deriving instance Serialise a => Serialise (Sum a)
+deriving instance Serialise a => Serialise (Dual a)
+deriving instance Serialise a => Serialise (M.Last a)
+deriving instance Serialise a => Serialise (M.First a)
+deriving instance Serialise a => Serialise (S.Last a)
+deriving instance Serialise a => Serialise (S.First a)
+deriving instance Serialise a => Serialise (ZipList a)
+deriving instance Serialise a => Serialise (Option a)
+deriving instance Serialise a => Serialise (Max a)
+deriving instance Serialise a => Serialise (Min a)
+deriving instance (Typeable k, Typeable f, Typeable a, Serialise (f a)) => Serialise (Alt f (a :: k))
+deriving instance (Typeable j, Typeable k, Typeable f, Typeable g, Typeable a, Serialise (f (g a))) => Serialise (Compose f (g :: j -> k) (a :: j))
+#if MIN_VERSION_base(4,12,0)
+deriving instance (Typeable k, Typeable f, Typeable a, Serialise (f a)) => Serialise (Ap f (a :: k))
+#endif
+
+instance (Typeable k, Typeable a, Typeable b, a ~ b) => Serialise ((a :: k) :~: b) where
+  schemaGen _ = pure $ SProduct []
+  toBuilder = mempty
+  extractor = pure Refl
+  decodeCurrent = pure Refl
+
+instance (Serialise a, Serialise b) => Serialise (Arg a b) where
+  schemaGen = gschemaGenProduct
+  toBuilder = gtoBuilderProduct
+  extractor = gextractorProduct
+  decodeCurrent = gdecodeCurrentProduct
+
+instance Serialise a => Serialise (Complex a) where
+  schemaGen = gschemaGenProduct
+  toBuilder = gtoBuilderProduct
+  extractor = gextractorProduct
+  decodeCurrent = gdecodeCurrentProduct
+
+instance Serialise Void where
+  schemaGen _ = pure $ SVariant V.empty
+  toBuilder = mempty
+  extractor = Extractor $ Plan $ const $ throwStrategy "No extractor for Void"
+  decodeCurrent = error "No decodeCurrent for Void"
diff --git a/src/Codec/Winery/Base.hs b/src/Codec/Winery/Base.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/Winery/Base.hs
@@ -0,0 +1,302 @@
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE OverloadedLists #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE DeriveTraversable #-}
+----------------------------------------------------------------------------
+-- |
+-- Module      :  Codec.Winery.Base
+-- Copyright   :  (c) Fumiaki Kinoshita 2019
+-- License     :  BSD3
+-- Stability   :  Provisional
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+--
+-- Basic types
+--
+-----------------------------------------------------------------------------
+module Codec.Winery.Base
+  ( Tag(..)
+  , Schema
+  , SchemaP(..)
+  , currentSchemaVersion
+  , bootstrapSchema
+  , Term(..)
+  , Extractor(..)
+  , Strategy'
+  , StrategyBind(..)
+  , StrategyEnv(..)
+  , Plan(..)
+  , unwrapExtractor
+  , WineryException(..)
+  , prettyWineryException)
+  where
+
+import Control.Applicative
+import Control.Exception
+import Data.Aeson as J
+import qualified Data.ByteString as B
+import Data.Dynamic
+import qualified Data.HashMap.Strict as HM
+import Data.Int
+import Data.String
+import qualified Data.Text as T
+import Data.Text.Prettyprint.Doc hiding ((<>), SText, SChar)
+import Data.Text.Prettyprint.Doc.Render.Terminal
+import Data.Time
+import Data.Typeable
+import qualified Data.Vector as V
+import Codec.Winery.Internal
+import Data.Word
+import GHC.Generics (Generic)
+import GHC.Exts (IsList(..))
+
+-- | Tag is an extra value that can be attached to a schema.
+data Tag = TagInt !Int
+  | TagStr !T.Text
+  | TagList ![Tag]
+  deriving (Show, Read, Eq, Generic)
+
+instance IsString Tag where
+  fromString = TagStr . fromString
+
+instance IsList Tag where
+  type Item Tag = Tag
+  fromList = TagList
+  toList (TagList xs) = xs
+  toList _ = []
+
+instance Pretty Tag where
+  pretty (TagInt i) = pretty i
+  pretty (TagStr s) = pretty s
+  pretty (TagList xs) = list (map pretty xs)
+
+-- | The current version of the schema
+currentSchemaVersion :: Word8
+currentSchemaVersion = 4
+
+-- | A schema preserves structure of a datatype, allowing users to inspect
+-- the data regardless of the current implementation.
+--
+-- /"Yeah, it’s just a memento. Just, you know, from the first time we met."/
+type Schema = SchemaP Int
+
+-- | The basic schema datatype
+data SchemaP a = SFix !(SchemaP a) -- ^ binds a fixpoint
+  | SVar !a -- ^ @SVar n@ refers to the n-th innermost fixpoint
+  | SVector !(SchemaP a)
+  | SProduct !(V.Vector (SchemaP a))
+  | SRecord !(V.Vector (T.Text, SchemaP a))
+  | SVariant !(V.Vector (T.Text, SchemaP a))
+  | SBool
+  | SChar
+  | SWord8
+  | SWord16
+  | SWord32
+  | SWord64
+  | SInt8
+  | SInt16
+  | SInt32
+  | SInt64
+  | SInteger
+  | SFloat
+  | SDouble
+  | SBytes
+  | SText
+  | SUTCTime -- ^ nanoseconds from POSIX epoch
+  | STag !Tag !(SchemaP a)
+  | SLet !(SchemaP a) !(SchemaP a)
+  deriving (Show, Read, Eq, Generic, Functor, Foldable, Traversable)
+
+instance Pretty a => Pretty (SchemaP a) where
+  pretty = \case
+    SProduct [] -> "()"
+    SBool -> "Bool"
+    SChar -> "Char"
+    SWord8 -> "Word8"
+    SWord16 -> "Word16"
+    SWord32 -> "Word32"
+    SWord64 -> "Word64"
+    SInt8 -> "Int8"
+    SInt16 -> "Int16"
+    SInt32 -> "Int32"
+    SInt64 -> "Int64"
+    SInteger -> "Integer"
+    SFloat -> "Float"
+    SDouble -> "Double"
+    SBytes -> "ByteString"
+    SText -> "Text"
+    SUTCTime -> "UTCTime"
+    SVector s -> "[" <> pretty s <> "]"
+    SProduct ss -> tupled $ map pretty (V.toList ss)
+    SRecord ss -> align $ encloseSep "{ " " }" ", " [group $ nest 2 $ sep [pretty k, "::" <+> pretty v] | (k, v) <- V.toList ss]
+    SVariant ss -> align $ encloseSep "" "" (flatAlt "| " " | ")
+      [ nest 2 $ sep $ pretty k : case vs of
+        SProduct xs -> map pretty $ V.toList xs
+        SRecord xs -> [pretty (SRecord xs)]
+        s -> [pretty s] | (k, vs) <- V.toList ss]
+    SFix sch -> group $ nest 2 $ sep ["μ", enclose "{ " " }" $ pretty sch]
+    SVar i -> "$" <> pretty i
+    STag t s -> nest 2 $ sep [pretty t <> ":", pretty s]
+    SLet s t -> sep ["let" <+> pretty s, pretty t]
+
+-- | Obtain the schema of the schema corresponding to the specified version.
+bootstrapSchema :: Word8 -> Either WineryException Schema
+bootstrapSchema 4 = Right
+  $ SFix $ SVariant [("SFix",SProduct [SVar 0]),("SVar",SProduct [SInteger]),("SVector",SProduct [SVar 0]),("SProduct",SProduct [SVector (SVar 0)]),("SRecord",SProduct [SVector (SProduct [SText,SVar 0])]),("SVariant",SProduct [SVector (SProduct [SText,SVar 0])]),("SBool",SProduct []),("SChar",SProduct []),("SWord8",SProduct []),("SWord16",SProduct []),("SWord32",SProduct []),("SWord64",SProduct []),("SInt8",SProduct []),("SInt16",SProduct []),("SInt32",SProduct []),("SInt64",SProduct []),("SInteger",SProduct []),("SFloat",SProduct []),("SDouble",SProduct []),("SBytes",SProduct []),("SText",SProduct []),("SUTCTime",SProduct []),("STag",SProduct [SFix (SVariant [("TagInt",SProduct [SInteger]),("TagStr",SProduct [SText]),("TagList",SProduct [SVector (SVar 0)])]),SVar 0]),("SLet",SProduct [SVar 0,SVar 0])]
+bootstrapSchema n = Left $ UnsupportedSchemaVersion n
+
+-- | Common representation for any winery data.
+-- Handy for prettyprinting winery-serialised data.
+data Term = TBool !Bool
+  | TChar !Char
+  | TWord8 !Word8
+  | TWord16 !Word16
+  | TWord32 !Word32
+  | TWord64 !Word64
+  | TInt8 !Int8
+  | TInt16 !Int16
+  | TInt32 !Int32
+  | TInt64 !Int64
+  | TInteger !Integer
+  | TFloat !Float
+  | TDouble !Double
+  | TBytes !B.ByteString
+  | TText !T.Text
+  | TUTCTime !UTCTime
+  | TVector !(V.Vector Term)
+  | TProduct !(V.Vector Term)
+  | TRecord !(V.Vector (T.Text, Term))
+  | TVariant !Int !T.Text Term
+  deriving Show
+
+instance J.ToJSON Term where
+  toJSON (TBool b) = J.toJSON b
+  toJSON (TChar c) = J.toJSON c
+  toJSON (TWord8 w) = J.toJSON w
+  toJSON (TWord16 w) = J.toJSON w
+  toJSON (TWord32 w) = J.toJSON w
+  toJSON (TWord64 w) = J.toJSON w
+  toJSON (TInt8 w) = J.toJSON w
+  toJSON (TInt16 w) = J.toJSON w
+  toJSON (TInt32 w) = J.toJSON w
+  toJSON (TInt64 w) = J.toJSON w
+  toJSON (TInteger w) = J.toJSON w
+  toJSON (TFloat x) = J.toJSON x
+  toJSON (TDouble x) = J.toJSON x
+  toJSON (TBytes bs) = J.toJSON (B.unpack bs)
+  toJSON (TText t) = J.toJSON t
+  toJSON (TUTCTime t) = J.toJSON t
+  toJSON (TVector xs) = J.toJSON xs
+  toJSON (TProduct xs) = J.toJSON xs
+  toJSON (TRecord xs) = J.toJSON $ HM.fromList $ V.toList xs
+  toJSON (TVariant _ "Just" x) = J.toJSON x
+  toJSON (TVariant _ "Nothing" _) = J.Null
+  toJSON (TVariant _ t x) = J.object ["tag" J..= J.toJSON t, "contents" J..= J.toJSON x]
+
+instance Pretty Term where
+  pretty (TWord8 i) = pretty i
+  pretty (TWord16 i) = pretty i
+  pretty (TWord32 i) = pretty i
+  pretty (TWord64 i) = pretty i
+  pretty (TInt8 i) = pretty i
+  pretty (TInt16 i) = pretty i
+  pretty (TInt32 i) = pretty i
+  pretty (TInt64 i) = pretty i
+  pretty (TInteger i) = pretty i
+  pretty (TBytes s) = pretty $ show s
+  pretty (TText s) = pretty s
+  pretty (TVector xs) = list $ map pretty (V.toList xs)
+  pretty (TBool x) = pretty x
+  pretty (TChar x) = pretty x
+  pretty (TFloat x) = pretty x
+  pretty (TDouble x) = pretty x
+  pretty (TProduct xs) = tupled $ map pretty (V.toList xs)
+  pretty (TRecord xs) = align $ encloseSep "{ " " }" ", " [group $ nest 2 $ vsep [pretty k <+> "=", pretty v] | (k, v) <- V.toList xs]
+  pretty (TVariant _ tag (TProduct xs)) = group $ nest 2 $ sep $ pretty tag : map pretty (V.toList xs)
+  pretty (TVariant _ tag x) = group $ nest 2 $ sep [pretty tag, pretty x]
+  pretty (TUTCTime t) = pretty (show t)
+
+-- | 'Extractor' is a 'Plan' that creates a function to extract a value from Term.
+--
+-- The 'Applicative' instance can be used to build a user-defined extractor.
+-- This is also 'Alternative', meaning that fallback plans may be added.
+--
+-- /"Don't get set into one form, adapt it and build your own, and let it grow, be like water."/
+newtype Extractor a = Extractor { getExtractor :: Plan (Term -> a) }
+  deriving Functor
+
+instance Applicative Extractor where
+  pure = Extractor . pure . pure
+  Extractor f <*> Extractor x = Extractor $ (<*>) <$> f <*> x
+
+instance Alternative Extractor where
+  empty = Extractor empty
+  Extractor f <|> Extractor g = Extractor $ f <|> g
+
+data StrategyBind = DynDecoder !Dynamic -- ^ A fixpoint of a decoder
+    | BoundSchema !Int !Schema
+    -- ^ schema bound by 'SLet'. 'Int' is a basis of the variables
+
+data StrategyEnv = StrategyEnv !Int ![StrategyBind]
+
+type Strategy' = Strategy WineryException StrategyEnv
+
+-- | Plan is a monad for computations which interpret 'Schema'.
+newtype Plan a = Plan { unPlan :: Schema -> Strategy' a }
+  deriving Functor
+
+instance Applicative Plan where
+  pure = Plan . const . pure
+  m <*> k = Plan $ \sch -> Strategy $ \decs -> case unStrategy (unPlan m sch) decs of
+    Right f -> f <$> unStrategy (unPlan k sch) decs
+    Left e -> Left e
+
+instance Monad Plan where
+  m >>= k = Plan $ \sch -> Strategy $ \decs -> case unStrategy (unPlan m sch) decs of
+    Right a -> unStrategy (unPlan (k a) sch) decs
+    Left e -> Left e
+
+instance Alternative Plan where
+  empty = Plan $ const empty
+  Plan a <|> Plan b = Plan $ \s -> a s <|> b s
+
+-- | Run an 'Extractor'.
+unwrapExtractor :: Extractor a -> Schema -> Strategy' (Term -> a)
+unwrapExtractor (Extractor m) = unPlan m
+{-# INLINE unwrapExtractor #-}
+
+-- | Exceptions thrown when by an extractor
+data WineryException = UnexpectedSchema !(Doc AnsiStyle) !(Doc AnsiStyle) !Schema
+  | FieldNotFound !(Doc AnsiStyle) !T.Text ![T.Text]
+  | TypeMismatch !Int !TypeRep !TypeRep
+  | ProductTooSmall !Int
+  | UnboundVariable !Int
+  | EmptyInput
+  | WineryMessage !(Doc AnsiStyle)
+  | UnsupportedSchemaVersion !Word8
+  deriving Show
+
+instance Exception WineryException
+
+instance IsString WineryException where
+  fromString = WineryMessage . fromString
+
+-- | Pretty-print 'WineryException'
+prettyWineryException :: WineryException -> Doc AnsiStyle
+prettyWineryException = \case
+  UnexpectedSchema subject expected actual -> annotate bold subject
+    <+> "expects" <+> annotate (color Green <> bold) expected
+    <+> "but got " <+> pretty actual
+  FieldNotFound rep x xs -> rep <> ": field or constructor " <> pretty x <> " not found in " <> pretty xs
+  TypeMismatch i s t -> "A type mismatch in variable"
+    <+> pretty i <> ":"
+    <+> "expected" <> viaShow s
+    <+> "but got " <> viaShow t
+  ProductTooSmall i -> "The product is too small; expecting " <> pretty i
+  UnboundVariable i -> "Unbound variable: " <> pretty i
+  EmptyInput -> "Unexpected empty string"
+  UnsupportedSchemaVersion i -> "Unsupported schema version: " <> pretty i
+  WineryMessage a -> a
diff --git a/src/Codec/Winery/Internal.hs b/src/Codec/Winery/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/Winery/Internal.hs
@@ -0,0 +1,265 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+----------------------------------------------------------------------------
+-- |
+-- Module      :  Codec.Winery.Internal
+-- Copyright   :  (c) Fumiaki Kinoshita 2019
+-- License     :  BSD3
+-- Stability   :  Experimental
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+--
+-- Internal functions and datatypes
+--
+-----------------------------------------------------------------------------
+module Codec.Winery.Internal
+  ( unsignedVarInt
+  , varInt
+  , Decoder
+  , evalDecoder
+  , State(..)
+  , evalState
+  , decodeVarInt
+  , decodeVarIntFinite
+  , getWord8
+  , getWord16
+  , getWord32
+  , getWord64
+  , DecodeException(..)
+  , indexDefault
+  , unsafeIndexV
+  , lookupWithIndexV
+  , Strategy(..)
+  , throwStrategy
+  , TransFusion(..)
+  )where
+
+import Control.Applicative
+import Control.Exception
+import Control.Monad
+import Control.Monad.Fix
+import qualified Data.ByteString as B
+import qualified Data.ByteString.FastBuilder as BB
+import qualified Data.ByteString.Internal as B
+import qualified Data.ByteString.Builder.Prim.Internal as BPI
+import Data.Bits
+import Data.Monoid ((<>))
+import Data.String
+import qualified Data.Vector.Unboxed as U
+import qualified Data.Vector as V
+import Data.Word
+import Foreign.ForeignPtr
+import Foreign.Storable
+import Foreign.Ptr
+import System.Endian
+
+unsignedVarInt :: (Bits a, Integral a) => a -> BB.Builder
+unsignedVarInt n
+  | n < 0x80 = BB.word8 (fromIntegral n)
+  | otherwise = BB.word8 (fromIntegral n `setBit` 7) <> uvarInt (unsafeShiftR n 7)
+{-# INLINE unsignedVarInt #-}
+
+varInt :: (Bits a, Integral a) => a -> BB.Builder
+varInt n
+  | n < 0 = case negate n of
+    n'
+      | n' < 0x40 -> BB.word8 (fromIntegral n' `setBit` 6)
+      | otherwise -> BB.word8 (0xc0 .|. fromIntegral n') <> uvarInt (unsafeShiftR n' 6)
+  | n < 0x40 = BB.word8 (fromIntegral n)
+  | otherwise = BB.word8 (fromIntegral n `setBit` 7 `clearBit` 6) <> uvarInt (unsafeShiftR n 6)
+{-# RULES "varInt/Int" varInt = varIntFinite #-}
+{-# INLINEABLE[1] varInt #-}
+
+varIntFinite :: Int -> BB.Builder
+varIntFinite = BB.primBounded (BPI.boudedPrim 10 writeIntFinite)
+
+writeWord8 :: Word8 -> Ptr Word8 -> IO (Ptr Word8)
+writeWord8 w p = do
+  poke p w
+  return $! plusPtr p 1
+
+writeIntFinite :: Int -> Ptr Word8 -> IO (Ptr Word8)
+writeIntFinite !n
+  | n < 0 = case negate n of
+    n'
+      | n' < 0x40 -> writeWord8 (fromIntegral n' `setBit` 6)
+      | otherwise ->
+          writeWord8 (0xc0 .|. fromIntegral n') >=>
+            writeUnsignedFinite pure (unsafeShiftR n' 6)
+  | n < 0x40 = writeWord8 (fromIntegral n)
+  | otherwise = writeWord8 (fromIntegral n `setBit` 7 `clearBit` 6) >=>
+      writeUnsignedFinite pure (unsafeShiftR n 6)
+{-# INLINE writeIntFinite #-}
+
+writeUnsignedFinite :: (Ptr Word8 -> IO r) -> Int -> Ptr Word8 -> IO r
+writeUnsignedFinite k = go
+  where
+    go m
+      | m < 0x80 = writeWord8 (fromIntegral m) >=> k
+      | otherwise = writeWord8 (setBit (fromIntegral m) 7) >=> go (unsafeShiftR m 7)
+{-# INLINE writeUnsignedFinite #-}
+
+uvarInt :: (Bits a, Integral a) => a -> BB.Builder
+uvarInt = go where
+  go m
+    | m < 0x80 = BB.word8 (fromIntegral m)
+    | otherwise = BB.word8 (setBit (fromIntegral m) 7) <> go (unsafeShiftR m 7)
+{-# INLINE uvarInt #-}
+
+-- | A state monad. The reason being not @State@ from transformers is to
+-- allow coercion for newtype deriving and DerivingVia.
+newtype State s a = State { runState :: s -> (a, s) }
+  deriving Functor
+
+evalState :: State s a -> s -> a
+evalState m = fst . runState m
+{-# INLINE evalState #-}
+
+instance Applicative (State s) where
+  pure a = State $ \s -> (a, s)
+  m <*> k = State $ \s -> case runState m s of
+    (f, s') -> case runState k s' of
+      (a, s'') -> (f a, s'')
+
+instance Monad (State s) where
+  m >>= k = State $ \s -> case runState m s of
+    (a, s') -> runState (k a) s'
+
+instance MonadFix (State s) where
+  mfix f = State $ \s -> fix $ \ ~(a, _) -> runState (f a) s
+
+-- | The Decoder monad
+type Decoder = State B.ByteString
+
+-- | Run a 'Decoder'
+evalDecoder :: Decoder a -> B.ByteString -> a
+evalDecoder = evalState
+{-# INLINE evalDecoder #-}
+
+getWord8 :: Decoder Word8
+getWord8 = State $ \bs -> case B.uncons bs of
+  Nothing -> throw InsufficientInput
+  Just (x, bs') -> (x, bs')
+{-# INLINE getWord8 #-}
+
+-- | Exceptions thrown by a 'Decoder'
+data DecodeException = InsufficientInput
+  | IntegerOverflow
+  | InvalidTag deriving (Eq, Show, Read)
+instance Exception DecodeException
+
+decodeVarIntBase :: (Num a, Bits a) => Decoder a -> Decoder a
+decodeVarIntBase body = getWord8 >>= \case
+  n | testBit n 7 -> do
+      m <- body
+      if testBit n 6
+        then return $! negate $ unsafeShiftL m 6 .|. fromIntegral n .&. 0x3f
+        else return $! unsafeShiftL m 6 .|. clearBit (fromIntegral n) 7
+    | testBit n 6 -> return $ negate $ fromIntegral $ clearBit n 6
+    | otherwise -> return $ fromIntegral n
+{-# INLINE decodeVarIntBase #-}
+
+decodeVarInt :: (Num a, Bits a) => Decoder a
+decodeVarInt = decodeVarIntBase $ getWord8 >>= go
+  where
+    go n
+      | testBit n 7 = do
+        m <- getWord8 >>= go
+        return $! unsafeShiftL m 7 .|. clearBit (fromIntegral n) 7
+      | otherwise = return $ fromIntegral n
+{-# INLINE decodeVarInt #-}
+
+decodeVarIntFinite :: forall a. (Num a, FiniteBits a) => Decoder a
+decodeVarIntFinite = decodeVarIntBase $ getWord8 >>= go 7
+  where
+    go w n
+      | testBit n 7 = do
+        m <- getWord8 >>= go (w + 7)
+        return $! unsafeShiftL m 7 .|. clearBit (fromIntegral n) 7
+      | w + 7 - countLeadingZeros n < finiteBitSize (0 :: a) = return $ fromIntegral n
+      | otherwise = throw IntegerOverflow
+{-# INLINABLE[1] decodeVarIntFinite #-}
+{-# SPECIALISE decodeVarIntFinite :: Decoder Int #-}
+
+getWord16 :: Decoder Word16
+getWord16 = State $ \(B.PS fp ofs len) -> if len >= 2
+  then (B.accursedUnutterablePerformIO $ withForeignPtr fp
+    $ \ptr -> fromLE16 <$> peekByteOff ptr ofs, B.PS fp (ofs + 2) (len - 2))
+  else throw InsufficientInput
+
+getWord32 :: Decoder Word32
+getWord32 = State $ \(B.PS fp ofs len) -> if len >= 4
+  then (B.accursedUnutterablePerformIO $ withForeignPtr fp
+    $ \ptr -> fromLE32 <$> peekByteOff ptr ofs, B.PS fp (ofs + 4) (len - 4))
+  else throw InsufficientInput
+
+getWord64 :: Decoder Word64
+getWord64 = State $ \(B.PS fp ofs len) -> if len >= 8
+  then (B.accursedUnutterablePerformIO $ withForeignPtr fp
+    $ \ptr -> fromLE64 <$> peekByteOff ptr ofs, B.PS fp (ofs + 8) (len - 8))
+  else throw InsufficientInput
+
+unsafeIndexV :: U.Unbox a => String -> U.Vector a -> Int -> a
+unsafeIndexV err xs i
+  | i >= U.length xs || i < 0 = error err
+  | otherwise = U.unsafeIndex xs i
+{-# INLINE unsafeIndexV #-}
+
+lookupWithIndexV :: Eq k => k -> V.Vector (k, v) -> Maybe (Int, v)
+lookupWithIndexV k v = (\i -> (i, snd $ V.unsafeIndex v i))
+  <$> V.findIndex ((k==) . fst) v
+{-# INLINE lookupWithIndexV #-}
+
+indexDefault :: a -> [a] -> Int -> a
+indexDefault err xs i = case drop i xs of
+  x : _ -> x
+  _ -> err
+
+-- | A monad with @Reader [r]@ and @Either WineryException@ combined, used internally
+-- to build an extractor.
+-- @r@ is used to share environment such as extractors for fixpoints.
+newtype Strategy e r a = Strategy { unStrategy :: r -> Either e a }
+  deriving Functor
+
+instance Applicative (Strategy e r) where
+  pure = return
+  (<*>) = ap
+
+instance Monad (Strategy e r) where
+  return = Strategy . const . Right
+  m >>= k = Strategy $ \decs -> case unStrategy m decs of
+    Right a -> unStrategy (k a) decs
+    Left e -> Left e
+
+instance IsString e => Alternative (Strategy e r) where
+  empty = Strategy $ const $ Left "empty"
+  Strategy a <|> Strategy b = Strategy $ \decs -> case a decs of
+    Left _ -> b decs
+    Right x -> Right x
+
+instance MonadFix (Strategy e r) where
+  mfix f = Strategy $ \r -> mfix $ \a -> unStrategy (f a) r
+  {-# INLINE mfix #-}
+
+throwStrategy :: e -> Strategy e r a
+throwStrategy = Strategy . const . Left
+
+-- | A Bazaar (chain of indexed store comonad)-like structure which instead
+-- works for natural transformations.
+newtype TransFusion f g a = TransFusion { unTransFusion :: forall h. Applicative h => (forall x. f x -> h (g x)) -> h a }
+
+instance Functor (TransFusion f g) where
+  fmap f (TransFusion m) = TransFusion $ \k -> fmap f (m k)
+  {-# INLINE fmap #-}
+
+instance Applicative (TransFusion f g) where
+  pure a = TransFusion $ \_ -> pure a
+  TransFusion a <*> TransFusion b = TransFusion $ \k -> a k <*> b k
+  {-# INLINE (<*>) #-}
diff --git a/src/Codec/Winery/Query.hs b/src/Codec/Winery/Query.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/Winery/Query.hs
@@ -0,0 +1,77 @@
+{-# LANGUAGE DeriveFunctor #-}
+----------------------------------------------------------------------------
+-- |
+-- Module      :  Codec.Winery.Query
+-- Copyright   :  (c) Fumiaki Kinoshita 2019
+-- License     :  BSD3
+-- Stability   :  Experimental
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+--
+-- Building blocks for winery queries.
+--
+-----------------------------------------------------------------------------
+module Codec.Winery.Query (Query(..)
+  , invalid
+  , list
+  , range
+  , field
+  , con
+  , select) where
+
+import Prelude hiding ((.), id)
+import Control.Applicative
+import Control.Category
+import Codec.Winery
+import Codec.Winery.Internal
+import Data.Typeable
+import qualified Data.Text as T
+import qualified Data.Vector as V
+
+-- | Query is a transformation between 'Extractor's.
+-- Like jq, this returns a list of values.
+newtype Query a b = Query
+  { runQuery :: Extractor [a] -> Extractor [b] }
+  deriving Functor
+
+instance Category Query where
+  id = Query id
+  Query f . Query g = Query $ f . g
+
+instance Applicative (Query a) where
+  pure a = Query $ const $ pure [a]
+  Query f <*> Query g = Query $ \d -> (<*>) <$> f d <*> g d
+
+instance Alternative (Query a) where
+  empty = Query $ const $ pure []
+  Query f <|> Query g = Query $ \d -> (++) <$> f d <*> g d
+
+-- | Throw an error.
+invalid :: WineryException -> Query a b
+invalid = Query . const . Extractor . Plan . const . throwStrategy
+
+-- | Takes a list and traverses on it.
+list :: Typeable a => Query a a
+list = Query $ fmap concat . extractListBy
+
+-- | Takes a list and enumerates elements in the specified range.
+-- Like Python's array slicing, negative numbers counts from the last element.
+range :: Typeable a => Int -> Int -> Query a a
+range i j = Query $ fmap (\v -> foldMap id
+  $ V.backpermute v (V.enumFromTo (i `mod` V.length v) (j `mod` V.length v)))
+  . extractListBy
+
+-- | Takes a record and extracts the specified field.
+field :: Typeable a => T.Text -> Query a a
+field name = Query $ \d -> buildExtractor $ extractFieldBy d name
+
+-- | Takes a variant and returns a value when the constructor matches.
+con :: Typeable a => T.Text -> Query a a
+con name = Query $ \d -> buildExtractor $ extractConstructorBy (d, name, id) (pure [])
+
+-- | Propagate values if the supplied 'Query' doesn't return False.
+select :: Query a Bool -> Query a a
+select qp = Query $ \d -> Extractor $ Plan $ \sch -> do
+  p <- unwrapExtractor (runQuery qp d) sch
+  dec <- unwrapExtractor d sch
+  return $ \bs -> [x | and $ p bs, x <- dec bs]
diff --git a/src/Codec/Winery/Query/Parser.hs b/src/Codec/Winery/Query/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/Winery/Query/Parser.hs
@@ -0,0 +1,61 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE GADTs #-}
+----------------------------------------------------------------------------
+-- |
+-- Module      :  Codec.Winery.Query.Parser
+-- Copyright   :  (c) Fumiaki Kinoshita 2019
+-- License     :  BSD3
+-- Stability   :  Experimental
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+--
+-- The language for winery queries
+--
+-- See the Pretty-printing section of README.md for examples.
+--
+-----------------------------------------------------------------------------
+module Codec.Winery.Query.Parser (parseQuery) where
+
+import Prelude hiding ((.), id)
+import Control.Category
+import Codec.Winery.Query
+import Text.Megaparsec
+import Text.Megaparsec.Char
+import qualified Text.Megaparsec.Char.Lexer as L
+import qualified Data.Text as T
+import Data.Text.Prettyprint.Doc (Doc, hsep)
+import Data.Typeable
+import Data.Void
+
+type Parser = Parsec Void T.Text
+
+symbol :: T.Text -> Parser T.Text
+symbol = L.symbol space
+
+name :: Parser T.Text
+name = fmap T.pack (some (alphaNumChar <|> oneOf ("_\'" :: [Char])) <?> "field name")
+
+parseQuery :: Typeable a => Parser (Query (Doc a) (Doc a))
+parseQuery = foldr (.) id <$> sepBy1 parseTerms (symbol "|")
+
+-- | Space-separated list of terms translate to a tabular output, applying the
+-- queries in parallel
+parseTerms :: Typeable a => Parser (Query (Doc a) (Doc a))
+parseTerms = fmap hsep . sequenceA <$> sepBy1 parseTerm space
+
+parseTerm :: Typeable a => Parser (Query (Doc a) (Doc a))
+parseTerm = L.lexeme space $ choice
+  [ char '.' >> choice
+    [ do
+      _ <- char '['
+      i <- optional L.decimal
+      j <- optional (symbol ":" >> L.decimal)
+      _ <- char ']'
+      return $ range (maybe 0 id i) (maybe (-1) id j)
+    , field <$> name
+    , return id
+    ]
+  ]
diff --git a/src/Codec/Winery/Test.hs b/src/Codec/Winery/Test.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/Winery/Test.hs
@@ -0,0 +1,249 @@
+{-# LANGUAGE Rank2Types, ScopedTypeVariables #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE DefaultSignatures #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE AllowAmbiguousTypes #-}
+----------------------------------------------------------------------------
+-- |
+-- Module      :  Codec.Winery.Test
+-- Copyright   :  (c) Fumiaki Kinoshita 2019
+-- License     :  BSD3
+-- Stability   :  Experimental
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+--
+-- A test framework that allows you to test all related Serialise instances
+-- with automatically-generated test cases
+--
+-----------------------------------------------------------------------------
+module Codec.Winery.Test
+  ( -- * Generating tests
+  TestGen(..)
+  , printTests
+  -- * Test cases
+  , Tested(..)
+  , testCase
+  -- * Running tests
+  , allTests
+  , mergeTests
+  ) where
+
+import Test.HUnit
+import qualified Data.Map as M
+import qualified Data.HashMap.Strict as HM
+import qualified Data.ByteString as B
+import Data.Functor.Identity
+import Data.Hashable
+import Data.Proxy
+import qualified Data.Sequence as S
+import Data.Typeable
+import Codec.Winery
+import Data.Word
+import Data.Void
+import qualified Data.Vector as V
+import qualified Data.Vector.Unboxed as UV
+import GHC.Generics
+import Text.Show
+import qualified Data.Text as T
+
+-- | Construct a test case.
+testCase :: (Show a, Eq a, Serialise a)
+  => Schema -- ^ the schema
+  -> B.ByteString -- ^ serialised
+  -> a -- ^ expected
+  -> Test
+testCase sch bs expected = case getDecoder sch of
+  Left err -> TestCase $ assertFailure (show err)
+  Right f -> expected ~=? evalDecoder f bs
+
+-- | Merge multiple tests into one.
+mergeTests :: M.Map TypeRep [Test] -> Test
+mergeTests = TestList . concatMap (\(k, v) -> map (show k ~:) v) . M.toList
+
+-- | Gather all test cases involved in the specified type.
+allTests :: forall a. (TestGen a, Tested a) => M.Map TypeRep [Test]
+allTests = M.insertWith (++) (typeRep (Proxy @ a)) (testCases @ a) (inheritedTests (Proxy @ a))
+
+-- | Types with concrete test cases.
+--
+-- /"Doubt is useful, it keeps faith a living thing. After all, you cannot know
+-- the strength of your faith until it has been tested."/
+class TestGen a => Tested a where
+  -- | List of test cases for the type.
+  testCases :: [Test]
+
+-- these are already covered by the QuickCheck tests from winery
+instance Tested Void where testCases = []
+instance Tested Bool where testCases = []
+instance Tested Int where testCases = []
+instance Tested Word8 where testCases = []
+instance Tested Word16 where testCases = []
+instance Tested Word32 where testCases = []
+instance Tested Word64 where testCases = []
+instance Tested Float where testCases = []
+instance Tested Double where testCases = []
+instance Tested () where testCases = []
+instance Tested Char where testCases = []
+instance Tested T.Text where testCases = []
+instance Tested B.ByteString where testCases = []
+instance Tested a => Tested (Identity a) where
+  testCases = testCases @ a
+instance Tested a => Tested (S.Seq a) where testCases = []
+instance Tested a => Tested [a] where testCases = []
+instance (Tested a, Tested b) => Tested (Either a b) where testCases = []
+instance (Tested a, Tested b) => Tested (a, b) where testCases = []
+instance (Tested a, Tested b, Tested c) => Tested (a, b, c) where testCases = []
+instance (Tested a, Tested b, Tested c, Tested d) => Tested (a, b, c, d) where testCases = []
+instance Tested a => Tested (V.Vector a) where testCases = []
+instance (UV.Unbox a, Tested a) => Tested (UV.Vector a) where testCases = []
+instance (Hashable k, Tested k, Tested a) => Tested (HM.HashMap k a) where testCases = []
+instance (Ord k, Tested k, Tested a) => Tested (M.Map k a) where testCases = []
+
+-- | Generate test cases and print them to the standard output.
+printTests :: forall a. (TestGen a, Serialise a, Show a) => IO ()
+printTests = putStrLn $ showTests (genTestCases :: [a])
+
+showTests :: (Serialise a, Show a) => [a] -> String
+showTests xs = showListWith ppTest xs ""
+
+ppTest :: (Serialise a, Show a) => a -> ShowS
+ppTest a = showString "testCase "
+  . showsPrec 11 (schema [a])
+  . showChar ' '
+  . showsPrec 11 (serialiseOnly a)
+  . showChar ' '
+  . showsPrec 11 a
+
+-- | A class to provide test values and gather tests for its components.
+-- It is recommended to use the generic default methods.
+class Typeable a => TestGen a where
+  -- | A list of values that can be used as test cases.
+  -- It should contain at least one value as long as there is a non-bottom value
+  -- in the type.
+  genTestCases :: [a]
+
+  -- | Inherited set of test cases for each type it involves.
+  inheritedTests :: Proxy a -> M.Map TypeRep [Test]
+
+  default genTestCases :: (Generic a, GTestGen (Rep a)) => [a]
+  genTestCases = fmap to ggenTestCases
+
+  default inheritedTests :: (GTestGen (Rep a)) => Proxy a -> M.Map TypeRep [Test]
+  inheritedTests _ = ginheritedTests (Proxy @ (Rep a))
+
+class GTestGen f where
+  ggenTestCases :: [f x]
+  ginheritedTests :: proxy f -> M.Map TypeRep [Test]
+
+instance GTestGen V1 where
+  ggenTestCases = mempty
+  ginheritedTests _ = mempty
+
+instance GTestGen U1 where
+  ggenTestCases = [U1]
+  ginheritedTests _ = mempty
+
+instance GTestGen f => GTestGen (Rec1 f) where
+  ggenTestCases = fmap Rec1 ggenTestCases
+  ginheritedTests _ = ginheritedTests (Proxy @ f)
+
+instance (Tested c, TestGen c) => GTestGen (K1 i c) where
+  ggenTestCases = fmap K1 genTestCases
+  ginheritedTests _ = allTests @ c
+
+instance GTestGen f => GTestGen (M1 i c f) where
+  ggenTestCases = fmap M1 ggenTestCases
+  ginheritedTests _ = ginheritedTests (Proxy @ f)
+
+instance (GTestGen f, GTestGen g) => GTestGen (f :+: g) where
+  ggenTestCases = fmap L1 ggenTestCases ++ fmap R1 ggenTestCases
+  ginheritedTests _ = ginheritedTests (Proxy @ f)
+    `mappend` ginheritedTests (Proxy @ g)
+
+instance (GTestGen f, GTestGen g) => GTestGen (f :*: g) where
+  ggenTestCases = ((:*:) <$> ggenTestCases <*> xs)
+    ++ ((:*:) <$> take 1 ggenTestCases <*> ys)
+    where
+      (xs, ys) = splitAt 1 ggenTestCases
+  ginheritedTests _ = ginheritedTests (Proxy @ f)
+    `mappend` ginheritedTests (Proxy @ g)
+
+deriving instance TestGen a => TestGen (Identity a)
+instance TestGen ()
+instance TestGen Bool
+instance (Tested a, Tested b) => TestGen (a, b)
+instance (Tested a, Tested b, Tested c) => TestGen (a, b, c)
+instance (Tested a, Tested b, Tested c, Tested d) => TestGen (a, b, c, d)
+instance (Tested a, Tested b) => TestGen (Either a b)
+
+instance Tested a => TestGen [a] where
+  genTestCases = [[]]
+  inheritedTests _ = allTests @ a
+
+instance Tested a => TestGen (S.Seq a) where
+  genTestCases = [mempty]
+  inheritedTests _ = allTests @ a
+
+instance Tested a => TestGen (V.Vector a) where
+  genTestCases = [V.empty]
+  inheritedTests _ = allTests @ a
+
+instance (UV.Unbox a, Tested a) => TestGen (UV.Vector a) where
+  genTestCases = [UV.empty]
+  inheritedTests _ = allTests @ a
+
+instance (Hashable k, Tested k, Tested a) => TestGen (HM.HashMap k a) where
+  genTestCases = HM.singleton <$> genTestCases <*> genTestCases
+  inheritedTests _ = allTests @ k `mappend` allTests @ a
+
+instance (Ord k, Tested k, Tested a) => TestGen (M.Map k a) where
+  genTestCases = [M.empty]
+  inheritedTests _ = allTests @ k `mappend` allTests @ a
+
+instance TestGen Void where
+  genTestCases = []
+  inheritedTests = mempty
+
+instance TestGen Int where
+  genTestCases = [42]
+  inheritedTests = mempty
+
+instance TestGen Word8 where
+  genTestCases = [42]
+  inheritedTests = mempty
+
+instance TestGen Word16 where
+  genTestCases = [42]
+  inheritedTests = mempty
+
+instance TestGen Word32 where
+  genTestCases = [42]
+  inheritedTests = mempty
+
+instance TestGen Word64 where
+  genTestCases = [42]
+  inheritedTests = mempty
+
+instance TestGen Float where
+  genTestCases = [pi]
+  inheritedTests = mempty
+
+instance TestGen Double where
+  genTestCases = [pi]
+  inheritedTests = mempty
+
+instance TestGen Char where
+  genTestCases = ['X']
+  inheritedTests = mempty
+
+instance TestGen T.Text where
+  genTestCases = [mempty]
+  inheritedTests = mempty
+
+instance TestGen B.ByteString where
+  genTestCases = [mempty]
+  inheritedTests = mempty
diff --git a/src/Data/Winery.hs b/src/Data/Winery.hs
--- a/src/Data/Winery.hs
+++ b/src/Data/Winery.hs
@@ -1,1273 +1,5 @@
-{-# LANGUAGE ApplicativeDo #-}
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE OverloadedLists #-}
-{-# LANGUAGE PolyKinds #-}
-{-# LANGUAGE TypeApplications #-}
-#if __GLASGOW_HASKELL__ < 806
-{-# LANGUAGE TypeInType #-}
-#endif
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE TypeOperators #-}
-{-# LANGUAGE UndecidableInstances #-}
-{-# LANGUAGE StandaloneDeriving #-}
-----------------------------------------------------------------------------
--- |
--- Module      :  Data.Winery
--- Copyright   :  (c) Fumiaki Kinoshita 2019
--- License     :  BSD3
--- Stability   :  Provisional
---
--- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
---
--- The standard interface of winery serialisation library
---
------------------------------------------------------------------------------
-module Data.Winery
-  ( Schema
-  , SchemaP(..)
-  , Tag(..)
-  , Serialise(..)
-  , testSerialise
-  , DecodeException(..)
-  , schema
-  -- * Standalone serialisation
-  , toBuilderWithSchema
-  , serialise
-  , deserialise
-  , deserialiseBy
-  , deserialiseTerm
-  , splitSchema
-  , writeFileSerialise
-  -- * Separate serialisation
-  , serialiseSchema
-  , deserialiseSchema
-  , Extractor(..)
-  , unwrapExtractor
-  , Decoder
-  , evalDecoder
-  , serialiseOnly
-  , getDecoder
-  , getDecoderBy
-  -- * Decoding combinators
-  , Term(..)
-  , Subextractor(..)
-  , buildExtractor
-  , extractListBy
-  , extractField
-  , extractFieldBy
-  , extractConstructor
-  , extractConstructorBy
-  , extractVoid
-  , ExtractException(..)
-  -- * Variable-length quantity
-  , VarInt(..)
-  -- * Internal
-  , WineryException(..)
-  , prettyWineryException
-  , unexpectedSchema
-  , SchemaGen
-  , getSchema
-  , Plan(..)
-  , mkPlan
-  -- * DerivingVia
-  , WineryRecord(..)
-  , WineryVariant(..)
-  , WineryProduct(..)
-  -- * Generic implementations (for old GHC / custom instances)
-  , GSerialiseRecord
-  , gschemaGenRecord
-  , GEncodeProduct
-  , gtoBuilderRecord
-  , gextractorRecord
-  , gdecodeCurrentRecord
-  , GSerialiseVariant
-  , gschemaGenVariant
-  , gtoBuilderVariant
-  , gextractorVariant
-  , gschemaGenProduct
-  , gtoBuilderProduct
-  , gdecodeCurrentVariant
-  , gextractorProduct
-  , gdecodeCurrentProduct
-  -- * Bundles
-  , BundleSerialise(..)
-  , bundleRecord
-  , bundleRecordDefault
-  , bundleVariant
-  -- * Preset schema
-  , bootstrapSchema
-  )where
-
-import Control.Applicative
-import Control.Exception
-import Control.Monad.Reader
-import qualified Data.ByteString as B
-import qualified Data.ByteString.FastBuilder as BB
-import qualified Data.ByteString.Lazy as BL
-import Data.Bits
-import Data.Complex
-import Data.Dynamic
-import Data.Fixed
-import Data.Functor.Compose
-import Data.Functor.Identity
-import Data.List (elemIndex)
-import Data.Monoid as M
-import Data.Proxy
-import Data.Ratio
-import Data.Scientific (Scientific, scientific, coefficient, base10Exponent)
-import Data.Semigroup as S
-import Data.Hashable (Hashable)
-import qualified Data.HashMap.Strict as HM
-import Data.Int
-import qualified Data.IntMap as IM
-import qualified Data.IntSet as IS
-import qualified Data.Map as M
-import Data.Ord
-import Data.Word
-import Data.Winery.Base as W
-import Data.Winery.Internal
-import qualified Data.Sequence as Seq
-import qualified Data.Set as S
-import qualified Data.Text as T
-import qualified Data.Text.Encoding as T
-import qualified Data.Text.Encoding.Error as T
-import qualified Data.Vector as V
-import qualified Data.Vector.Storable as SV
-import qualified Data.Vector.Unboxed as UV
-import Data.Text.Prettyprint.Doc hiding ((<>), SText, SChar)
-import Data.Text.Prettyprint.Doc.Render.Terminal
-import Data.Time.Clock
-import Data.Time.Clock.POSIX
-import Data.Typeable
-import Data.Void
-import Unsafe.Coerce
-import GHC.Float (castWord32ToFloat, castWord64ToDouble)
-import GHC.Natural
-import GHC.Generics
-import GHC.TypeLits
-import System.IO
-import qualified Test.QuickCheck as QC
-
--- | Deserialiser for a 'Term'.
---
--- /"I will read anything rather than work."/
-decodeTerm :: Schema -> Decoder Term
-decodeTerm = go [] where
-  go points = \case
-    SBool -> TBool <$> decodeCurrent
-    W.SChar -> TChar <$> decodeCurrent
-    SWord8 -> TWord8 <$> getWord8
-    SWord16 -> TWord16 <$> getWord16
-    SWord32 -> TWord32 <$> getWord32
-    SWord64 -> TWord64 <$> getWord64
-    SInt8 -> TInt8 <$> decodeCurrent
-    SInt16 -> TInt16 <$> decodeCurrent
-    SInt32 -> TInt32 <$> decodeCurrent
-    SInt64 -> TInt64 <$> decodeCurrent
-    SInteger -> TInteger <$> decodeVarInt
-    SFloat -> TFloat <$> decodeCurrent
-    SDouble -> TDouble <$> decodeCurrent
-    SBytes -> TBytes <$> decodeCurrent
-    W.SText -> TText <$> decodeCurrent
-    SUTCTime -> TUTCTime <$> decodeCurrent
-    SVector sch -> do
-      n <- decodeVarInt
-      TVector <$> V.replicateM n (go points sch)
-    SProduct schs -> TProduct <$> traverse (go points) schs
-    SRecord schs -> TRecord <$> traverse (\(k, s) -> (,) k <$> go points s) schs
-    SVariant schs -> do
-      let !decoders = V.map (\(name, sch) -> let !m = go points sch in (name, m)) schs
-      tag <- decodeVarInt
-      let (name, dec) = maybe (throw InvalidTag) id $ decoders V.!? tag
-      TVariant tag name <$> dec
-    SVar i -> indexDefault (throw InvalidTag) points i
-    SFix s' -> fix $ \a -> go (a : points) s'
-    STag _ s -> go points s
-    SLet s t -> go (go points s : points) t
-
--- | Deserialise a 'serialise'd 'B.Bytestring'.
-deserialiseTerm :: B.ByteString -> Either WineryException (Schema, Term)
-deserialiseTerm bs_ = do
-  (sch, bs) <- splitSchema bs_
-  return (sch, decodeTerm sch `evalDecoder` bs)
-
--- | This may be thrown if illegal 'Term' is passed to an extractor.
-data ExtractException = InvalidTerm !Term deriving Show
-instance Exception ExtractException
-
--- | Serialisable datatype
---
-class Typeable a => Serialise a where
-  -- | Obtain the schema of the datatype.
-  schemaGen :: Proxy a -> SchemaGen Schema
-  schemaGen = bundleSchemaGen bundleSerialise
-  {-# INLINE schemaGen #-}
-
-  -- | Serialise a value.
-  toBuilder :: a -> BB.Builder
-  toBuilder = bundleToBuilder bundleSerialise
-  {-# INLINE toBuilder #-}
-
-  -- | A value of 'Extractor a' interprets a schema and builds a function from
-  -- 'Term' to @a@. This must be equivalent to 'decodeCurrent' when the schema
-  -- is the current one.
-  --
-  -- If @'extractor' s@ returns a function, the function must return a
-  -- non-bottom for any 'Term' @'decodeTerm' s@ returns.
-  --
-  -- It must not return a function if an unsupported schema is supplied.
-  --
-  -- @getDecoderBy extractor (schema (Proxy @ a))@ must be @Right d@
-  -- where @d@ is equivalent to 'decodeCurrent'.
-  --
-  extractor :: Extractor a
-  extractor = bundleExtractor bundleSerialise
-  {-# INLINE extractor #-}
-
-  -- | Decode a value with the current schema.
-  --
-  -- @'decodeCurrent' `evalDecoder` 'toBuilder' x@ ≡ x
-  decodeCurrent :: Decoder a
-  decodeCurrent = bundleDecodeCurrent bundleSerialise
-  {-# INLINE decodeCurrent #-}
-
-  -- | Instead of the four methods above, you can supply a bundle.
-  bundleSerialise :: BundleSerialise a
-  bundleSerialise = BundleSerialise
-    { bundleSchemaGen = schemaGen
-    , bundleToBuilder = toBuilder
-    , bundleExtractor = extractor
-    , bundleDecodeCurrent = decodeCurrent
-    }
-
-  {-# MINIMAL schemaGen, toBuilder, extractor, decodeCurrent | bundleSerialise #-}
-
--- | A bundle of 'Serialise' methods
-data BundleSerialise a = BundleSerialise
-  { bundleSchemaGen :: Proxy a -> SchemaGen Schema
-  , bundleToBuilder :: a -> BB.Builder
-  , bundleExtractor :: Extractor a
-  , bundleDecodeCurrent :: Decoder a
-  }
-
-bundleRecord :: (GEncodeProduct (Rep a), GSerialiseRecord (Rep a), Generic a, Typeable a)
-  => (Extractor a -> Extractor a) -- extractor modifier
-  -> BundleSerialise a
-bundleRecord f = BundleSerialise
-  { bundleSchemaGen = gschemaGenRecord
-  , bundleToBuilder = gtoBuilderRecord
-  , bundleExtractor = f $ gextractorRecord Nothing
-  , bundleDecodeCurrent = gdecodeCurrentRecord
-  }
-{-# INLINE bundleRecord #-}
-
-bundleRecordDefault :: (GEncodeProduct (Rep a), GSerialiseRecord (Rep a), Generic a, Typeable a)
-  => a -- default value
-  -> (Extractor a -> Extractor a) -- extractor modifier
-  -> BundleSerialise a
-bundleRecordDefault def f = BundleSerialise
-  { bundleSchemaGen = gschemaGenRecord
-  , bundleToBuilder = gtoBuilderRecord
-  , bundleExtractor = f $ gextractorRecord $ Just def
-  , bundleDecodeCurrent = gdecodeCurrentRecord
-  }
-{-# INLINE bundleRecordDefault #-}
-
-bundleVariant :: (GSerialiseVariant (Rep a), Generic a, Typeable a)
-  => (Extractor a -> Extractor a) -- extractor modifier
-  -> BundleSerialise a
-bundleVariant f = BundleSerialise
-  { bundleSchemaGen = gschemaGenVariant
-  , bundleToBuilder = gtoBuilderVariant
-  , bundleExtractor = f $ gextractorVariant
-  , bundleDecodeCurrent = gdecodeCurrentVariant
-  }
-{-# INLINE bundleVariant #-}
-
--- | Check the integrity of a Serialise instance.
---
--- /"No tears in the writer, no tears in the reader. No surprise in the writer, no surprise in the reader."/
-testSerialise :: forall a. (Eq a, Show a, Serialise a) => a -> QC.Property
-testSerialise x = case getDecoderBy extractor (schema (Proxy @ a)) of
-  Left e -> QC.counterexample (show e) False
-  Right f -> QC.counterexample "extractor" (evalDecoder f b QC.=== x)
-    QC..&&. QC.counterexample "decodeCurrent" (evalDecoder decodeCurrent b QC.=== x)
-  where
-    b = serialiseOnly x
-
-decodeCurrentDefault :: forall a. Serialise a => Decoder a
-decodeCurrentDefault = case getDecoderBy extractor (schema (Proxy @ a)) of
-  Left err -> error $ "decodeCurrentDefault: failed to get a decoder from the current schema"
-    ++ show err
-  Right a -> a
-
--- | Schema generator
-newtype SchemaGen a = SchemaGen { unSchemaGen :: S.Set TypeRep -> (S.Set TypeRep, [TypeRep] -> a) }
-
-instance Functor SchemaGen where
-  fmap f m = SchemaGen $ \s -> case unSchemaGen m s of
-    (rep, k) -> (rep, f . k)
-
-instance Applicative SchemaGen where
-  pure a = SchemaGen $ const (S.empty, const a)
-  m <*> n = SchemaGen $ \s -> case unSchemaGen m s of
-    (rep, f) -> case unSchemaGen n s of
-      (rep', g) -> (mappend rep rep', f <*> g)
-
--- | Obtain a schema on 'SchemaGen', binding a fixpoint when necessary.
--- If you are hand-rolling a definition of 'schemaGen', you should call this
--- instead of 'schemaGen'.
-getSchema :: forall proxy a. Serialise a => proxy a -> SchemaGen Schema
-getSchema p = SchemaGen $ \seen -> if S.member rep seen
-  then (S.singleton rep, \xs -> case elemIndex rep xs of
-    Just i -> SVar i
-    Nothing -> error $ "getSchema: impossible " ++ show (rep, seen, xs))
-    -- request a fixpoint for rep when it detects a recursion
-  else case unSchemaGen (schemaGen (Proxy @ a)) (S.insert rep seen) of
-    (reps, f)
-      | S.member rep reps -> (reps, \xs -> SFix $ f (rep : xs))
-      | otherwise -> (reps, f)
-  where
-    rep = typeRep p
-
--- | Obtain the schema of the datatype.
---
--- /"Tell me what you drink, and I will tell you what you are."/
-schema :: forall proxy a. Serialise a => proxy a -> Schema
-schema p = case unSchemaGen (schemaGen (Proxy @ a)) (S.singleton rep) of
-  (reps, f)
-    | S.member rep reps -> SFix $ f [rep]
-    | otherwise -> f []
-  where
-    rep = typeRep p
-
--- | Obtain a decoder from a schema.
---
--- /"A reader lives a thousand lives before he dies... The man who never reads lives only one."/
-getDecoder :: forall a. Serialise a => Schema -> Either WineryException (Decoder a)
-getDecoder sch
-  | sch == schema (Proxy @ a) = Right decodeCurrent
-  | otherwise = getDecoderBy extractor sch
-{-# INLINE getDecoder #-}
-
--- | Get a decoder from a `Extractor` and a schema.
-getDecoderBy :: Extractor a -> Schema -> Either WineryException (Decoder a)
-getDecoderBy (Extractor plan) sch = (\f -> f <$> decodeTerm sch)
-  <$> unPlan plan sch `unStrategy` StrategyEnv 0 []
-{-# INLINE getDecoderBy #-}
-
--- | Serialise a value along with its schema.
---
--- /"Write the vision, and make it plain upon tables, that he may run that readeth it."/
-serialise :: Serialise a => a -> B.ByteString
-serialise = BL.toStrict . BB.toLazyByteString . toBuilderWithSchema
-{-# INLINE serialise #-}
-
--- | Serialise a value along with its schema.
-writeFileSerialise :: Serialise a => FilePath -> a -> IO ()
-writeFileSerialise path a = withBinaryFile path WriteMode
-  $ \h -> BB.hPutBuilder h $ toBuilderWithSchema a
-{-# INLINE writeFileSerialise #-}
-
-toBuilderWithSchema :: forall a. Serialise a => a -> BB.Builder
-toBuilderWithSchema a = mappend (BB.word8 currentSchemaVersion)
-  $ toBuilder (schema (Proxy @ a), a)
-{-# INLINE toBuilderWithSchema #-}
-
-splitSchema :: B.ByteString -> Either WineryException (Schema, B.ByteString)
-splitSchema bs_ = case B.uncons bs_ of
-  Just (ver, bs) -> do
-    m <- getDecoder $ bootstrapSchema ver
-    return $ flip evalDecoder bs $ do
-      sch <- m
-      State $ \bs' -> ((sch, bs'), mempty)
-  Nothing -> Left EmptyInput
-
--- | Serialise a schema.
-serialiseSchema :: Schema -> B.ByteString
-serialiseSchema = BL.toStrict . BB.toLazyByteString
-  . mappend (BB.word8 currentSchemaVersion) . toBuilder
-
--- | Deserialise a 'serialise'd 'B.Bytestring'.
---
--- /"Old wood to burn! Old wine to drink! Old friends to trust! Old authors to read!"/
-deserialise :: Serialise a => B.ByteString -> Either WineryException a
-deserialise bs_ = do
-  (sch, bs) <- splitSchema bs_
-  dec <- getDecoder sch
-  return $ evalDecoder dec bs
-{-# INLINE deserialise #-}
-
--- | Deserialise a 'serialise'd 'B.Bytestring' using an 'Extractor'.
-deserialiseBy :: Extractor a -> B.ByteString -> Either WineryException a
-deserialiseBy e bs_ = do
-  (sch, bs) <- splitSchema bs_
-  dec <- getDecoderBy e sch
-  return $ evalDecoder dec bs
-
--- | Serialise a schema.
-deserialiseSchema :: B.ByteString -> Either WineryException Schema
-deserialiseSchema bs_ = case B.uncons bs_ of
-  Just (ver, bs) -> do
-    m <- getDecoder $ bootstrapSchema ver
-    return $ evalDecoder m bs
-  Nothing -> Left EmptyInput
-
--- | Serialise a value without its schema.
---
--- /"Any unsaved progress will be lost."/
-serialiseOnly :: Serialise a => a -> B.ByteString
-serialiseOnly = BL.toStrict . BB.toLazyByteString . toBuilder
-{-# INLINE serialiseOnly #-}
-
-unexpectedSchema :: forall f a. Serialise a => Doc AnsiStyle -> Schema -> Strategy' (f a)
-unexpectedSchema subject actual = throwStrategy
-  $ UnexpectedSchema subject (pretty $ schema (Proxy @ a)) actual
-
-instance Serialise Tag where
-  schemaGen = gschemaGenVariant
-  toBuilder = gtoBuilderVariant
-  extractor = gextractorVariant
-  decodeCurrent = gdecodeCurrentVariant
-
-instance Serialise Schema where
-  schemaGen = gschemaGenVariant
-  toBuilder = gtoBuilderVariant
-  extractor = gextractorVariant
-  decodeCurrent = gdecodeCurrentVariant
-
-instance Serialise () where
-  schemaGen _ = pure $ SProduct []
-  toBuilder = mempty
-  {-# INLINE toBuilder #-}
-  extractor = pure ()
-  decodeCurrent = pure ()
-
-instance Serialise Bool where
-  schemaGen _ = pure SBool
-  toBuilder False = BB.word8 0
-  toBuilder True = BB.word8 1
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SBool -> pure $ \case
-      TBool b -> b
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Bool" s
-  decodeCurrent = (/=0) <$> getWord8
-
-instance Serialise Word8 where
-  schemaGen _ = pure SWord8
-  toBuilder = BB.word8
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SWord8 -> pure $ \case
-      TWord8 i -> i
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Word8" s
-  decodeCurrent = getWord8
-
-instance Serialise Word16 where
-  schemaGen _ = pure SWord16
-  toBuilder = BB.word16LE
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SWord16 -> pure $ \case
-      TWord16 i -> i
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Word16" s
-  decodeCurrent = getWord16
-
-instance Serialise Word32 where
-  schemaGen _ = pure SWord32
-  toBuilder = BB.word32LE
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SWord32 -> pure $ \case
-      TWord32 i -> i
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Word32" s
-  decodeCurrent = getWord32
-
-instance Serialise Word64 where
-  schemaGen _ = pure SWord64
-  toBuilder = BB.word64LE
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SWord64 -> pure $ \case
-      TWord64 i -> i
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Word64" s
-  decodeCurrent = getWord64
-
-instance Serialise Word where
-  schemaGen _ = pure SWord64
-  toBuilder = BB.word64LE . fromIntegral
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SWord64 -> pure $ \case
-      TWord64 i -> fromIntegral i
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Word" s
-  decodeCurrent = fromIntegral <$> getWord64
-
-instance Serialise Int8 where
-  schemaGen _ = pure SInt8
-  toBuilder = BB.word8 . fromIntegral
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SInt8 -> pure $ \case
-      TInt8 i -> i
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Int8" s
-  decodeCurrent = fromIntegral <$> getWord8
-
-instance Serialise Int16 where
-  schemaGen _ = pure SInt16
-  toBuilder = BB.word16LE . fromIntegral
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SInt16 -> pure $ \case
-      TInt16 i -> i
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Int16" s
-  decodeCurrent = fromIntegral <$> getWord16
-
-instance Serialise Int32 where
-  schemaGen _ = pure SInt32
-  toBuilder = BB.word32LE . fromIntegral
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SInt32 -> pure $ \case
-      TInt32 i -> i
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Int32" s
-  decodeCurrent = fromIntegral <$> getWord32
-
-instance Serialise Int64 where
-  schemaGen _ = pure SInt64
-  toBuilder = BB.word64LE . fromIntegral
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SInt64 -> pure $ \case
-      TInt64 i -> i
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Int64" s
-  decodeCurrent = fromIntegral <$> getWord64
-
-instance Serialise Int where
-  schemaGen _ = pure SInteger
-  toBuilder = toBuilder . VarInt
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SInteger -> pure $ \case
-      TInteger i -> fromIntegral i
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Int" s
-  decodeCurrent = decodeVarIntFinite
-
-instance Serialise Float where
-  schemaGen _ = pure SFloat
-  toBuilder = BB.floatLE
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SFloat -> pure $ \case
-      TFloat x -> x
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Float" s
-  decodeCurrent = castWord32ToFloat <$> getWord32
-
-instance Serialise Double where
-  schemaGen _ = pure SDouble
-  toBuilder = BB.doubleLE
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SDouble -> pure $ \case
-      TDouble x -> x
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Double" s
-  decodeCurrent = castWord64ToDouble <$> getWord64
-
-instance Serialise T.Text where
-  schemaGen _ = pure SText
-  toBuilder = toBuilder . T.encodeUtf8
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SText -> pure $ \case
-      TText t -> t
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Text" s
-  decodeCurrent = do
-    len <- decodeVarInt
-    T.decodeUtf8With T.lenientDecode <$> State (B.splitAt len)
-
--- | Encoded in variable-length quantity.
-newtype VarInt a = VarInt { getVarInt :: a } deriving (Show, Read, Eq, Ord, Enum
-  , Bounded, Num, Real, Integral, Bits, Typeable)
-
-instance (Typeable a, Bits a, Integral a) => Serialise (VarInt a) where
-  schemaGen _ = pure SInteger
-  toBuilder = varInt . getVarInt
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SInteger -> pure $ \case
-      TInteger i -> fromIntegral i
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise (VarInt a)" s
-  decodeCurrent = VarInt <$> decodeVarInt
-
-instance Serialise Integer where
-  schemaGen _ = pure SInteger
-  toBuilder = toBuilder . VarInt
-  {-# INLINE toBuilder #-}
-  extractor = getVarInt <$> extractor
-  decodeCurrent = getVarInt <$> decodeCurrent
-
-instance Serialise Natural where
-  schemaGen _ = pure SInteger
-  toBuilder = toBuilder . toInteger
-  extractor = naturalFromInteger <$> extractor
-  decodeCurrent = naturalFromInteger <$> decodeCurrent
-
-instance Serialise Char where
-  schemaGen _ = pure SChar
-  toBuilder = toBuilder . fromEnum
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SChar -> pure $ \case
-      TChar c -> c
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise Char" s
-  decodeCurrent = toEnum <$> decodeVarInt
-
-instance Serialise a => Serialise (Maybe a) where
-  schemaGen = gschemaGenVariant
-  toBuilder = gtoBuilderVariant
-  extractor = gextractorVariant
-  decodeCurrent = gdecodeCurrentVariant
-
-instance Serialise B.ByteString where
-  schemaGen _ = pure SBytes
-  toBuilder bs = varInt (B.length bs) <> BB.byteString bs
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ mkPlan $ \case
-    SBytes -> pure $ \case
-      TBytes bs -> bs
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise ByteString" s
-  decodeCurrent = do
-    len <- decodeVarInt
-    State (B.splitAt len)
-
-instance Serialise BL.ByteString where
-  schemaGen _ = pure SBytes
-  toBuilder = toBuilder . BL.toStrict
-  {-# INLINE toBuilder #-}
-  extractor = BL.fromStrict <$> extractor
-  decodeCurrent = BL.fromStrict <$> decodeCurrent
-
--- | time-1.9.1
-nanosecondsToNominalDiffTime :: Int64 -> NominalDiffTime
-nanosecondsToNominalDiffTime = unsafeCoerce . MkFixed . (*1000) . fromIntegral
-
-instance Serialise UTCTime where
-  schemaGen _ = pure SUTCTime
-  toBuilder = toBuilder . utcTimeToPOSIXSeconds
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ Plan $ \case
-    SUTCTime -> pure $ \case
-      TUTCTime bs -> bs
-      t -> throw $ InvalidTerm t
-    s -> unexpectedSchema "Serialise UTCTime" s
-  decodeCurrent = posixSecondsToUTCTime <$> decodeCurrent
-
-instance Serialise NominalDiffTime where
-  schemaGen _ = pure SInt64
-  toBuilder x = case unsafeCoerce x of
-    MkFixed p -> toBuilder (fromIntegral (p `div` 1000) :: Int64)
-  {-# INLINE toBuilder #-}
-  extractor = nanosecondsToNominalDiffTime <$> extractor
-  decodeCurrent = nanosecondsToNominalDiffTime <$> decodeCurrent
-
-instance Serialise a => Serialise [a] where
-  schemaGen _ = SVector <$> getSchema (Proxy @ a)
-  toBuilder xs = varInt (length xs)
-      <> foldMap toBuilder xs
-  {-# INLINE toBuilder #-}
-  extractor = V.toList <$> extractListBy extractor
-  decodeCurrent = do
-    n <- decodeVarInt
-    replicateM n decodeCurrent
-
-instance Serialise a => Serialise (V.Vector a) where
-  schemaGen _ = SVector <$> getSchema (Proxy @ a)
-  toBuilder xs = varInt (V.length xs)
-    <> foldMap toBuilder xs
-  {-# INLINE toBuilder #-}
-  extractor = extractListBy extractor
-  decodeCurrent = do
-    n <- decodeVarInt
-    V.replicateM n decodeCurrent
-
-instance (SV.Storable a, Serialise a) => Serialise (SV.Vector a) where
-  schemaGen _ = SVector <$> getSchema (Proxy @ a)
-  toBuilder = toBuilder . (SV.convert :: SV.Vector a -> V.Vector a)
-  {-# INLINE toBuilder #-}
-  extractor = SV.convert <$> extractListBy extractor
-  decodeCurrent = do
-    n <- decodeVarInt
-    SV.replicateM n decodeCurrent
-
-instance (UV.Unbox a, Serialise a) => Serialise (UV.Vector a) where
-  schemaGen _ = SVector <$> getSchema (Proxy @ a)
-  toBuilder = toBuilder . (UV.convert :: UV.Vector a -> V.Vector a)
-  {-# INLINE toBuilder #-}
-  extractor = UV.convert <$> extractListBy extractor
-  decodeCurrent = do
-    n <- decodeVarInt
-    UV.replicateM n decodeCurrent
-
--- | Extract a list or an array of values.
-extractListBy :: Typeable a => Extractor a -> Extractor (V.Vector a)
-extractListBy (Extractor plan) = Extractor $ mkPlan $ \case
-  SVector s -> do
-    getItem <- unPlan plan s
-    return $ \case
-      TVector xs -> V.map getItem xs
-      t -> throw $ InvalidTerm t
-  s -> throwStrategy $ UnexpectedSchema "extractListBy ..." "[a]" s
-{-# INLINE extractListBy #-}
-
-instance (Ord k, Serialise k, Serialise v) => Serialise (M.Map k v) where
-  schemaGen _ = schemaGen (Proxy @ [(k, v)])
-  toBuilder m = toBuilder (M.size m)
-    <> M.foldMapWithKey (curry toBuilder) m
-  {-# INLINE toBuilder #-}
-  extractor = M.fromList <$> extractor
-  decodeCurrent = M.fromList <$> decodeCurrent
-
-instance (Eq k, Hashable k, Serialise k, Serialise v) => Serialise (HM.HashMap k v) where
-  schemaGen _ = schemaGen (Proxy @ [(k, v)])
-  toBuilder m = toBuilder (HM.size m)
-    <> HM.foldrWithKey (\k v r -> toBuilder (k, v) <> r) mempty m
-  {-# INLINE toBuilder #-}
-  extractor = HM.fromList <$> extractor
-  decodeCurrent = HM.fromList <$> decodeCurrent
-
-instance (Serialise v) => Serialise (IM.IntMap v) where
-  schemaGen _ = schemaGen (Proxy @ [(Int, v)])
-  toBuilder m = toBuilder (IM.size m)
-    <> IM.foldMapWithKey (curry toBuilder) m
-  {-# INLINE toBuilder #-}
-  extractor = IM.fromList <$> extractor
-  decodeCurrent = IM.fromList <$> decodeCurrent
-
-instance (Ord a, Serialise a) => Serialise (S.Set a) where
-  schemaGen _ = schemaGen (Proxy @ [a])
-  toBuilder s = toBuilder (S.size s) <> foldMap toBuilder s
-  {-# INLINE toBuilder #-}
-  extractor = S.fromList <$> extractor
-  decodeCurrent = S.fromList <$> decodeCurrent
-
-instance Serialise IS.IntSet where
-  schemaGen _ = schemaGen (Proxy @ [Int])
-  toBuilder s = toBuilder (IS.size s) <> IS.foldr (mappend . toBuilder) mempty s
-  {-# INLINE toBuilder #-}
-  extractor = IS.fromList <$> extractor
-  decodeCurrent = IS.fromList <$> decodeCurrent
-
-instance Serialise a => Serialise (Seq.Seq a) where
-  schemaGen _ = schemaGen (Proxy @ [a])
-  toBuilder s = toBuilder (length s) <> foldMap toBuilder s
-  {-# INLINE toBuilder #-}
-  extractor = Seq.fromList <$> extractor
-  decodeCurrent = Seq.fromList <$> decodeCurrent
-
-instance (Integral a, Serialise a) => Serialise (Ratio a) where
-  schemaGen _ = schemaGen (Proxy @ (a, a))
-  toBuilder x = toBuilder (numerator x, denominator x)
-  {-# INLINE toBuilder #-}
-  extractor = uncurry (%) <$> extractor
-  decodeCurrent = uncurry (%) <$> decodeCurrent
-
-instance Serialise Scientific where
-  schemaGen _ = schemaGen (Proxy @ (Integer, Int))
-  toBuilder s = toBuilder (coefficient s, base10Exponent s)
-  {-# INLINE toBuilder #-}
-  extractor = Extractor $ Plan $ \s -> case s of
-    SWord8 -> f (fromIntegral :: Word8 -> Scientific) s
-    SWord16 -> f (fromIntegral :: Word16 -> Scientific) s
-    SWord32 -> f (fromIntegral :: Word32 -> Scientific) s
-    SWord64 -> f (fromIntegral :: Word64 -> Scientific) s
-    SInt8 -> f (fromIntegral :: Int8 -> Scientific) s
-    SInt16 -> f (fromIntegral :: Int16 -> Scientific) s
-    SInt32 -> f (fromIntegral :: Int32 -> Scientific) s
-    SInt64 -> f (fromIntegral :: Int64 -> Scientific) s
-    SInteger -> f fromInteger s
-    SFloat -> f (realToFrac :: Float -> Scientific) s
-    SDouble -> f (realToFrac :: Double -> Scientific) s
-    _ -> f (uncurry scientific) s
-    where
-      f c = unwrapExtractor (c <$> extractor)
-  decodeCurrent = decodeCurrentDefault
-
-buildExtractor :: Typeable a => Subextractor a -> Extractor a
-buildExtractor (Subextractor e) = Extractor $ mkPlan $ unwrapExtractor e
-{-# INLINE buildExtractor #-}
-
-newtype Subextractor a = Subextractor { unSubextractor :: Extractor a }
-  deriving (Functor, Applicative, Alternative)
-
--- | Extract a field of a record.
-extractField :: Serialise a => T.Text -> Subextractor a
-extractField = extractFieldBy extractor
-{-# INLINE extractField #-}
-
--- | Extract a field using the supplied 'Extractor'.
-extractFieldBy :: Extractor a -> T.Text -> Subextractor a
-extractFieldBy (Extractor g) name = Subextractor $ Extractor $ Plan $ \case
-  SRecord schs -> case lookupWithIndexV name schs of
-    Just (i, sch) -> do
-      m <- unPlan g sch
-      return $ \case
-        TRecord xs -> maybe (error msg) (m . snd) $ xs V.!? i
-        t -> throw $ InvalidTerm t
-    _ -> throwStrategy $ FieldNotFound rep name (map fst $ V.toList schs)
-  s -> throwStrategy $ UnexpectedSchema rep "a record" s
-  where
-    rep = "extractFieldBy ... " <> dquotes (pretty name)
-    msg = "Data.Winery.extractFieldBy ... " <> show name <> ": impossible"
-
--- | Construct a plan, expanding fixpoints and let bindings.
-mkPlan :: forall a. Typeable a => (Schema -> Strategy' (Term -> a)) -> Plan (Term -> a)
-mkPlan k = Plan $ \sch -> Strategy $ \(StrategyEnv ofs decs) -> case sch of
-  SVar i
-    | point : _ <- drop i decs -> case point of
-      BoundSchema ofs' sch' -> unPlan (mkPlan k) sch' `unStrategy` StrategyEnv ofs' (drop (ofs - ofs') decs)
-      DynDecoder dyn -> case fromDynamic dyn of
-        Nothing -> Left $ TypeMismatch i
-          (typeRep (Proxy @ (Term -> a)))
-          (dynTypeRep dyn)
-        Just a -> Right a
-    | otherwise -> Left $ UnboundVariable i
-  SFix s -> mfix $ \a -> unPlan (mkPlan k) s `unStrategy` StrategyEnv (ofs + 1) (DynDecoder (toDyn a) : decs)
-  SLet s t -> unPlan (mkPlan k) t `unStrategy` StrategyEnv (ofs + 1) (BoundSchema ofs s : decs)
-  s -> k s `unStrategy` StrategyEnv ofs decs
-
-instance (Serialise a, Serialise b) => Serialise (a, b) where
-  schemaGen = gschemaGenProduct
-  toBuilder = gtoBuilderProduct
-  extractor = gextractorProduct
-  decodeCurrent = gdecodeCurrentProduct
-
-instance (Serialise a, Serialise b, Serialise c) => Serialise (a, b, c) where
-  schemaGen = gschemaGenProduct
-  toBuilder = gtoBuilderProduct
-  extractor = gextractorProduct
-  decodeCurrent = gdecodeCurrentProduct
-
-instance (Serialise a, Serialise b, Serialise c, Serialise d) => Serialise (a, b, c, d) where
-  schemaGen = gschemaGenProduct
-  toBuilder = gtoBuilderProduct
-  extractor = gextractorProduct
-  decodeCurrent = gdecodeCurrentProduct
-
-instance (Serialise a, Serialise b, Serialise c, Serialise d, Serialise e) => Serialise (a, b, c, d, e) where
-  schemaGen = gschemaGenProduct
-  toBuilder = gtoBuilderProduct
-  extractor = gextractorProduct
-  decodeCurrent = gdecodeCurrentProduct
-
-instance (Serialise a, Serialise b, Serialise c, Serialise d, Serialise e, Serialise f) => Serialise (a, b, c, d, e, f) where
-  schemaGen = gschemaGenProduct
-  toBuilder = gtoBuilderProduct
-  extractor = gextractorProduct
-  decodeCurrent = gdecodeCurrentProduct
-
-instance (Serialise a, Serialise b) => Serialise (Either a b) where
-  schemaGen = gschemaGenVariant
-  toBuilder = gtoBuilderVariant
-  extractor = gextractorVariant
-  decodeCurrent = gdecodeCurrentVariant
-
--- | Tries to extract a specific constructor of a variant. Useful for
--- implementing backward-compatible extractors.
-extractConstructorBy :: Typeable a => (Extractor a, T.Text, a -> r) -> Subextractor r -> Subextractor r
-extractConstructorBy (d, name, f) cont = Subextractor $ Extractor $ Plan $ \case
-  SVariant schs0 -> Strategy $ \decs -> do
-    let run :: Extractor x -> Schema -> Either WineryException (Term -> x)
-        run e s = unwrapExtractor e s `unStrategy` decs
-    case lookupWithIndexV name schs0 of
-      Just (i, s) -> do
-        (j, dec) <- fmap ((,) i) $ run d $ case s of
-          SProduct [s'] -> s'
-          s' -> s'
-        let rest = SVariant $ V.filter ((/=name) . fst) schs0
-        k <- run (unSubextractor cont) rest
-        return $ \case
-          TVariant tag _ v
-            | tag == j -> f $ dec v
-          t -> k t
-      _ -> run (unSubextractor cont) (SVariant schs0)
-  s -> throwStrategy $ UnexpectedSchema rep "a variant" s
-  where
-    rep = "extractConstructorBy ... " <> dquotes (pretty name)
-
--- | Tries to match on a constructor. If it doesn't match (or constructor
--- doesn't exist at all), leave it to the successor.
---
--- @extractor = ("Just", Just) `extractConstructor` ("Nothing", \() -> Nothing) `extractConstructor` extractVoid@
-extractConstructor :: (Serialise a) => (T.Text, a -> r) -> Subextractor r -> Subextractor r
-extractConstructor (name, f) = extractConstructorBy (extractor, name, f)
-{-# INLINE extractConstructor #-}
-
-extractVoid :: Typeable r => Subextractor r
-extractVoid = Subextractor $ Extractor $ mkPlan $ \case
-  SVariant schs0
-    | V.null schs0 -> return $ throw . InvalidTerm
-  s -> throwStrategy $ UnexpectedSchema "extractVoid" "no constructors" s
-
-infixr 1 `extractConstructorBy`
-infixr 1 `extractConstructor`
-
--- | Generic implementation of 'schemaGen' for a record.
-gschemaGenRecord :: forall proxy a. (GSerialiseRecord (Rep a), Generic a, Typeable a) => proxy a -> SchemaGen Schema
-gschemaGenRecord _ = SRecord . V.fromList <$> recordSchema (Proxy @ (Rep a))
-
--- | Generic implementation of 'toBuilder' for a record.
-gtoBuilderRecord :: (GEncodeProduct (Rep a), Generic a) => a -> BB.Builder
-gtoBuilderRecord = productEncoder . from
-{-# INLINE gtoBuilderRecord #-}
-
-data FieldDecoder i a = FieldDecoder !i !(Maybe a) !(Plan (Term -> a))
-
--- | Generic implementation of 'extractor' for a record.
-gextractorRecord :: forall a. (GSerialiseRecord (Rep a), Generic a, Typeable a)
-  => Maybe a -- ^ default value (optional)
-  -> Extractor a
-gextractorRecord def = Extractor $ mkPlan
-  $ fmap (fmap (to .)) $ extractorRecord'
-  ("gextractorRecord :: Extractor " <> viaShow (typeRep (Proxy @ a)))
-  (from <$> def)
-
--- | Generic implementation of 'extractor' for a record.
-extractorRecord' :: (GSerialiseRecord f)
-  => Doc AnsiStyle
-  -> Maybe (f x) -- ^ default value (optional)
-  -> Schema -> Strategy' (Term -> f x)
-extractorRecord' rep def (SRecord schs) = Strategy $ \decs -> do
-    let go :: FieldDecoder T.Text x -> Either WineryException (Term -> x)
-        go (FieldDecoder name def' p) = case lookupWithIndexV name schs of
-          Nothing -> case def' of
-            Just d -> Right (const d)
-            Nothing -> Left $ FieldNotFound rep name (map fst $ V.toList schs)
-          Just (i, sch) -> case p `unPlan` sch `unStrategy` decs of
-            Right getItem -> Right $ \case
-              TRecord xs -> maybe (error (show rep)) (getItem . snd) $ xs V.!? i
-              t -> throw $ InvalidTerm t
-            Left e -> Left e
-    unTransFusion (recordExtractor def) go
-extractorRecord' rep _ s = throwStrategy $ UnexpectedSchema rep "a record" s
-{-# INLINE gextractorRecord #-}
-
-gdecodeCurrentRecord :: (GSerialiseRecord (Rep a), Generic a) => Decoder a
-gdecodeCurrentRecord = to <$> recordDecoder
-{-# INLINE gdecodeCurrentRecord #-}
-
--- | The 'Serialise' instance is generically defined for records.
---
--- /"Remember thee! Yea, from the table of my memory I'll wipe away all trivial
--- fond records."/
-newtype WineryRecord a = WineryRecord { unWineryRecord :: a }
-
-instance (GEncodeProduct (Rep a), GSerialiseRecord (Rep a), Generic a, Typeable a) => Serialise (WineryRecord a) where
-  schemaGen _ = gschemaGenRecord (Proxy @ a)
-  toBuilder = gtoBuilderRecord . unWineryRecord
-  extractor = WineryRecord <$> gextractorRecord Nothing
-  decodeCurrent = WineryRecord <$> gdecodeCurrentRecord
-
-class GEncodeProduct f where
-  productEncoder :: f x -> BB.Builder
-
-instance GEncodeProduct U1 where
-  productEncoder _ = mempty
-  {-# INLINE productEncoder #-}
-
-instance (GEncodeProduct f, GEncodeProduct g) => GEncodeProduct (f :*: g) where
-  productEncoder (f :*: g) = productEncoder f <> productEncoder g
-  {-# INLINE productEncoder #-}
-
-instance Serialise a => GEncodeProduct (S1 c (K1 i a)) where
-  productEncoder (M1 (K1 a)) = toBuilder a
-  {-# INLINE productEncoder #-}
-
-instance GEncodeProduct f => GEncodeProduct (C1 c f) where
-  productEncoder (M1 a) = productEncoder a
-  {-# INLINE productEncoder #-}
-
-instance GEncodeProduct f => GEncodeProduct (D1 c f) where
-  productEncoder (M1 a) = productEncoder a
-  {-# INLINE productEncoder #-}
-
-class GSerialiseRecord f where
-  recordSchema :: proxy f -> SchemaGen [(T.Text, Schema)]
-  recordExtractor :: Maybe (f x) -> TransFusion (FieldDecoder T.Text) ((->) Term) (Term -> f x)
-  recordDecoder :: Decoder (f x)
-
-instance (GSerialiseRecord f, GSerialiseRecord g) => GSerialiseRecord (f :*: g) where
-  recordSchema _ = (++) <$> recordSchema (Proxy @ f) <*> recordSchema (Proxy @ g)
-  recordExtractor def = (\f g -> (:*:) <$> f <*> g)
-    <$> recordExtractor ((\(x :*: _) -> x) <$> def)
-    <*> recordExtractor ((\(_ :*: x) -> x) <$> def)
-  {-# INLINE recordExtractor #-}
-  recordDecoder = (:*:) <$> recordDecoder <*> recordDecoder
-  {-# INLINE recordDecoder #-}
-
-instance (Serialise a, Selector c) => GSerialiseRecord (S1 c (K1 i a)) where
-  recordSchema _ = do
-    s <- getSchema (Proxy @ a)
-    pure [(T.pack $ selName (M1 undefined :: M1 i c (K1 i a) x), s)]
-  recordExtractor def = TransFusion $ \k -> fmap (fmap (M1 . K1)) $ k $ FieldDecoder
-    (T.pack $ selName (M1 undefined :: M1 i c (K1 i a) x))
-    (unK1 . unM1 <$> def)
-    (getExtractor extractor)
-  {-# INLINE recordExtractor #-}
-  recordDecoder = M1 . K1 <$> decodeCurrent
-  {-# INLINE recordDecoder #-}
-
-instance (GSerialiseRecord f) => GSerialiseRecord (C1 c f) where
-  recordSchema _ = recordSchema (Proxy @ f)
-  recordExtractor def = fmap M1 <$> recordExtractor (unM1 <$> def)
-  recordDecoder = M1 <$> recordDecoder
-
-instance (GSerialiseRecord f) => GSerialiseRecord (D1 c f) where
-  recordSchema _ = recordSchema (Proxy @ f)
-  recordExtractor def = fmap M1 <$> recordExtractor (unM1 <$> def)
-  recordDecoder = M1 <$> recordDecoder
-
-class GSerialiseProduct f where
-  productSchema :: proxy f -> SchemaGen [Schema]
-  productExtractor :: Compose (State Int) (TransFusion (FieldDecoder Int) ((->) Term)) (Term -> f x)
-  productDecoder :: Decoder (f x)
-
-instance GSerialiseProduct U1 where
-  productSchema _ = pure []
-  productExtractor = pure (pure U1)
-  productDecoder = pure U1
-
-instance (Serialise a) => GSerialiseProduct (K1 i a) where
-  productSchema _ = pure <$> getSchema (Proxy @ a)
-  productExtractor = Compose $ State $ \i ->
-    ( TransFusion $ \k -> fmap (fmap K1) $ k $ FieldDecoder i Nothing (getExtractor extractor)
-    , i + 1)
-  productDecoder = K1 <$> decodeCurrent
-
-instance GSerialiseProduct f => GSerialiseProduct (M1 i c f) where
-  productSchema _ = productSchema (Proxy @ f)
-  productExtractor = fmap M1 <$> productExtractor
-  productDecoder = M1 <$> productDecoder
-
-instance (GSerialiseProduct f, GSerialiseProduct g) => GSerialiseProduct (f :*: g) where
-  productSchema _ = (++) <$> productSchema (Proxy @ f) <*> productSchema (Proxy @ g)
-  productExtractor = liftA2 (:*:) <$> productExtractor <*> productExtractor
-  productDecoder = (:*:) <$> productDecoder <*> productDecoder
-
--- | Serialise a value as a product (omits field names).
---
--- /"I get ideas about what's essential when packing my suitcase."/
-newtype WineryProduct a = WineryProduct { unWineryProduct :: a }
-
-instance (GEncodeProduct (Rep a), GSerialiseProduct (Rep a), Generic a, Typeable a) => Serialise (WineryProduct a) where
-  schemaGen _ = gschemaGenProduct (Proxy @ a)
-  toBuilder = gtoBuilderProduct . unWineryProduct
-  extractor = WineryProduct <$> gextractorProduct
-  decodeCurrent = WineryProduct <$> gdecodeCurrentProduct
-
-gschemaGenProduct :: forall proxy a. (Generic a, GSerialiseProduct (Rep a)) => proxy a -> SchemaGen Schema
-gschemaGenProduct _ = SProduct . V.fromList <$> productSchema (Proxy @ (Rep a))
-{-# INLINE gschemaGenProduct #-}
-
-gtoBuilderProduct :: (Generic a, GEncodeProduct (Rep a)) => a -> BB.Builder
-gtoBuilderProduct = productEncoder . from
-{-# INLINE gtoBuilderProduct #-}
-
--- | Generic implementation of 'extractor' for a record.
-gextractorProduct :: forall a. (GSerialiseProduct (Rep a), Generic a, Typeable a)
-  => Extractor a
-gextractorProduct = Extractor $ mkPlan $ fmap (to .) . extractorProduct'
-{-# INLINE gextractorProduct #-}
-
--- | Generic implementation of 'extractor' for a record.
-gdecodeCurrentProduct :: forall a. (GSerialiseProduct (Rep a), Generic a)
-  => Decoder a
-gdecodeCurrentProduct = to <$> productDecoder
-{-# INLINE gdecodeCurrentProduct #-}
-
-extractorProduct' :: GSerialiseProduct f => Schema -> Strategy' (Term -> f x)
-extractorProduct' sch
-  | Just schs <- strip sch = Strategy $ \recs -> do
-    let go :: FieldDecoder Int x -> Either WineryException (Term -> x)
-        go (FieldDecoder i _ p) = do
-          getItem <- if i < length schs
-            then unPlan p (schs V.! i) `unStrategy` recs
-            else Left $ ProductTooSmall $ length schs
-          return $ \case
-            TProduct xs -> getItem $ maybe (throw $ InvalidTerm (TProduct xs)) id
-              $ xs V.!? i
-            t -> throw $ InvalidTerm t
-    unTransFusion (getCompose productExtractor `evalState` 0) go
-  where
-    strip (SProduct xs) = Just xs
-    strip (SRecord xs) = Just $ V.map snd xs
-    strip _ = Nothing
-extractorProduct' sch = throwStrategy $ UnexpectedSchema "extractorProduct'" "a product" sch
-
--- | The 'Serialise' instance is generically defined for variants.
---
--- /"The one so like the other as could not be distinguish'd but by names."/
-newtype WineryVariant a = WineryVariant { unWineryVariant :: a }
-
-instance (GSerialiseVariant (Rep a), Generic a, Typeable a) => Serialise (WineryVariant a) where
-  schemaGen _ = gschemaGenVariant (Proxy @ a)
-  toBuilder = gtoBuilderVariant . unWineryVariant
-  extractor = WineryVariant <$> gextractorVariant
-  decodeCurrent = WineryVariant <$> gdecodeCurrentVariant
-
--- | Generic implementation of 'schemaGen' for an ADT.
-gschemaGenVariant :: forall proxy a. (GSerialiseVariant (Rep a), Typeable a, Generic a) => proxy a -> SchemaGen Schema
-gschemaGenVariant _ = SVariant . V.fromList <$> variantSchema (Proxy @ (Rep a))
-
--- | Generic implementation of 'toBuilder' for an ADT.
-gtoBuilderVariant :: (GSerialiseVariant (Rep a), Generic a) => a -> BB.Builder
-gtoBuilderVariant = variantEncoder 0 . from
-{-# INLINE gtoBuilderVariant #-}
-
--- | Generic implementation of 'extractor' for an ADT.
-gextractorVariant :: forall a. (GSerialiseVariant (Rep a), Generic a, Typeable a)
-  => Extractor a
-gextractorVariant = Extractor $ mkPlan $ \case
-  SVariant schs0 -> Strategy $ \decs -> do
-    ds' <- traverse (\(name, sch) -> case lookup name variantExtractor of
-      Nothing -> Left $ FieldNotFound rep name (map fst $ V.toList schs0)
-      Just f -> f sch `unStrategy` decs) schs0
-    return $ \case
-      TVariant i _ v -> to $ maybe (throw InvalidTag) ($ v) $ ds' V.!? i
-      t -> throw $ InvalidTerm t
-  s -> throwStrategy $ UnexpectedSchema rep "a variant" s
-  where
-    rep = "gextractorVariant :: Extractor "
-      <> viaShow (typeRep (Proxy @ a))
-
-gdecodeCurrentVariant :: (GSerialiseVariant (Rep a), Generic a) => Decoder a
-gdecodeCurrentVariant = decodeVarInt >>= maybe (throw InvalidTag) (fmap to) . (decs V.!?)
-  where
-    decs = V.fromList variantDecoder
-
-class GSerialiseVariant f where
-  variantCount :: proxy f -> Int
-  variantSchema :: proxy f -> SchemaGen [(T.Text, Schema)]
-  variantEncoder :: Int -> f x -> BB.Builder
-  variantExtractor :: [(T.Text, Schema -> Strategy' (Term -> f x))]
-  variantDecoder :: [Decoder (f x)]
-
-instance (GSerialiseVariant f, GSerialiseVariant g) => GSerialiseVariant (f :+: g) where
-  variantCount _ = variantCount (Proxy @ f) + variantCount (Proxy @ g)
-  variantSchema _ = (++) <$> variantSchema (Proxy @ f) <*> variantSchema (Proxy @ g)
-  variantEncoder i (L1 f) = variantEncoder i f
-  variantEncoder i (R1 g) = variantEncoder (i + variantCount (Proxy @ f)) g
-  variantExtractor = fmap (fmap (fmap (fmap (fmap L1)))) variantExtractor
-    ++ fmap (fmap (fmap (fmap (fmap R1)))) variantExtractor
-  variantDecoder = fmap (fmap L1) variantDecoder ++ fmap (fmap R1) variantDecoder
-
-instance (GSerialiseProduct f, GEncodeProduct f, KnownSymbol name) => GSerialiseVariant (C1 ('MetaCons name fixity 'False) f) where
-  variantCount _ = 1
-  variantSchema _ = do
-    s <- productSchema (Proxy @ f)
-    return [(T.pack $ symbolVal (Proxy @ name), SProduct $ V.fromList s)]
-  variantEncoder i (M1 a) = varInt i <> productEncoder a
-  variantExtractor = [(T.pack $ symbolVal (Proxy @ name), fmap (fmap M1) . extractorProduct') ]
-  variantDecoder = [M1 <$> productDecoder]
-
-instance (GSerialiseRecord f, GEncodeProduct f, KnownSymbol name) => GSerialiseVariant (C1 ('MetaCons name fixity 'True) f) where
-  variantCount _ = 1
-  variantSchema _ = do
-    s <- recordSchema (Proxy @ f)
-    return [(T.pack $ symbolVal (Proxy @ name), SRecord $ V.fromList s)]
-  variantEncoder i (M1 a) = varInt i <> productEncoder a
-  variantExtractor = [(T.pack $ symbolVal (Proxy @ name), fmap (fmap M1) . extractorRecord' "" Nothing) ]
-  variantDecoder = [M1 <$> recordDecoder]
-
-instance (GSerialiseVariant f) => GSerialiseVariant (S1 c f) where
-  variantCount _ = variantCount (Proxy @ f)
-  variantSchema _ = variantSchema (Proxy @ f)
-  variantEncoder i (M1 a) = variantEncoder i a
-  variantExtractor = fmap (fmap (fmap (fmap M1))) <$> variantExtractor
-  variantDecoder = fmap M1 <$> variantDecoder
-
-instance (GSerialiseVariant f) => GSerialiseVariant (D1 c f) where
-  variantCount _ = variantCount (Proxy @ f)
-  variantSchema _ = variantSchema (Proxy @ f)
-  variantEncoder i (M1 a) = variantEncoder i a
-  variantExtractor = fmap (fmap (fmap (fmap M1))) <$> variantExtractor
-  variantDecoder = fmap M1 <$> variantDecoder
-
-instance Serialise Ordering where
-  schemaGen = gschemaGenVariant
-  toBuilder = gtoBuilderVariant
-  extractor = gextractorVariant
-  decodeCurrent = gdecodeCurrentVariant
-
-deriving instance Serialise a => Serialise (Identity a)
-deriving instance (Serialise a, Typeable b, Typeable k) => Serialise (Const a (b :: k))
-
-deriving instance Serialise Any
-deriving instance Serialise All
-deriving instance Serialise a => Serialise (Down a)
-deriving instance Serialise a => Serialise (Product a)
-deriving instance Serialise a => Serialise (Sum a)
-deriving instance Serialise a => Serialise (Dual a)
-deriving instance Serialise a => Serialise (M.Last a)
-deriving instance Serialise a => Serialise (M.First a)
-deriving instance Serialise a => Serialise (S.Last a)
-deriving instance Serialise a => Serialise (S.First a)
-deriving instance Serialise a => Serialise (ZipList a)
-deriving instance Serialise a => Serialise (Option a)
-deriving instance Serialise a => Serialise (Max a)
-deriving instance Serialise a => Serialise (Min a)
-deriving instance (Typeable k, Typeable f, Typeable a, Serialise (f a)) => Serialise (Alt f (a :: k))
-deriving instance (Typeable j, Typeable k, Typeable f, Typeable g, Typeable a, Serialise (f (g a))) => Serialise (Compose f (g :: j -> k) (a :: j))
-#if MIN_VERSION_base(4,12,0)
-deriving instance (Typeable k, Typeable f, Typeable a, Serialise (f a)) => Serialise (Ap f (a :: k))
-#endif
-
-instance (Typeable k, Typeable a, Typeable b, a ~ b) => Serialise ((a :: k) :~: b) where
-  schemaGen _ = pure $ SProduct []
-  toBuilder = mempty
-  extractor = pure Refl
-  decodeCurrent = pure Refl
-
-instance (Serialise a, Serialise b) => Serialise (Arg a b) where
-  schemaGen = gschemaGenProduct
-  toBuilder = gtoBuilderProduct
-  extractor = gextractorProduct
-  decodeCurrent = gdecodeCurrentProduct
-
-instance Serialise a => Serialise (Complex a) where
-  schemaGen = gschemaGenProduct
-  toBuilder = gtoBuilderProduct
-  extractor = gextractorProduct
-  decodeCurrent = gdecodeCurrentProduct
-
-instance Serialise Void where
-  schemaGen _ = pure $ SVariant V.empty
-  toBuilder = mempty
-  extractor = Extractor $ Plan $ const $ throwStrategy "No extractor for Void"
-  decodeCurrent = error "No decodeCurrent for Void"
+module Data.Winery {-# DEPRECATED "Use Codec.Winery instead" #-}
+  ( module Codec.Winery )
+  where
+
+import Codec.Winery
diff --git a/src/Data/Winery/Base.hs b/src/Data/Winery/Base.hs
deleted file mode 100644
--- a/src/Data/Winery/Base.hs
+++ /dev/null
@@ -1,293 +0,0 @@
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE OverloadedLists #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE DeriveTraversable #-}
-----------------------------------------------------------------------------
--- |
--- Module      :  Data.Winery.Base
--- Copyright   :  (c) Fumiaki Kinoshita 2019
--- License     :  BSD3
--- Stability   :  Provisional
---
--- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
---
--- Basic types
---
------------------------------------------------------------------------------
-module Data.Winery.Base
-  ( Tag(..)
-  , Schema
-  , SchemaP(..)
-  , currentSchemaVersion
-  , bootstrapSchema
-  , Term(..)
-  , Extractor(..)
-  , Strategy'
-  , StrategyBind(..)
-  , StrategyEnv(..)
-  , Plan(..)
-  , unwrapExtractor
-  , WineryException(..)
-  , prettyWineryException)
-  where
-
-import Control.Applicative
-import Control.Exception
-import Data.Aeson as J
-import qualified Data.ByteString as B
-import Data.Dynamic
-import qualified Data.HashMap.Strict as HM
-import Data.Int
-import Data.String
-import qualified Data.Text as T
-import Data.Text.Prettyprint.Doc hiding ((<>), SText, SChar)
-import Data.Text.Prettyprint.Doc.Render.Terminal
-import Data.Time
-import Data.Typeable
-import qualified Data.Vector as V
-import Data.Winery.Internal
-import Data.Word
-import GHC.Generics (Generic)
-import GHC.Exts (IsList(..))
-
--- | Tag is an extra value that can be attached to a schema.
-data Tag = TagInt !Int
-  | TagStr !T.Text
-  | TagList ![Tag]
-  deriving (Show, Read, Eq, Generic)
-
-instance IsString Tag where
-  fromString = TagStr . fromString
-
-instance IsList Tag where
-  type Item Tag = Tag
-  fromList = TagList
-  toList (TagList xs) = xs
-  toList _ = []
-
-instance Pretty Tag where
-  pretty (TagInt i) = pretty i
-  pretty (TagStr s) = pretty s
-  pretty (TagList xs) = list (map pretty xs)
-
-currentSchemaVersion :: Word8
-currentSchemaVersion = 4
-
--- | A schema preserves structure of a datatype, allowing users to inspect
--- the data regardless of the current implementation.
---
--- /"Yeah, it’s just a memento. Just, you know, from the first time we met."/
-type Schema = SchemaP Int
-
-data SchemaP a = SFix !(SchemaP a) -- ^ binds a fixpoint
-  | SVar !a -- ^ @SVar n@ refers to the n-th innermost fixpoint
-  | SVector !(SchemaP a)
-  | SProduct !(V.Vector (SchemaP a))
-  | SRecord !(V.Vector (T.Text, SchemaP a))
-  | SVariant !(V.Vector (T.Text, SchemaP a))
-  | SBool
-  | SChar
-  | SWord8
-  | SWord16
-  | SWord32
-  | SWord64
-  | SInt8
-  | SInt16
-  | SInt32
-  | SInt64
-  | SInteger
-  | SFloat
-  | SDouble
-  | SBytes
-  | SText
-  | SUTCTime -- ^ nanoseconds from POSIX epoch
-  | STag !Tag !(SchemaP a)
-  | SLet !(SchemaP a) !(SchemaP a)
-  deriving (Show, Read, Eq, Generic, Functor, Foldable, Traversable)
-
-instance Pretty a => Pretty (SchemaP a) where
-  pretty = \case
-    SProduct [] -> "()"
-    SBool -> "Bool"
-    SChar -> "Char"
-    SWord8 -> "Word8"
-    SWord16 -> "Word16"
-    SWord32 -> "Word32"
-    SWord64 -> "Word64"
-    SInt8 -> "Int8"
-    SInt16 -> "Int16"
-    SInt32 -> "Int32"
-    SInt64 -> "Int64"
-    SInteger -> "Integer"
-    SFloat -> "Float"
-    SDouble -> "Double"
-    SBytes -> "ByteString"
-    SText -> "Text"
-    SUTCTime -> "UTCTime"
-    SVector s -> "[" <> pretty s <> "]"
-    SProduct ss -> tupled $ map pretty (V.toList ss)
-    SRecord ss -> align $ encloseSep "{ " " }" ", " [group $ nest 2 $ sep [pretty k, "::" <+> pretty v] | (k, v) <- V.toList ss]
-    SVariant ss -> align $ encloseSep "" "" (flatAlt "| " " | ")
-      [ nest 2 $ sep $ pretty k : case vs of
-        SProduct xs -> map pretty $ V.toList xs
-        SRecord xs -> [pretty (SRecord xs)]
-        s -> [pretty s] | (k, vs) <- V.toList ss]
-    SFix sch -> group $ nest 2 $ sep ["μ", enclose "{ " " }" $ pretty sch]
-    SVar i -> "$" <> pretty i
-    STag t s -> nest 2 $ sep [pretty t <> ":", pretty s]
-    SLet s t -> sep ["let" <+> pretty s, pretty t]
-
-bootstrapSchema :: Word8 -> Schema
-bootstrapSchema 4 = SFix (SVariant [("SFix",SProduct [SVar 0]),("SVar",SProduct [SInteger]),("SVector",SProduct [SVar 0]),("SProduct",SProduct [SVector (SVar 0)]),("SRecord",SProduct [SVector (SProduct [SText,SVar 0])]),("SVariant",SProduct [SVector (SProduct [SText,SVar 0])]),("SBool",SProduct []),("SChar",SProduct []),("SWord8",SProduct []),("SWord16",SProduct []),("SWord32",SProduct []),("SWord64",SProduct []),("SInt8",SProduct []),("SInt16",SProduct []),("SInt32",SProduct []),("SInt64",SProduct []),("SInteger",SProduct []),("SFloat",SProduct []),("SDouble",SProduct []),("SBytes",SProduct []),("SText",SProduct []),("SUTCTime",SProduct []),("STag",SProduct [SFix (SVariant [("TagInt",SProduct [SInteger]),("TagStr",SProduct [SText]),("TagList",SProduct [SVector (SVar 0)])]),SVar 0]),("SLet",SProduct [SVar 0,SVar 0])])
-bootstrapSchema n = error $ "Unsupported version: " <> show n
-
--- | Common representation for any winery data.
--- Handy for prettyprinting winery-serialised data.
-data Term = TBool !Bool
-  | TChar !Char
-  | TWord8 !Word8
-  | TWord16 !Word16
-  | TWord32 !Word32
-  | TWord64 !Word64
-  | TInt8 !Int8
-  | TInt16 !Int16
-  | TInt32 !Int32
-  | TInt64 !Int64
-  | TInteger !Integer
-  | TFloat !Float
-  | TDouble !Double
-  | TBytes !B.ByteString
-  | TText !T.Text
-  | TUTCTime !UTCTime
-  | TVector !(V.Vector Term)
-  | TProduct !(V.Vector Term)
-  | TRecord !(V.Vector (T.Text, Term))
-  | TVariant !Int !T.Text Term
-  deriving Show
-
-instance J.ToJSON Term where
-  toJSON (TBool b) = J.toJSON b
-  toJSON (TChar c) = J.toJSON c
-  toJSON (TWord8 w) = J.toJSON w
-  toJSON (TWord16 w) = J.toJSON w
-  toJSON (TWord32 w) = J.toJSON w
-  toJSON (TWord64 w) = J.toJSON w
-  toJSON (TInt8 w) = J.toJSON w
-  toJSON (TInt16 w) = J.toJSON w
-  toJSON (TInt32 w) = J.toJSON w
-  toJSON (TInt64 w) = J.toJSON w
-  toJSON (TInteger w) = J.toJSON w
-  toJSON (TFloat x) = J.toJSON x
-  toJSON (TDouble x) = J.toJSON x
-  toJSON (TBytes bs) = J.toJSON (B.unpack bs)
-  toJSON (TText t) = J.toJSON t
-  toJSON (TUTCTime t) = J.toJSON t
-  toJSON (TVector xs) = J.toJSON xs
-  toJSON (TProduct xs) = J.toJSON xs
-  toJSON (TRecord xs) = J.toJSON $ HM.fromList $ V.toList xs
-  toJSON (TVariant _ "Just" x) = J.toJSON x
-  toJSON (TVariant _ "Nothing" _) = J.Null
-  toJSON (TVariant _ t x) = J.object ["tag" J..= J.toJSON t, "contents" J..= J.toJSON x]
-
-instance Pretty Term where
-  pretty (TWord8 i) = pretty i
-  pretty (TWord16 i) = pretty i
-  pretty (TWord32 i) = pretty i
-  pretty (TWord64 i) = pretty i
-  pretty (TInt8 i) = pretty i
-  pretty (TInt16 i) = pretty i
-  pretty (TInt32 i) = pretty i
-  pretty (TInt64 i) = pretty i
-  pretty (TInteger i) = pretty i
-  pretty (TBytes s) = pretty $ show s
-  pretty (TText s) = pretty s
-  pretty (TVector xs) = list $ map pretty (V.toList xs)
-  pretty (TBool x) = pretty x
-  pretty (TChar x) = pretty x
-  pretty (TFloat x) = pretty x
-  pretty (TDouble x) = pretty x
-  pretty (TProduct xs) = tupled $ map pretty (V.toList xs)
-  pretty (TRecord xs) = align $ encloseSep "{ " " }" ", " [group $ nest 2 $ vsep [pretty k <+> "=", pretty v] | (k, v) <- V.toList xs]
-  pretty (TVariant _ tag (TProduct xs)) = group $ nest 2 $ sep $ pretty tag : map pretty (V.toList xs)
-  pretty (TVariant _ tag x) = group $ nest 2 $ sep [pretty tag, pretty x]
-  pretty (TUTCTime t) = pretty (show t)
-
--- | 'Extractor' is a 'Plan' that creates a function to extract a value from Term.
---
--- The 'Applicative' instance can be used to build a user-defined extractor.
--- This is also 'Alternative', meaning that fallback plans may be added.
---
--- /"Don't get set into one form, adapt it and build your own, and let it grow, be like water."/
-newtype Extractor a = Extractor { getExtractor :: Plan (Term -> a) }
-  deriving Functor
-
-instance Applicative Extractor where
-  pure = Extractor . pure . pure
-  Extractor f <*> Extractor x = Extractor $ (<*>) <$> f <*> x
-
-instance Alternative Extractor where
-  empty = Extractor empty
-  Extractor f <|> Extractor g = Extractor $ f <|> g
-
-data StrategyBind = DynDecoder !Dynamic -- ^ A fixpoint of a decoder
-    | BoundSchema !Int !Schema
-    -- ^ schema bound by 'SLet'. 'Int' is a basis of the variables
-
-data StrategyEnv = StrategyEnv !Int ![StrategyBind]
-
-type Strategy' = Strategy WineryException StrategyEnv
-
--- | Plan is a monad for computations which interpret 'Schema'.
-newtype Plan a = Plan { unPlan :: Schema -> Strategy' a }
-  deriving Functor
-
-instance Applicative Plan where
-  pure = Plan . const . pure
-  m <*> k = Plan $ \sch -> Strategy $ \decs -> case unStrategy (unPlan m sch) decs of
-    Right f -> f <$> unStrategy (unPlan k sch) decs
-    Left e -> Left e
-
-instance Monad Plan where
-  m >>= k = Plan $ \sch -> Strategy $ \decs -> case unStrategy (unPlan m sch) decs of
-    Right a -> unStrategy (unPlan (k a) sch) decs
-    Left e -> Left e
-
-instance Alternative Plan where
-  empty = Plan $ const empty
-  Plan a <|> Plan b = Plan $ \s -> a s <|> b s
-
-unwrapExtractor :: Extractor a -> Schema -> Strategy' (Term -> a)
-unwrapExtractor (Extractor m) = unPlan m
-{-# INLINE unwrapExtractor #-}
-
-data WineryException = UnexpectedSchema !(Doc AnsiStyle) !(Doc AnsiStyle) !Schema
-  | FieldNotFound !(Doc AnsiStyle) !T.Text ![T.Text]
-  | TypeMismatch !Int !TypeRep !TypeRep
-  | ProductTooSmall !Int
-  | UnboundVariable !Int
-  | EmptyInput
-  | WineryMessage !(Doc AnsiStyle)
-  deriving Show
-
-instance Exception WineryException
-
-instance IsString WineryException where
-  fromString = WineryMessage . fromString
-
-prettyWineryException :: WineryException -> Doc AnsiStyle
-prettyWineryException = \case
-  UnexpectedSchema subject expected actual -> annotate bold subject
-    <+> "expects" <+> annotate (color Green <> bold) expected
-    <+> "but got " <+> pretty actual
-  FieldNotFound rep x xs -> rep <> ": field or constructor " <> pretty x <> " not found in " <> pretty xs
-  TypeMismatch i s t -> "A type mismatch in variable"
-    <+> pretty i <> ":"
-    <+> "expected" <> viaShow s
-    <+> "but got " <> viaShow t
-  ProductTooSmall i -> "The product is too small; expecting " <> pretty i
-  UnboundVariable i -> "Unbound variable: " <> pretty i
-  EmptyInput -> "Unexpected empty string"
-  WineryMessage a -> a
diff --git a/src/Data/Winery/Internal.hs b/src/Data/Winery/Internal.hs
deleted file mode 100644
--- a/src/Data/Winery/Internal.hs
+++ /dev/null
@@ -1,262 +0,0 @@
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE ExistentialQuantification #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE Rank2Types #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeFamilies #-}
-----------------------------------------------------------------------------
--- |
--- Module      :  Data.Winery.Internal
--- Copyright   :  (c) Fumiaki Kinoshita 2019
--- License     :  BSD3
--- Stability   :  Experimental
---
--- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
---
--- Internal functions and datatypes
---
------------------------------------------------------------------------------
-module Data.Winery.Internal
-  ( unsignedVarInt
-  , varInt
-  , Decoder
-  , evalDecoder
-  , State(..)
-  , evalState
-  , decodeVarInt
-  , decodeVarIntFinite
-  , getWord8
-  , getWord16
-  , getWord32
-  , getWord64
-  , DecodeException(..)
-  , indexDefault
-  , unsafeIndexV
-  , lookupWithIndexV
-  , Strategy(..)
-  , throwStrategy
-  , TransFusion(..)
-  )where
-
-import Control.Applicative
-import Control.Exception
-import Control.Monad
-import Control.Monad.Fix
-import qualified Data.ByteString as B
-import qualified Data.ByteString.FastBuilder as BB
-import qualified Data.ByteString.Internal as B
-import qualified Data.ByteString.Builder.Prim.Internal as BPI
-import Data.Bits
-import Data.Monoid ((<>))
-import Data.String
-import qualified Data.Vector.Unboxed as U
-import qualified Data.Vector as V
-import Data.Word
-import Foreign.ForeignPtr
-import Foreign.Storable
-import Foreign.Ptr
-import System.Endian
-
-unsignedVarInt :: (Bits a, Integral a) => a -> BB.Builder
-unsignedVarInt n
-  | n < 0x80 = BB.word8 (fromIntegral n)
-  | otherwise = BB.word8 (fromIntegral n `setBit` 7) <> uvarInt (unsafeShiftR n 7)
-{-# INLINE unsignedVarInt #-}
-
-varInt :: (Bits a, Integral a) => a -> BB.Builder
-varInt n
-  | n < 0 = case negate n of
-    n'
-      | n' < 0x40 -> BB.word8 (fromIntegral n' `setBit` 6)
-      | otherwise -> BB.word8 (0xc0 .|. fromIntegral n') <> uvarInt (unsafeShiftR n' 6)
-  | n < 0x40 = BB.word8 (fromIntegral n)
-  | otherwise = BB.word8 (fromIntegral n `setBit` 7 `clearBit` 6) <> uvarInt (unsafeShiftR n 6)
-{-# RULES "varInt/Int" varInt = varIntFinite #-}
-{-# INLINEABLE[1] varInt #-}
-
-varIntFinite :: Int -> BB.Builder
-varIntFinite = BB.primBounded (BPI.boudedPrim 10 writeIntFinite)
-
-writeWord8 :: Word8 -> Ptr Word8 -> IO (Ptr Word8)
-writeWord8 w p = do
-  poke p w
-  return $! plusPtr p 1
-
-writeIntFinite :: Int -> Ptr Word8 -> IO (Ptr Word8)
-writeIntFinite !n
-  | n < 0 = case negate n of
-    n'
-      | n' < 0x40 -> writeWord8 (fromIntegral n' `setBit` 6)
-      | otherwise ->
-          writeWord8 (0xc0 .|. fromIntegral n') >=>
-            writeUnsignedFinite pure (unsafeShiftR n' 6)
-  | n < 0x40 = writeWord8 (fromIntegral n)
-  | otherwise = writeWord8 (fromIntegral n `setBit` 7 `clearBit` 6) >=>
-      writeUnsignedFinite pure (unsafeShiftR n 6)
-{-# INLINE writeIntFinite #-}
-
-writeUnsignedFinite :: (Ptr Word8 -> IO r) -> Int -> Ptr Word8 -> IO r
-writeUnsignedFinite k = go
-  where
-    go m
-      | m < 0x80 = writeWord8 (fromIntegral m) >=> k
-      | otherwise = writeWord8 (setBit (fromIntegral m) 7) >=> go (unsafeShiftR m 7)
-{-# INLINE writeUnsignedFinite #-}
-
-uvarInt :: (Bits a, Integral a) => a -> BB.Builder
-uvarInt = go where
-  go m
-    | m < 0x80 = BB.word8 (fromIntegral m)
-    | otherwise = BB.word8 (setBit (fromIntegral m) 7) <> go (unsafeShiftR m 7)
-{-# INLINE uvarInt #-}
-
--- | A state monad. The reason being not @State@ from transformers is to
--- allow coercion for newtype deriving and DerivingVia.
-newtype State s a = State { runState :: s -> (a, s) }
-  deriving Functor
-
-evalState :: State s a -> s -> a
-evalState m = fst . runState m
-{-# INLINE evalState #-}
-
-instance Applicative (State s) where
-  pure a = State $ \s -> (a, s)
-  m <*> k = State $ \s -> case runState m s of
-    (f, s') -> case runState k s' of
-      (a, s'') -> (f a, s'')
-
-instance Monad (State s) where
-  m >>= k = State $ \s -> case runState m s of
-    (a, s') -> runState (k a) s'
-
-instance MonadFix (State s) where
-  mfix f = State $ \s -> fix $ \ ~(a, _) -> runState (f a) s
-
-type Decoder = State B.ByteString
-
-evalDecoder :: Decoder a -> B.ByteString -> a
-evalDecoder = evalState
-{-# INLINE evalDecoder #-}
-
-getWord8 :: Decoder Word8
-getWord8 = State $ \bs -> case B.uncons bs of
-  Nothing -> throw InsufficientInput
-  Just (x, bs') -> (x, bs')
-{-# INLINE getWord8 #-}
-
-data DecodeException = InsufficientInput
-  | IntegerOverflow
-  | InvalidTag deriving (Eq, Show, Read)
-instance Exception DecodeException
-
-decodeVarIntBase :: (Num a, Bits a) => Decoder a -> Decoder a
-decodeVarIntBase body = getWord8 >>= \case
-  n | testBit n 7 -> do
-      m <- body
-      if testBit n 6
-        then return $! negate $ unsafeShiftL m 6 .|. fromIntegral n .&. 0x3f
-        else return $! unsafeShiftL m 6 .|. clearBit (fromIntegral n) 7
-    | testBit n 6 -> return $ negate $ fromIntegral $ clearBit n 6
-    | otherwise -> return $ fromIntegral n
-{-# INLINE decodeVarIntBase #-}
-
-decodeVarInt :: (Num a, Bits a) => Decoder a
-decodeVarInt = decodeVarIntBase $ getWord8 >>= go
-  where
-    go n
-      | testBit n 7 = do
-        m <- getWord8 >>= go
-        return $! unsafeShiftL m 7 .|. clearBit (fromIntegral n) 7
-      | otherwise = return $ fromIntegral n
-{-# INLINE decodeVarInt #-}
-
-decodeVarIntFinite :: forall a. (Num a, FiniteBits a) => Decoder a
-decodeVarIntFinite = decodeVarIntBase $ getWord8 >>= go 7
-  where
-    go w n
-      | testBit n 7 = do
-        m <- getWord8 >>= go (w + 7)
-        return $! unsafeShiftL m 7 .|. clearBit (fromIntegral n) 7
-      | w + 7 - countLeadingZeros n < finiteBitSize (0 :: a) = return $ fromIntegral n
-      | otherwise = throw IntegerOverflow
-{-# INLINABLE[1] decodeVarIntFinite #-}
-{-# SPECIALISE decodeVarIntFinite :: Decoder Int #-}
-
-getWord16 :: Decoder Word16
-getWord16 = State $ \(B.PS fp ofs len) -> if len >= 2
-  then (B.accursedUnutterablePerformIO $ withForeignPtr fp
-    $ \ptr -> fromLE16 <$> peekByteOff ptr ofs, B.PS fp (ofs + 2) (len - 2))
-  else throw InsufficientInput
-
-getWord32 :: Decoder Word32
-getWord32 = State $ \(B.PS fp ofs len) -> if len >= 4
-  then (B.accursedUnutterablePerformIO $ withForeignPtr fp
-    $ \ptr -> fromLE32 <$> peekByteOff ptr ofs, B.PS fp (ofs + 4) (len - 4))
-  else throw InsufficientInput
-
-getWord64 :: Decoder Word64
-getWord64 = State $ \(B.PS fp ofs len) -> if len >= 8
-  then (B.accursedUnutterablePerformIO $ withForeignPtr fp
-    $ \ptr -> fromLE64 <$> peekByteOff ptr ofs, B.PS fp (ofs + 8) (len - 8))
-  else throw InsufficientInput
-
-unsafeIndexV :: U.Unbox a => String -> U.Vector a -> Int -> a
-unsafeIndexV err xs i
-  | i >= U.length xs || i < 0 = error err
-  | otherwise = U.unsafeIndex xs i
-{-# INLINE unsafeIndexV #-}
-
-lookupWithIndexV :: Eq k => k -> V.Vector (k, v) -> Maybe (Int, v)
-lookupWithIndexV k v = (\i -> (i, snd $ V.unsafeIndex v i))
-  <$> V.findIndex ((k==) . fst) v
-{-# INLINE lookupWithIndexV #-}
-
-indexDefault :: a -> [a] -> Int -> a
-indexDefault err xs i = case drop i xs of
-  x : _ -> x
-  _ -> err
-
--- | A monad with @Reader [r]@ and @Either WineryException@ combined, used internally
--- to build an extractor.
--- @r@ is used to share environment such as extractors for fixpoints.
-newtype Strategy e r a = Strategy { unStrategy :: r -> Either e a }
-  deriving Functor
-
-instance Applicative (Strategy e r) where
-  pure = return
-  (<*>) = ap
-
-instance Monad (Strategy e r) where
-  return = Strategy . const . Right
-  m >>= k = Strategy $ \decs -> case unStrategy m decs of
-    Right a -> unStrategy (k a) decs
-    Left e -> Left e
-
-instance IsString e => Alternative (Strategy e r) where
-  empty = Strategy $ const $ Left "empty"
-  Strategy a <|> Strategy b = Strategy $ \decs -> case a decs of
-    Left _ -> b decs
-    Right x -> Right x
-
-instance MonadFix (Strategy e r) where
-  mfix f = Strategy $ \r -> mfix $ \a -> unStrategy (f a) r
-  {-# INLINE mfix #-}
-
-throwStrategy :: e -> Strategy e r a
-throwStrategy = Strategy . const . Left
-
--- | A Bazaar (chain of indexed store comonad)-like structure which instead
--- works for natural transformations.
-newtype TransFusion f g a = TransFusion { unTransFusion :: forall h. Applicative h => (forall x. f x -> h (g x)) -> h a }
-
-instance Functor (TransFusion f g) where
-  fmap f (TransFusion m) = TransFusion $ \k -> fmap f (m k)
-  {-# INLINE fmap #-}
-
-instance Applicative (TransFusion f g) where
-  pure a = TransFusion $ \_ -> pure a
-  TransFusion a <*> TransFusion b = TransFusion $ \k -> a k <*> b k
-  {-# INLINE (<*>) #-}
diff --git a/src/Data/Winery/Query.hs b/src/Data/Winery/Query.hs
deleted file mode 100644
--- a/src/Data/Winery/Query.hs
+++ /dev/null
@@ -1,77 +0,0 @@
-{-# LANGUAGE DeriveFunctor #-}
-----------------------------------------------------------------------------
--- |
--- Module      :  Data.Winery.Query
--- Copyright   :  (c) Fumiaki Kinoshita 2019
--- License     :  BSD3
--- Stability   :  Experimental
---
--- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
---
--- Building blocks for winery queries.
---
------------------------------------------------------------------------------
-module Data.Winery.Query (Query(..)
-  , invalid
-  , list
-  , range
-  , field
-  , con
-  , select) where
-
-import Prelude hiding ((.), id)
-import Control.Applicative
-import Control.Category
-import Data.Winery
-import Data.Winery.Internal
-import Data.Typeable
-import qualified Data.Text as T
-import qualified Data.Vector as V
-
--- | Query is a transformation between 'Extractor's.
--- Like jq, this returns a list of values.
-newtype Query a b = Query
-  { runQuery :: Extractor [a] -> Extractor [b] }
-  deriving Functor
-
-instance Category Query where
-  id = Query id
-  Query f . Query g = Query $ f . g
-
-instance Applicative (Query a) where
-  pure a = Query $ const $ pure [a]
-  Query f <*> Query g = Query $ \d -> (<*>) <$> f d <*> g d
-
-instance Alternative (Query a) where
-  empty = Query $ const $ pure []
-  Query f <|> Query g = Query $ \d -> (++) <$> f d <*> g d
-
--- | Throw an error.
-invalid :: WineryException -> Query a b
-invalid = Query . const . Extractor . Plan . const . throwStrategy
-
--- | Takes a list and traverses on it.
-list :: Typeable a => Query a a
-list = Query $ fmap concat . extractListBy
-
--- | Takes a list and enumerates elements in the specified range.
--- Like Python's array slicing, negative numbers counts from the last element.
-range :: Typeable a => Int -> Int -> Query a a
-range i j = Query $ fmap (\v -> foldMap id
-  $ V.backpermute v (V.enumFromTo (i `mod` V.length v) (j `mod` V.length v)))
-  . extractListBy
-
--- | Takes a record and extracts the specified field.
-field :: Typeable a => T.Text -> Query a a
-field name = Query $ \d -> buildExtractor $ extractFieldBy d name
-
--- | Takes a variant and returns a value when the constructor matches.
-con :: Typeable a => T.Text -> Query a a
-con name = Query $ \d -> buildExtractor $ extractConstructorBy (d, name, id) (pure [])
-
--- | Propagate values if the supplied 'Query' doesn't return False.
-select :: Query a Bool -> Query a a
-select qp = Query $ \d -> Extractor $ Plan $ \sch -> do
-  p <- unwrapExtractor (runQuery qp d) sch
-  dec <- unwrapExtractor d sch
-  return $ \bs -> [x | and $ p bs, x <- dec bs]
diff --git a/src/Data/Winery/Query/Parser.hs b/src/Data/Winery/Query/Parser.hs
deleted file mode 100644
--- a/src/Data/Winery/Query/Parser.hs
+++ /dev/null
@@ -1,61 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE Rank2Types #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeOperators #-}
-{-# LANGUAGE GADTs #-}
-----------------------------------------------------------------------------
--- |
--- Module      :  Data.Winery.Query.Parser
--- Copyright   :  (c) Fumiaki Kinoshita 2019
--- License     :  BSD3
--- Stability   :  Experimental
---
--- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
---
--- The language for winery queries
---
--- See the Pretty-printing section of README.md for examples.
---
------------------------------------------------------------------------------
-module Data.Winery.Query.Parser (parseQuery) where
-
-import Prelude hiding ((.), id)
-import Control.Category
-import Data.Winery.Query
-import Text.Megaparsec
-import Text.Megaparsec.Char
-import qualified Text.Megaparsec.Char.Lexer as L
-import qualified Data.Text as T
-import Data.Text.Prettyprint.Doc (Doc, hsep)
-import Data.Typeable
-import Data.Void
-
-type Parser = Parsec Void T.Text
-
-symbol :: T.Text -> Parser T.Text
-symbol = L.symbol space
-
-name :: Parser T.Text
-name = fmap T.pack (some (alphaNumChar <|> oneOf ("_\'" :: [Char])) <?> "field name")
-
-parseQuery :: Typeable a => Parser (Query (Doc a) (Doc a))
-parseQuery = foldr (.) id <$> sepBy1 parseTerms (symbol "|")
-
--- | Space-separated list of terms translate to a tabular output, applying the
--- queries in parallel
-parseTerms :: Typeable a => Parser (Query (Doc a) (Doc a))
-parseTerms = fmap hsep . sequenceA <$> sepBy1 parseTerm space
-
-parseTerm :: Typeable a => Parser (Query (Doc a) (Doc a))
-parseTerm = L.lexeme space $ choice
-  [ char '.' >> choice
-    [ do
-      _ <- char '['
-      i <- optional L.decimal
-      j <- optional (symbol ":" >> L.decimal)
-      _ <- char ']'
-      return $ range (maybe 0 id i) (maybe (-1) id j)
-    , field <$> name
-    , return id
-    ]
-  ]
diff --git a/src/Data/Winery/Test.hs b/src/Data/Winery/Test.hs
--- a/src/Data/Winery/Test.hs
+++ b/src/Data/Winery/Test.hs
@@ -1,199 +1,5 @@
-{-# LANGUAGE Rank2Types, ScopedTypeVariables #-}
-{-# LANGUAGE TypeOperators #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE DefaultSignatures #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE StandaloneDeriving #-}
-{-# LANGUAGE TypeApplications #-}
-{-# LANGUAGE AllowAmbiguousTypes #-}
-----------------------------------------------------------------------------
--- |
--- Module      :  Data.Winery.Test
--- Copyright   :  (c) Fumiaki Kinoshita 2019
--- License     :  BSD3
--- Stability   :  Experimental
---
--- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
---
--- A test framework that allows you to test all related Serialise instances
--- with automatically-generated test cases
---
------------------------------------------------------------------------------
-module Data.Winery.Test
-  ( -- * Generating tests
-  TestGen(..)
-  , printTests
-  -- * Test cases
-  , Tested(..)
-  , testCase
-  -- * Running tests
-  , allTests
-  , mergeTests
-  ) where
-
-import Test.HUnit
-import qualified Data.Map as M
-import qualified Data.HashMap.Strict as HM
-import qualified Data.ByteString as B
-import Data.Functor.Identity
-import Data.Hashable
-import Data.Proxy
-import qualified Data.Sequence as S
-import Data.Typeable
-import Data.Winery
-import qualified Data.Vector as V
-import qualified Data.Vector.Unboxed as UV
-import GHC.Generics
-import Text.Show
-
--- | Construct a test case.
-testCase :: (Show a, Eq a, Serialise a)
-  => Schema -- ^ the schema
-  -> B.ByteString -- ^ serialised
-  -> a -- ^ expected
-  -> Test
-testCase sch bs expected = case getDecoder sch of
-  Left err -> TestCase $ assertFailure (show err)
-  Right f -> expected ~=? evalDecoder f bs
-
--- | Merge multiple tests into one.
-mergeTests :: M.Map TypeRep [Test] -> Test
-mergeTests = TestList . concatMap (\(k, v) -> map (show k ~:) v) . M.toList
-
--- | Gather all test cases involved in the specified type.
-allTests :: forall a. (TestGen a, Tested a) => M.Map TypeRep [Test]
-allTests = M.insertWith (++) (typeRep (Proxy @ a)) (testCases @ a) (inheritedTests (Proxy @ a))
-
--- | Types with concrete test cases.
---
--- /"Doubt is useful, it keeps faith a living thing. After all, you cannot know
--- the strength of your faith until it has been tested."/
-class TestGen a => Tested a where
-  -- | List of test cases for the type.
-  testCases :: [Test]
-
--- these are already covered by the QuickCheck tests from winery
-instance Tested Bool where testCases = []
-instance Tested Int where testCases = []
-instance Tested Double where testCases = []
-instance Tested () where testCases = []
-instance Tested Char where testCases = []
-instance Tested a => Tested (Identity a) where
-  testCases = testCases @ a
-instance Tested a => Tested (S.Seq a) where testCases = []
-instance Tested a => Tested [a] where testCases = []
-instance (Tested a, Tested b) => Tested (Either a b) where testCases = []
-instance (Tested a, Tested b) => Tested (a, b) where testCases = []
-instance Tested a => Tested (V.Vector a) where testCases = []
-instance (UV.Unbox a, Tested a) => Tested (UV.Vector a) where testCases = []
-instance (Hashable k, Tested k, Tested a) => Tested (HM.HashMap k a) where testCases = []
-
--- | Generate test cases and print them to the standard output.
-printTests :: forall a. (TestGen a, Serialise a, Show a) => IO ()
-printTests = putStrLn $ showTests (genTestCases :: [a])
-
-showTests :: (Serialise a, Show a) => [a] -> String
-showTests xs = showListWith ppTest xs ""
-
-ppTest :: (Serialise a, Show a) => a -> ShowS
-ppTest a = showString "testCase "
-  . showsPrec 11 (schema [a])
-  . showChar ' '
-  . showsPrec 11 (serialiseOnly a)
-  . showChar ' '
-  . showsPrec 11 a
-
--- | A class to provide test values and gather tests for its components.
--- It is recommended to use the generic default methods.
-class Typeable a => TestGen a where
-  -- | A list of values that can be used as test cases.
-  -- It should contain at least one value as long as there is a non-bottom value
-  -- in the type.
-  genTestCases :: [a]
-
-  -- | Inherited set of test cases for each type it involves.
-  inheritedTests :: Proxy a -> M.Map TypeRep [Test]
-
-  default genTestCases :: (Generic a, GTestGen (Rep a)) => [a]
-  genTestCases = fmap to ggenTestCases
-
-  default inheritedTests :: (GTestGen (Rep a)) => Proxy a -> M.Map TypeRep [Test]
-  inheritedTests _ = ginheritedTests (Proxy @ (Rep a))
-
-class GTestGen f where
-  ggenTestCases :: [f x]
-  ginheritedTests :: proxy f -> M.Map TypeRep [Test]
-
-instance GTestGen V1 where
-  ggenTestCases = mempty
-  ginheritedTests _ = mempty
-
-instance GTestGen U1 where
-  ggenTestCases = [U1]
-  ginheritedTests _ = mempty
-
-instance GTestGen f => GTestGen (Rec1 f) where
-  ggenTestCases = fmap Rec1 ggenTestCases
-  ginheritedTests _ = ginheritedTests (Proxy @ f)
-
-instance (Tested c, TestGen c) => GTestGen (K1 i c) where
-  ggenTestCases = fmap K1 genTestCases
-  ginheritedTests _ = allTests @ c
-
-instance GTestGen f => GTestGen (M1 i c f) where
-  ggenTestCases = fmap M1 ggenTestCases
-  ginheritedTests _ = ginheritedTests (Proxy @ f)
-
-instance (GTestGen f, GTestGen g) => GTestGen (f :+: g) where
-  ggenTestCases = fmap L1 ggenTestCases ++ fmap R1 ggenTestCases
-  ginheritedTests _ = ginheritedTests (Proxy @ f)
-    `mappend` ginheritedTests (Proxy @ g)
-
-instance (GTestGen f, GTestGen g) => GTestGen (f :*: g) where
-  ggenTestCases = ((:*:) <$> ggenTestCases <*> xs)
-    ++ ((:*:) <$> take 1 ggenTestCases <*> ys)
-    where
-      (xs, ys) = splitAt 1 ggenTestCases
-  ginheritedTests _ = ginheritedTests (Proxy @ f)
-    `mappend` ginheritedTests (Proxy @ g)
-
-deriving instance TestGen a => TestGen (Identity a)
-instance TestGen ()
-instance TestGen Bool
-instance (Tested a, Tested b) => TestGen (a, b)
-instance (Tested a, Tested b, Tested c) => TestGen (a, b, c)
-instance (Tested a, Tested b, Tested c, Tested d) => TestGen (a, b, c, d)
-instance (Tested a, Tested b) => TestGen (Either a b)
-
-instance Tested a => TestGen [a] where
-  genTestCases = [[]]
-  inheritedTests _ = allTests @ a
-
-instance Tested a => TestGen (S.Seq a) where
-  genTestCases = [mempty]
-  inheritedTests _ = allTests @ a
-
-instance Tested a => TestGen (V.Vector a) where
-  genTestCases = [V.empty]
-  inheritedTests _ = allTests @ a
-
-instance (UV.Unbox a, Tested a) => TestGen (UV.Vector a) where
-  genTestCases = [UV.empty]
-  inheritedTests _ = allTests @ a
-
-instance (Hashable k, Tested k, Tested a) => TestGen (HM.HashMap k a) where
-  genTestCases = HM.singleton <$> genTestCases <*> genTestCases
-  inheritedTests _ = allTests @ k `mappend` allTests @ a
-
-instance TestGen Int where
-  genTestCases = [42]
-  inheritedTests = mempty
-
-instance TestGen Double where
-  genTestCases = [pi]
-  inheritedTests = mempty
+module Data.Winery.Test {-# DEPRECATED "Use Codec.Winery instead" #-}
+  ( module Codec.Winery.Test )
+  where
 
-instance TestGen Char where
-  genTestCases = ['X']
-  inheritedTests = mempty
+import Codec.Winery.Test
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -14,8 +14,8 @@
 import Data.Set (Set)
 import Data.Text (Text)
 import Data.Time (UTCTime, NominalDiffTime)
-import Data.Winery
-import Data.Winery.Internal
+import Codec.Winery
+import Codec.Winery.Internal
 import Data.Word
 import qualified Data.ByteString.FastBuilder as B
 import qualified Data.ByteString.Lazy as BL
diff --git a/winery.cabal b/winery.cabal
--- a/winery.cabal
+++ b/winery.cabal
@@ -1,9 +1,12 @@
 cabal-version: 1.12
 
 name:           winery
-version:        1.0.1
-synopsis:       Sustainable serialisation library
-description:    Please see the README on GitHub at <https://github.com/fumieval/winery#readme>
+version:        1.1
+synopsis:       A compact, well-typed seralisation format for Haskell values
+description:
+  <<https://i.imgur.com/lTosHnE.png>>
+  .
+  Please see the README on GitHub at <https://github.com/fumieval/winery#readme>
 category:       Data, Codec, Parsing, Serialization
 homepage:       https://github.com/fumieval/winery#readme
 bug-reports:    https://github.com/fumieval/winery/issues
@@ -15,8 +18,11 @@
 tested-with:    GHC == 8.4.4, GHC == 8.6.3
 build-type:     Simple
 extra-source-files:
-    README.md
-    ChangeLog.md
+  README.md
+  ChangeLog.md
+  .travis.yml
+  art/logo.png
+  art/logo.svg
 
 source-repository head
   type: git
@@ -24,11 +30,13 @@
 
 library
   exposed-modules:
+      Codec.Winery
+      Codec.Winery.Base
+      Codec.Winery.Internal
+      Codec.Winery.Query
+      Codec.Winery.Query.Parser
+      Codec.Winery.Test
       Data.Winery
-      Data.Winery.Base
-      Data.Winery.Internal
-      Data.Winery.Query
-      Data.Winery.Query.Parser
       Data.Winery.Test
   other-modules:
       Paths_winery
