diff --git a/.github/workflows/packcheck.yml b/.github/workflows/packcheck.yml index 922ac74..e338309 100644 --- a/.github/workflows/packcheck.yml +++ b/.github/workflows/packcheck.yml @@ -1,4 +1,4 @@ -# packcheck-0.5.1 +# packcheck-0.7.0 # You can use any of the options supported by packcheck as environment # variables here. See https://github.com/composewell/packcheck for all # options and their explanation. @@ -23,219 +23,148 @@ on: jobs: build: name: ${{ matrix.name }} - env: # ------------------------------------------------------------------------ # Common options # ------------------------------------------------------------------------ # GHC_OPTIONS: "-Werror" + GHCUP_VERSION: 0.1.20.0 + DOCSPEC_URL: https://github.com/phadej/cabal-extras/releases/download/cabal-docspec-0.0.0.20210111/cabal-docspec-0.0.0.20210111.xz + DOCSPEC_OPTIONS: "--timeout 60" CABAL_REINIT_CONFIG: y LC_ALL: C.UTF-8 - # ------------------------------------------------------------------------ - # What to build - # ------------------------------------------------------------------------ - # DISABLE_TEST: "y" - # DISABLE_BENCH: "y" - # DISABLE_DOCS: "y" - # DISABLE_SDIST_BUILD: "y" - # DISABLE_SDIST_GIT_CHECK: "y" - # DISABLE_DIST_CHECKS: "y" - - # ------------------------------------------------------------------------ - # stack options - # ------------------------------------------------------------------------ - # Note requiring a specific version of stack using STACKVER may fail due to - # github API limit while checking and upgrading/downgrading to the specific - # version. - #STACKVER: "1.6.5" - #STACK_UPGRADE: "y" - #RESOLVER: ${{ matrix.resolver }} + STACK_UPGRADE: "y" - # ------------------------------------------------------------------------ - # cabal options - # ------------------------------------------------------------------------ CABAL_CHECK_RELAX: y - CABAL_HACKAGE_MIRROR: "hackage.haskell.org:http://hackage.fpcomplete.com" - # CABAL_PROJECT: "cabal.project.user" - DISABLE_SDIST_BUILD: "n" - - # ------------------------------------------------------------------------ - # Where to find the required tools - # ------------------------------------------------------------------------ - PATH: /opt/ghc/bin:/sbin:/usr/sbin:/bin:/usr/bin - #TOOLS_DIR: /opt + CABAL_HACKAGE_MIRROR: hackage.haskell.org:http://hackage.fpcomplete.com - # ------------------------------------------------------------------------ - # Location of packcheck.sh (the shell script invoked to perform CI tests ). - # ------------------------------------------------------------------------ - # You can either commit the packcheck.sh script at this path in your repo or - # you can use it by specifying the PACKCHECK_REPO_URL option below in which - # case it will be automatically copied from the packcheck repo to this path - # during CI tests. In any case it is finally invoked from this path. PACKCHECK: "./packcheck.sh" - # If you have not committed packcheck.sh in your repo at PACKCHECK - # then it is automatically pulled from this URL. PACKCHECK_GITHUB_URL: "https://raw.githubusercontent.com/composewell/packcheck" - PACKCHECK_GITHUB_COMMIT: "ccc55fd4b895e842ca6e2d8ac63aa4acc1c3209a" + PACKCHECK_GITHUB_COMMIT: "7c4e1ab7a59b5ed6e92cfd0da67460a6116be4ac" - # ------------------------------------------------------------------------ - # Final build variables - # ------------------------------------------------------------------------ - PACKCHECK_COMMAND: ${{ matrix.command }} ${{ matrix.pack_options }} + BUILD: ${{ matrix.build }} + GHCVER: ${{ matrix.ghc_version }} + #RESOLVER: ${{ matrix.resolver }} + CABAL_BUILD_OPTIONS: ${{ matrix.cabal_build_options }} + CABAL_PROJECT: ${{ matrix.cabal_project }} + DISABLE_DOCS: ${{ matrix.disable_docs }} + #DISABLE_SDIST_BUILD: ${{ matrix.disable_sdist_build }} + #DISABLE_SDIST_BUILD: "y" + HLINT_VERSION: 3.6.1 + HLINT_OPTIONS: ${{ matrix.hlint_options }} + HLINT_TARGETS: ${{ matrix.hlint_targets }} runs-on: ${{ matrix.runner }} - continue-on-error: ${{ matrix.ignore_error }} strategy: fail-fast: false matrix: - include: - - - name: 9.10.1+streamly-core-master + - name: 9.10.1-Werror ghc_version: 9.10.1 - command: cabal-v2 + build: cabal runner: ubuntu-latest - cabal-version: 3.8.1.0 - ignore_error: false - pack_options: >- - CABAL_PROJECT=cabal.project.Werror + cabal-version: 3.10.2.0 + cabal_project: cabal.project.Werror - - name: 9.8.1+streamly-core-0.2.2+text-2.1.1 + - name: 9.8.1-Werror ghc_version: 9.8.1 - command: cabal-v2 + build: cabal runner: ubuntu-latest - cabal-version: 3.8.1.0 - pack_options: >- - CABAL_BUILD_OPTIONS=" - --constraint='streamly-core==0.2.2' - --constraint='text==2.1.1' - " - ignore_error: false - - - name: 9.6.2+streamly-core-0.2.2+text-2.1 - ghc_version: 9.6.2 - command: cabal-v2 + cabal-version: 3.10.2.0 + cabal_project: cabal.project.Werror + + - name: hlint + build: hlint + hlint_options: "lint" + hlint_targets: "src" runner: ubuntu-latest - cabal-version: 3.8.1.0 - ignore_error: true - pack_options: >- - CABAL_BUILD_OPTIONS=" - --constraint='streamly-core==0.2.2' - --constraint='text==2.1' - " - - - name: 9.4.4+streamly-core-0.2.1+text-2.0.2 - ghc_version: 9.4.4 - command: cabal-v2 + cabal-version: 3.2 + cabal_project: cabal.project.Werror + + - name: 9.6.3-macos + runner: macos-latest + ghc_version: 9.6.3 + build: cabal + cabal-version: 3.10.1.0 + cabal_project: cabal.project.Werror + + - name: 9.4.4 runner: ubuntu-latest + ghc_version: 9.4.4 + build: cabal cabal-version: 3.8.1.0 - ignore_error: false - pack_options: >- - CABAL_BUILD_OPTIONS=" - --constraint='streamly-core==0.2.1' - --constraint='text==2.0.2' - " - - - name: 9.2.7+streamly-core-0.2.1+text-2.0.1 - ghc_version: 9.2.7 - command: cabal-v2 + cabal_project: cabal.project.Werror + + - name: 9.4.4 runner: ubuntu-latest - cabal-version: 3.6.2.0 - ignore_error: false - pack_options: >- - CABAL_BUILD_OPTIONS=" - --constraint='streamly-core==0.2.1' - --constraint='text==2.0.1' - " - - - name: 9.0.1+streamly-core-0.2.0+text-2.0 - ghc_version: 9.0.1 - command: cabal-v2 + ghc_version: 9.4.4 + build: cabal + cabal-version: 3.8.1.0 + cabal_project: cabal.project.Werror + + - name: 9.2.7 runner: ubuntu-latest - cabal-version: 3.2 - ignore_error: false - pack_options: >- - CABAL_BUILD_OPTIONS=" - --constraint='streamly-core==0.2.0' - --constraint='text==2.0' - " + ghc_version: 9.2.7 + build: cabal + cabal-version: 3.6 + cabal_project: cabal.project.Werror - name: 8.10.7 - ghc_version: 8.10.7 - command: cabal-v2 runner: ubuntu-latest - cabal-version: 3.2 - ignore_error: false - - - name: 8.10.7+macOS ghc_version: 8.10.7 - command: cabal-v2 - runner: macos-latest - cabal_version: 3.4 - ignore_error: false + build: cabal + cabal-version: 3.2 + cabal_project: cabal.project.Werror + disable_docs: y - name: 8.8.4 - ghc_version: 8.8.4 - command: cabal-v2 runner: ubuntu-latest + ghc_version: 8.8.4 + build: cabal cabal-version: 3.2 - ignore_error: false + disable_docs: y - name: 8.6.5 - ghc_version: 8.6.5 - command: cabal-v2 runner: ubuntu-latest + ghc_version: 8.6.5 + build: cabal cabal-version: 3.2 - ignore_error: false - - - name: hlint - ghc_version: 8.8.4 - command: cabal-v2 - runner: ubuntu-latest - pack_options: >- - HLINT_OPTIONS="lint" - HLINT_TARGETS="src" - cabal-version: 3.2 - ignore_error: false + disable_docs: y steps: - uses: actions/checkout@v2 - - uses: haskell/actions/setup@v1 - with: - ghc-version: ${{ matrix.ghc_version }} - - - uses: actions/cache@v2 - name: Cache common directories + - uses: actions/cache@v4 + name: Restore cache with: path: | - ~/.cabal - ~/.ghc ~/.local + ~/.cabal ~/.stack - key: ${{ matrix.ghc_version }}-${{ matrix.runner }} - - - name: Run installer - if: ${{ matrix.installer != '' }} - run: ${{ matrix.installer }} - - - name: Setup stack - if: ${{ matrix.command == 'stack' }} - run: | - # required for packcheck - sudo apt-get install -y curl - # required for outbound https for stack and for stack setup - sudo apt-get install -y netbase xz-utils make + .stack-work + key: ${{ runner.os }}-${{ matrix.name }} - name: Download packcheck run: | - # Get packcheck if needed - CURL=$(which curl) - PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh - if test ! -e "$PACKCHECK"; then $CURL -sL -o "$PACKCHECK" $PACKCHECK_URL; fi; - chmod +x $PACKCHECK + # If a custom stack-yaml is specified, replace the default with that + #if test -e "$STACK_YAML"; then rm -f stack.yaml && ln -sv $STACK_YAML stack.yaml; else true; fi + #unset STACK_YAML + + if test ! -e "$PACKCHECK" + then + if test -z "$PACKCHECK_GITHUB_COMMIT" + then + die "PACKCHECK_GITHUB_COMMIT is not specified." + fi + PACKCHECK_URL=${PACKCHECK_GITHUB_URL}/${PACKCHECK_GITHUB_COMMIT}/packcheck.sh + curl --fail -sL -o "$PACKCHECK" $PACKCHECK_URL || exit 1 + chmod +x $PACKCHECK + elif test ! -x "$PACKCHECK" + then + chmod +x $PACKCHECK + fi - name: Run packcheck run: | - bash -c "$PACKCHECK $PACKCHECK_COMMAND" + bash -c "$PACKCHECK $BUILD" diff --git a/README.md b/README.md index fcca492..f4e8985 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,8 @@ Library for streamly and text interoperation. This library is to enable interoperation of streamly with existing code that uses `Text`. -The package provides APIs to interconvert between strict `Text` and -streamly `Array Word16` and between lazy `Text` and stream of `Array -Word16`. +The package provides APIs to interconvert between strict `Text` and streamly +`Array Word8` and between lazy `Text` and stream of `Array Word8`. The interconversion in the case of strict `Text` and streamly `Array Word8` has no overhead. diff --git a/cabal.project.Werror b/cabal.project.Werror index 0559699..d4610aa 100644 --- a/cabal.project.Werror +++ b/cabal.project.Werror @@ -3,13 +3,13 @@ packages: streamly-text.cabal package streamly-text ghc-options: -Werror -source-repository-package - type: git - location: https://github.com/composewell/streamly.git - tag: master +-- source-repository-package +-- type: git +-- location: https://github.com/composewell/streamly.git +-- tag: master -source-repository-package - type: git - location: https://github.com/composewell/streamly.git - tag: master - subdir: core +-- source-repository-package +-- type: git +-- location: https://github.com/composewell/streamly.git +-- tag: master +-- subdir: core diff --git a/src/Streamly/External/Text.hs b/src/Streamly/Compat/Text.hs similarity index 81% rename from src/Streamly/External/Text.hs rename to src/Streamly/Compat/Text.hs index 610a783..7ddca95 100644 --- a/src/Streamly/External/Text.hs +++ b/src/Streamly/Compat/Text.hs @@ -3,13 +3,13 @@ {-# LANGUAGE MagicHash #-} {-# LANGUAGE BangPatterns #-} -module Streamly.External.Text +module Streamly.Compat.Text ( toArray , unsafeFromArray , reader - , unsafeCreateOf + -- , unsafeCreateOf , unsafeCreate ) where @@ -58,10 +58,13 @@ toArray (Text (TArr.ByteArray _) _ len) toArray (Text (TArr.ByteArray barr#) off8 len8) = Array (MutByteArray (unsafeCoerce# barr#)) off8 (off8 + len8) --- | Treat an an array of 'Word8' as 'Text'. This function is unsafe and the --- onus is on the caller to check the sanity of 'Array' 'Word8'. This function --- unwraps the 'Array' and wraps it with 'Text' constructors and hence the --- operation is performed in constant time. +-- | Treat an an array of 'Word8' as 'Text'. +-- +-- This function is unsafe: the caller must ensure that the 'Array' 'Word8' is a +-- valid UTF-8 encoding. +-- +-- This function unwraps the 'Array' and wraps it with 'Text' constructors and +-- hence the operation is performed in constant time. {-# INLINE unsafeFromArray #-} unsafeFromArray :: Array Word8 -> Text unsafeFromArray Array {..} @@ -80,9 +83,9 @@ reader :: Monad m => Unfold m Text Word8 reader = lmap toArray Array.reader -- | Fold a stream of Word8 to a 'Text' of given size in bytes. -{-# INLINE unsafeCreateOf #-} -unsafeCreateOf :: MonadIO m => Int -> Fold m Word8 Text -unsafeCreateOf i = unsafeFromArray <$> CREATE_OF i +{-# INLINE _unsafeCreateOf #-} +_unsafeCreateOf :: MonadIO m => Int -> Fold m Word8 Text +_unsafeCreateOf i = unsafeFromArray <$> CREATE_OF i -- | Fold a stream of Word8 to a 'Text' of appropriate size. {-# INLINE unsafeCreate #-} diff --git a/src/Streamly/External/Text/Lazy.hs b/src/Streamly/Compat/Text/Lazy.hs similarity index 89% rename from src/Streamly/External/Text/Lazy.hs rename to src/Streamly/Compat/Text/Lazy.hs index 6053c31..cf4995f 100644 --- a/src/Streamly/External/Text/Lazy.hs +++ b/src/Streamly/Compat/Text/Lazy.hs @@ -1,6 +1,6 @@ {-# LANGUAGE CPP #-} -module Streamly.External.Text.Lazy +module Streamly.Compat.Text.Lazy ( chunkReader , reader @@ -20,7 +20,7 @@ import Data.Text.Internal.Lazy (Text(..), chunk) import Streamly.Internal.Data.Stream (Step(..)) import Streamly.Internal.Data.Unfold (Unfold(..)) -import qualified Streamly.External.Text as Strict +import qualified Streamly.Compat.Text as Strict import qualified Streamly.Data.Array as Array import qualified Streamly.Data.Unfold as Unfold import qualified Streamly.Data.Stream as Stream @@ -55,8 +55,8 @@ toChunks = Stream.unfold chunkReader -- | Convert a serial stream of 'Array' 'Word8' to a lazy 'Text'. -- --- This function is unsafe and the onus is on the caller to check the sanity of --- the stream of 'Array' 'Word8'. +-- This function is unsafe: the caller must ensure that each 'Array' 'Word8' +-- element in the stream is a valid UTF-8 encoding. -- -- IMPORTANT NOTE: This function is lazy only for lazy monads -- (e.g. Identity). For strict monads (e.g. /IO/) it consumes the entire input @@ -65,8 +65,8 @@ toChunks = Stream.unfold chunkReader -- -- For strict monads like /IO/ you could create a newtype wrapper to make the -- monad bind operation lazy and lift the stream to that type using hoist, then --- you can use this function to generate the bytestring lazily. For example you --- can wrap the /IO/ type to make the bind lazy like this: +-- you can use this function to generate the text lazily. For example you can +-- wrap the /IO/ type to make the bind lazy like this: -- -- @ -- newtype LazyIO a = LazyIO { runLazy :: IO a } deriving (Functor, Applicative) diff --git a/streamly-text.cabal b/streamly-text.cabal index 99d4fbb..d62806a 100644 --- a/streamly-text.cabal +++ b/streamly-text.cabal @@ -26,8 +26,8 @@ common compile-options library import: compile-options - exposed-modules: Streamly.External.Text - , Streamly.External.Text.Lazy + exposed-modules: Streamly.Compat.Text + , Streamly.Compat.Text.Lazy build-depends: base >=4.7 && <5 , streamly-core >=0.2.0 && <0.3.1 , text >=2.0 && <2.1.2 diff --git a/test/Main.hs b/test/Main.hs index 472f2c5..c70a66c 100644 --- a/test/Main.hs +++ b/test/Main.hs @@ -10,13 +10,14 @@ import Test.QuickCheck.Instances.Text () import System.IO (hClose) import Data.Functor.Identity (Identity(..)) -import qualified Streamly.Internal.Data.Array as Array (castUnsafe) +import qualified Streamly.Internal.Data.Array as Array (unsafeCast) import qualified Data.Text as BS import qualified Data.Text.Lazy as BSL -import qualified Streamly.FileSystem.File as File -import qualified Streamly.External.Text as Strict -import qualified Streamly.External.Text.Lazy as Lazy +import qualified Streamly.FileSystem.FileIO as File +import qualified Streamly.FileSystem.Path as Path +import qualified Streamly.Compat.Text as Strict +import qualified Streamly.Compat.Text.Lazy as Lazy import qualified Streamly.Data.Stream as Stream pipeline :: @@ -55,11 +56,12 @@ writeRead :: Int -> IO () writeRead n = do str <- sequence $ replicate n (randomIO :: IO Char) let txt = BSL.pack str - withSystemTempFile "temp" $ \fp hdl -> do + withSystemTempFile "temp" $ \fp0 hdl -> do + fp <- Path.fromString fp0 hClose hdl - let strm = fmap Array.castUnsafe $ Lazy.toChunks txt + let strm = fmap Array.unsafeCast $ Lazy.toChunks txt Stream.fold (File.writeChunks fp) strm - let strm1 = fmap Array.castUnsafe $ File.readChunks fp + let strm1 = fmap Array.unsafeCast $ File.readChunks fp txt1 <- Lazy.unsafeFromChunksIO strm1 txt1 `shouldBe` txt