From 3be088ccf6c32f4d844355f48f7ef78c1d0fc29b Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sat, 14 Oct 2023 18:57:19 +0800 Subject: [PATCH] Add more bytestring like functions --- System/OsString.hs | 65 ++++++ System/OsString/Common.hs | 383 ++++++++++++++++++++++++++++++++++++ System/OsString/Internal.hs | 86 ++++++++ 3 files changed, 534 insertions(+) diff --git a/System/OsString.hs b/System/OsString.hs index c11a4bdf..cfa8ee38 100644 --- a/System/OsString.hs +++ b/System/OsString.hs @@ -24,6 +24,8 @@ module System.OsString , encodeWith , encodeFS , osstr + , empty + , singleton , pack -- * OsString deconstruction @@ -40,6 +42,40 @@ module System.OsString -- * Word deconstruction , toChar + + -- * Basic interface + , snoc + , cons + , last + , tail + , uncons + , head + , unsnoc + , null + , length + , map + , reverse + , intercalate + + -- * Reducing OsStrings (folds) + , foldl + , foldl' + , foldl1 + , foldl1' + , foldr + , foldr' + , foldr1 + , foldr1' + + -- * Special folds + , all + , any + , concat + + -- * Generating and unfolding OsStrings + , replicate + , unfoldr + , unfoldrN ) where @@ -51,10 +87,39 @@ import System.OsString.Internal , encodeFS , osstr , pack + , empty + , singleton , decodeUtf , decodeWith , decodeFS , unpack + , snoc + , cons + , last + , tail + , uncons + , head + , unsnoc + , null + , length + , map + , reverse + , intercalate + , foldl + , foldl' + , foldl1 + , foldl1' + , foldr + , foldr' + , foldr1 + , foldr1' + , all + , any + , concat + , replicate + , unfoldr + , unfoldrN ) import System.OsString.Internal.Types ( OsString, OsChar ) +import Prelude hiding (last, tail, head, init, null, length, map, reverse, foldl, foldr, foldl1, foldr1, all, any, concat, replicate, take, takeWhile, drop, dropWhile, break, span, splitAt) diff --git a/System/OsString/Common.hs b/System/OsString/Common.hs index 80eb69b5..ea841d69 100644 --- a/System/OsString/Common.hs +++ b/System/OsString/Common.hs @@ -1,6 +1,7 @@ {- HLINT ignore "Unused LANGUAGE pragma" -} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE RankNTypes #-} -- This template expects CPP definitions for: -- MODULE_NAME = Posix | Windows -- IS_WINDOWS = False | True @@ -28,6 +29,8 @@ module System.OsString.MODULE_NAME , encodeFS , fromBytes , pstr + , singleton + , empty , pack -- * String deconstruction @@ -41,6 +44,63 @@ module System.OsString.MODULE_NAME -- * Word deconstruction , toChar + + -- * Basic interface + , snoc + , cons + , last + , tail + , uncons + , head + , init + , unsnoc + , null + , length + + -- * Transforming OsString + , map + , reverse + , intercalate + + -- * Reducing OsStrings (folds) + , foldl + , foldl' + , foldl1 + , foldl1' + , foldr + , foldr' + , foldr1 + , foldr1' + + -- ** Special folds + , all + , any + , concat + + -- ** Generating and unfolding OsStrings + , replicate + , unfoldr + , unfoldrN + + -- * Substrings + -- ** Breaking strings + , take + , takeEnd + , takeWhileEnd + , takeWhile + , drop + , dropEnd + , dropWhileEnd + , dropWhile + , break + , breakEnd + , span + , spanEnd + , splitAt + , split + , splitWith + , stripSuffix + , stripPrefix ) where @@ -87,6 +147,9 @@ import System.IO import GHC.IO.Encoding.UTF8 ( mkUTF8 ) import qualified System.OsPath.Data.ByteString.Short as BS #endif +import GHC.Stack (HasCallStack) +import Prelude hiding (last, tail, head, init, null, length, map, reverse, foldl, foldr, foldl1, foldr1, all, any, concat, replicate, take, takeWhile, drop, dropWhile, break, span, splitAt) +import Data.Bifunctor ( bimap ) @@ -295,6 +358,16 @@ pack = WindowsString . BS16.pack . fmap (\(WindowsChar w) -> w) pack = PosixString . BS.pack . fmap (\(PosixChar w) -> w) #endif +singleton :: PLATFORM_WORD -> PLATFORM_STRING +#ifdef WINDOWS +singleton = WindowsString . BS16.singleton . getWindowsChar +#else +singleton = PosixString . BS.singleton . getPosixChar +#endif + +empty :: PLATFORM_STRING +empty = mempty + #ifdef WINDOWS -- | Truncates to 2 octets. @@ -313,3 +386,313 @@ toChar (WindowsChar w) = chr $ fromIntegral w #else toChar (PosixChar w) = chr $ fromIntegral w #endif + +snoc :: PLATFORM_STRING -> PLATFORM_WORD -> PLATFORM_STRING +#ifdef WINDOWS +snoc (WindowsString s) (WindowsChar w) = WindowsString (BS16.snoc s w) +#else +snoc (PosixString s) (PosixChar w) = PosixString (BS.snoc s w) +#endif + + +cons :: PLATFORM_WORD -> PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +cons (WindowsChar w) (WindowsString s) = WindowsString (BS16.cons w s) +#else +cons (PosixChar w) (PosixString s) = PosixString (BS.cons w s) +#endif + + +last :: HasCallStack => PLATFORM_STRING -> PLATFORM_WORD +#ifdef WINDOWS +last (WindowsString s) = WindowsChar (BS16.last s) +#else +last (PosixString s) = PosixChar (BS.last s) +#endif + +tail :: HasCallStack => PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +tail (WindowsString s) = WindowsString (BS16.tail s) +#else +tail (PosixString s) = PosixString (BS.tail s) +#endif + +uncons :: PLATFORM_STRING -> Maybe (PLATFORM_WORD, PLATFORM_STRING) +#ifdef WINDOWS +uncons (WindowsString s) = (bimap WindowsChar WindowsString) <$> (BS16.uncons s) +#else +uncons (PosixString s) = (bimap PosixChar PosixString) <$> (BS.uncons s) +#endif + +head :: HasCallStack => PLATFORM_STRING -> PLATFORM_WORD +#ifdef WINDOWS +head (WindowsString s) = WindowsChar (BS16.head s) +#else +head (PosixString s) = PosixChar (BS.head s) +#endif + +init :: HasCallStack => PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +init (WindowsString s) = WindowsString (BS16.init s) +#else +init (PosixString s) = PosixString (BS.init s) +#endif + +unsnoc :: PLATFORM_STRING -> Maybe (PLATFORM_STRING, PLATFORM_WORD) +#ifdef WINDOWS +unsnoc (WindowsString s) = (bimap WindowsString WindowsChar) <$> (BS16.unsnoc s) +#else +unsnoc (PosixString s) = (bimap PosixString PosixChar) <$> (BS.unsnoc s) +#endif + +null :: PLATFORM_STRING -> Bool +#ifdef WINDOWS +null (WindowsString s) = BS16.null s +#else +null (PosixString s) = BS.null s +#endif + +length :: PLATFORM_STRING -> Int +#ifdef WINDOWS +length (WindowsString s) = BS16.length s +#else +length (PosixString s) = BS.length s +#endif + +map :: (PLATFORM_WORD -> PLATFORM_WORD) -> PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +map f (WindowsString s) = WindowsString (BS16.map (getWindowsChar . f . WindowsChar) s) +#else +map f (PosixString s) = PosixString (BS.map (getPosixChar . f . PosixChar) s) +#endif + +reverse :: PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +reverse (WindowsString s) = WindowsString (BS16.reverse s) +#else +reverse (PosixString s) = PosixString (BS.reverse s) +#endif + +intercalate :: PLATFORM_STRING -> [PLATFORM_STRING] -> PLATFORM_STRING +#ifdef WINDOWS +intercalate (WindowsString s) xs = WindowsString (BS16.intercalate s (fmap getWindowsString xs)) +#else +intercalate (PosixString s) xs = PosixString (BS.intercalate s (fmap getPosixString xs)) +#endif + +foldl :: (a -> PLATFORM_WORD -> a) -> a -> PLATFORM_STRING -> a +#ifdef WINDOWS +foldl f a (WindowsString s) = BS16.foldl (\a' c -> f a' (WindowsChar c)) a s +#else +foldl f a (PosixString s) = BS.foldl (\a' c -> f a' (PosixChar c)) a s +#endif + +foldl' + :: (a -> PLATFORM_WORD -> a) -> a -> PLATFORM_STRING -> a +#ifdef WINDOWS +foldl' f a (WindowsString s) = BS16.foldl' (\a' c -> f a' (WindowsChar c)) a s +#else +foldl' f a (PosixString s) = BS.foldl' (\a' c -> f a' (PosixChar c)) a s +#endif + +foldl1 :: (PLATFORM_WORD -> PLATFORM_WORD -> PLATFORM_WORD) -> PLATFORM_STRING -> PLATFORM_WORD +#ifdef WINDOWS +foldl1 f (WindowsString s) = WindowsChar $ BS16.foldl1 (\a' c -> getWindowsChar $ f (WindowsChar a') (WindowsChar c)) s +#else +foldl1 f (PosixString s) = PosixChar $ BS.foldl1 (\a' c -> getPosixChar $ f (PosixChar a') (PosixChar c)) s +#endif + +foldl1' + :: (PLATFORM_WORD -> PLATFORM_WORD -> PLATFORM_WORD) -> PLATFORM_STRING -> PLATFORM_WORD +#ifdef WINDOWS +foldl1' f (WindowsString s) = WindowsChar $ BS16.foldl1' (\a' c -> getWindowsChar $ f (WindowsChar a') (WindowsChar c)) s +#else +foldl1' f (PosixString s) = PosixChar $ BS.foldl1' (\a' c -> getPosixChar $ f (PosixChar a') (PosixChar c)) s +#endif + +foldr :: (PLATFORM_WORD -> a -> a) -> a -> PLATFORM_STRING -> a +#ifdef WINDOWS +foldr f a (WindowsString s) = BS16.foldr (\c a' -> f (WindowsChar c) a') a s +#else +foldr f a (PosixString s) = BS.foldr (\c a' -> f (PosixChar c) a') a s +#endif + +foldr' + :: (PLATFORM_WORD -> a -> a) -> a -> PLATFORM_STRING -> a +#ifdef WINDOWS +foldr' f a (WindowsString s) = BS16.foldr' (\c a' -> f (WindowsChar c) a') a s +#else +foldr' f a (PosixString s) = BS.foldr' (\c a' -> f (PosixChar c) a') a s +#endif + +foldr1 :: (PLATFORM_WORD -> PLATFORM_WORD -> PLATFORM_WORD) -> PLATFORM_STRING -> PLATFORM_WORD +#ifdef WINDOWS +foldr1 f (WindowsString s) = WindowsChar $ BS16.foldr1 (\c a' -> getWindowsChar $ f (WindowsChar c) (WindowsChar a')) s +#else +foldr1 f (PosixString s) = PosixChar $ BS.foldr1 (\c a' -> getPosixChar $ f (PosixChar c) (PosixChar a')) s +#endif + +foldr1' + :: (PLATFORM_WORD -> PLATFORM_WORD -> PLATFORM_WORD) -> PLATFORM_STRING -> PLATFORM_WORD +#ifdef WINDOWS +foldr1' f (WindowsString s) = WindowsChar $ BS16.foldr1' (\c a' -> getWindowsChar $ f (WindowsChar c) (WindowsChar a')) s +#else +foldr1' f (PosixString s) = PosixChar $ BS.foldr1' (\c a' -> getPosixChar $ f (PosixChar c) (PosixChar a')) s +#endif + +all :: (PLATFORM_WORD -> Bool) -> PLATFORM_STRING -> Bool +#ifdef WINDOWS +all f (WindowsString s) = BS16.all (f . WindowsChar) s +#else +all f (PosixString s) = BS.all (f . PosixChar) s +#endif + +any :: (PLATFORM_WORD -> Bool) -> PLATFORM_STRING -> Bool +#ifdef WINDOWS +any f (WindowsString s) = BS16.any (f . WindowsChar) s +#else +any f (PosixString s) = BS.any (f . PosixChar) s +#endif + +concat :: [PLATFORM_STRING] -> PLATFORM_STRING +concat = mconcat + +replicate :: Int -> PLATFORM_WORD -> PLATFORM_STRING +#ifdef WINDOWS +replicate i (WindowsChar w) = WindowsString $ BS16.replicate i w +#else +replicate i (PosixChar w) = PosixString $ BS.replicate i w +#endif + +unfoldr :: (a -> Maybe (PLATFORM_WORD, a)) -> a -> PLATFORM_STRING +#ifdef WINDOWS +unfoldr f a = WindowsString $ BS16.unfoldr (fmap (first getWindowsChar) . f) a +#else +unfoldr f a = PosixString $ BS.unfoldr (fmap (first getPosixChar) . f) a +#endif + +unfoldrN :: forall a. Int -> (a -> Maybe (PLATFORM_WORD, a)) -> a -> (PLATFORM_STRING, Maybe a) +#ifdef WINDOWS +unfoldrN n f a = first WindowsString $ BS16.unfoldrN n (fmap (first getWindowsChar) . f) a +#else +unfoldrN n f a = first PosixString $ BS.unfoldrN n (fmap (first getPosixChar) . f) a +#endif + +take :: Int -> PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +take n (WindowsString s) = WindowsString $ BS16.take n s +#else +take n (PosixString s) = PosixString $ BS.take n s +#endif + +takeEnd :: Int -> PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +takeEnd n (WindowsString s) = WindowsString $ BS16.takeEnd n s +#else +takeEnd n (PosixString s) = PosixString $ BS.takeEnd n s +#endif + +takeWhileEnd :: (PLATFORM_WORD -> Bool) -> PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +takeWhileEnd f (WindowsString s) = WindowsString $ BS16.takeWhileEnd (f . WindowsChar) s +#else +takeWhileEnd f (PosixString s) = PosixString $ BS.takeWhileEnd (f . PosixChar) s +#endif + +takeWhile :: (PLATFORM_WORD -> Bool) -> PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +takeWhile f (WindowsString s) = WindowsString $ BS16.takeWhile (f . WindowsChar) s +#else +takeWhile f (PosixString s) = PosixString $ BS.takeWhile (f . PosixChar) s +#endif + +drop :: Int -> PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +drop n (WindowsString s) = WindowsString $ BS16.drop n s +#else +drop n (PosixString s) = PosixString $ BS.drop n s +#endif + +dropEnd :: Int -> PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +dropEnd n (WindowsString s) = WindowsString $ BS16.dropEnd n s +#else +dropEnd n (PosixString s) = PosixString $ BS.dropEnd n s +#endif + +dropWhile :: (PLATFORM_WORD -> Bool) -> PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +dropWhile f (WindowsString s) = WindowsString $ BS16.dropWhile (f . WindowsChar) s +#else +dropWhile f (PosixString s) = PosixString $ BS.dropWhile (f . PosixChar) s +#endif + +dropWhileEnd :: (PLATFORM_WORD -> Bool) -> PLATFORM_STRING -> PLATFORM_STRING +#ifdef WINDOWS +dropWhileEnd f (WindowsString s) = WindowsString $ BS16.dropWhileEnd (f . WindowsChar) s +#else +dropWhileEnd f (PosixString s) = PosixString $ BS.dropWhileEnd (f . PosixChar) s +#endif + +breakEnd :: (PLATFORM_WORD -> Bool) -> PLATFORM_STRING -> (PLATFORM_STRING, PLATFORM_STRING) +#ifdef WINDOWS +breakEnd f (WindowsString s) = bimap WindowsString WindowsString $ BS16.breakEnd (f . WindowsChar) s +#else +breakEnd f (PosixString s) = bimap PosixString PosixString $ BS.breakEnd (f . PosixChar) s +#endif + +break :: (PLATFORM_WORD -> Bool) -> PLATFORM_STRING -> (PLATFORM_STRING, PLATFORM_STRING) +#ifdef WINDOWS +break f (WindowsString s) = bimap WindowsString WindowsString $ BS16.break (f . WindowsChar) s +#else +break f (PosixString s) = bimap PosixString PosixString $ BS.break (f . PosixChar) s +#endif + +span :: (PLATFORM_WORD -> Bool) -> PLATFORM_STRING -> (PLATFORM_STRING, PLATFORM_STRING) +#ifdef WINDOWS +span f (WindowsString s) = bimap WindowsString WindowsString $ BS16.span (f . WindowsChar) s +#else +span f (PosixString s) = bimap PosixString PosixString $ BS.span (f . PosixChar) s +#endif + +spanEnd :: (PLATFORM_WORD -> Bool) -> PLATFORM_STRING -> (PLATFORM_STRING, PLATFORM_STRING) +#ifdef WINDOWS +spanEnd f (WindowsString s) = bimap WindowsString WindowsString $ BS16.spanEnd (f . WindowsChar) s +#else +spanEnd f (PosixString s) = bimap PosixString PosixString $ BS.spanEnd (f . PosixChar) s +#endif + +splitAt :: Int -> PLATFORM_STRING -> (PLATFORM_STRING, PLATFORM_STRING) +#ifdef WINDOWS +splitAt n (WindowsString s) = bimap WindowsString WindowsString $ BS16.splitAt n s +#else +splitAt n (PosixString s) = bimap PosixString PosixString $ BS.splitAt n s +#endif + +split :: PLATFORM_WORD -> PLATFORM_STRING -> [PLATFORM_STRING] +#ifdef WINDOWS +split (WindowsChar w) (WindowsString s) = WindowsString <$> BS16.split w s +#else +split (PosixChar w) (PosixString s) = PosixString <$> BS.split w s +#endif + +splitWith :: (PLATFORM_WORD -> Bool) -> PLATFORM_STRING -> [PLATFORM_STRING] +#ifdef WINDOWS +splitWith f (WindowsString s) = WindowsString <$> BS16.splitWith (f . WindowsChar) s +#else +splitWith f (PosixString s) = PosixString <$> BS.splitWith (f . PosixChar) s +#endif + +stripSuffix :: PLATFORM_STRING -> PLATFORM_STRING -> Maybe PLATFORM_STRING +#ifdef WINDOWS +stripSuffix (WindowsString a) (WindowsString b) = WindowsString <$> BS16.stripSuffix a b +#else +stripSuffix (PosixString a) (PosixString b) = PosixString <$> BS.stripSuffix a b +#endif + +stripPrefix :: PLATFORM_STRING -> PLATFORM_STRING -> Maybe PLATFORM_STRING +#ifdef WINDOWS +stripPrefix (WindowsString a) (WindowsString b) = WindowsString <$> BS16.stripPrefix a b +#else +stripPrefix (PosixString a) (PosixString b) = PosixString <$> BS.stripPrefix a b +#endif diff --git a/System/OsString/Internal.hs b/System/OsString/Internal.hs index f72fdcb7..a2d95da8 100644 --- a/System/OsString/Internal.hs +++ b/System/OsString/Internal.hs @@ -27,6 +27,8 @@ import qualified System.OsString.Windows as PF import GHC.IO.Encoding.UTF8 ( mkUTF8 ) import qualified System.OsString.Posix as PF #endif +import GHC.Stack (HasCallStack) +import Data.Bifunctor @@ -159,6 +161,12 @@ unpack (OsString x) = OsChar <$> PF.unpack x pack :: [OsChar] -> OsString pack = OsString . PF.pack . fmap (\(OsChar x) -> x) +empty :: OsString +empty = mempty + +singleton :: OsChar -> OsString +singleton = OsString . PF.singleton . getOsChar + -- | Truncates on unix to 1 and on Windows to 2 octets. unsafeFromChar :: Char -> OsChar @@ -172,3 +180,81 @@ toChar (OsChar (WindowsChar w)) = chr $ fromIntegral w toChar (OsChar (PosixChar w)) = chr $ fromIntegral w #endif +snoc :: OsString -> OsChar -> OsString +snoc (OsString s) (OsChar w) = OsString (PF.snoc s w) + +cons :: OsChar -> OsString -> OsString +cons (OsChar w) (OsString s) = OsString (PF.cons w s) + +last :: HasCallStack => OsString -> OsChar +last (OsString s) = OsChar (PF.last s) + +tail :: HasCallStack => OsString -> OsString +tail (OsString s) = OsString (PF.tail s) + +uncons :: OsString -> Maybe (OsChar, OsString) +uncons (OsString s) = bimap OsChar OsString <$> PF.uncons s + +head :: HasCallStack => OsString -> OsChar +head (OsString s) = OsChar (PF.head s) + +unsnoc :: OsString -> Maybe (OsString, OsChar) +unsnoc (OsString s) = bimap OsString OsChar <$> PF.unsnoc s + +null :: OsString -> Bool +null (OsString s) = PF.null s + +length :: OsString -> Int +length (OsString s) = PF.length s + +map :: (OsChar -> OsChar) -> OsString -> OsString +map f (OsString s) = OsString (PF.map (getOsChar . f . OsChar) s) + +reverse :: OsString -> OsString +reverse (OsString s) = OsString (PF.reverse s) + +intercalate :: OsString -> [OsString] -> OsString +intercalate (OsString s) xs = OsString (PF.intercalate s (fmap getOsString xs)) + +foldl :: (a -> OsChar -> a) -> a -> OsString -> a +foldl f a (OsString s) = PF.foldl (\a' c -> f a' (OsChar c)) a s + +foldl' :: (a -> OsChar -> a) -> a -> OsString -> a +foldl' f a (OsString s) = PF.foldl' (\a' c -> f a' (OsChar c)) a s + +foldl1 :: (OsChar -> OsChar -> OsChar) -> OsString -> OsChar +foldl1 f (OsString s) = OsChar $ PF.foldl1 (\a' c -> getOsChar $ f (OsChar a') (OsChar c)) s + +foldl1' :: (OsChar -> OsChar -> OsChar) -> OsString -> OsChar +foldl1' f (OsString s) = OsChar $ PF.foldl1' (\a' c -> getOsChar $ f (OsChar a') (OsChar c)) s + + +foldr :: (OsChar -> a -> a) -> a -> OsString -> a +foldr f a (OsString s) = PF.foldr (\c a' -> f (OsChar c) a') a s + +foldr' :: (OsChar -> a -> a) -> a -> OsString -> a +foldr' f a (OsString s) = PF.foldr' (\c a' -> f (OsChar c) a') a s + +foldr1 :: (OsChar -> OsChar -> OsChar) -> OsString -> OsChar +foldr1 f (OsString s) = OsChar $ PF.foldr1 (\c a' -> getOsChar $ f (OsChar c) (OsChar a')) s + +foldr1' :: (OsChar -> OsChar -> OsChar) -> OsString -> OsChar +foldr1' f (OsString s) = OsChar $ PF.foldr1' (\c a' -> getOsChar $ f (OsChar c) (OsChar a')) s + +all :: (OsChar -> Bool) -> OsString -> Bool +all f (OsString s) = PF.all (f . OsChar) s + +any :: (OsChar -> Bool) -> OsString -> Bool +any f (OsString s) = PF.any (f . OsChar) s + +concat :: [OsString] -> OsString +concat = mconcat + +replicate :: Int -> OsChar -> OsString +replicate i (OsChar w) = OsString $ PF.replicate i w + +unfoldr :: (a -> Maybe (OsChar, a)) -> a -> OsString +unfoldr f a = OsString $ PF.unfoldr (fmap (first getOsChar) . f) a + +unfoldrN :: forall a. Int -> (a -> Maybe (OsChar, a)) -> a -> (OsString, Maybe a) +unfoldrN n f a = first OsString $ PF.unfoldrN n (fmap (first getOsChar) . f) a