Skip to content

Commit 4fbeaf8

Browse files
committed
Merge remote-tracking branch 'github/pr/9'
2 parents 33ea7f8 + 525a6bd commit 4fbeaf8

File tree

5 files changed

+63
-75
lines changed

5 files changed

+63
-75
lines changed

System/OsString.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ module System.OsString
124124
, count
125125
, findIndex
126126
, findIndices
127+
128+
-- * Coercions
129+
, coercionToPlatformTypes
127130
)
128131
where
129132

@@ -204,5 +207,5 @@ import System.OsString.Internal
204207
, findIndices
205208
)
206209
import System.OsString.Internal.Types
207-
( OsString, OsChar )
210+
( OsString, OsChar, coercionToPlatformTypes )
208211
import Prelude ()

System/OsString/Internal.hs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import qualified System.OsString.Posix as PF
3333
#endif
3434
import GHC.Stack (HasCallStack)
3535
import Data.Coerce (coerce)
36+
import Data.Type.Coercion (coerceWith)
3637

3738

3839

@@ -189,11 +190,9 @@ unsafeFromChar = coerce PF.unsafeFromChar
189190

190191
-- | Converts back to a unicode codepoint (total).
191192
toChar :: OsChar -> Char
192-
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
193-
toChar (OsChar (WindowsChar w)) = chr $ fromIntegral w
194-
#else
195-
toChar (OsChar (PosixChar w)) = chr $ fromIntegral w
196-
#endif
193+
toChar = case coercionToPlatformTypes of
194+
Left (co, _) -> chr . fromIntegral . getWindowsChar . coerceWith co
195+
Right (co, _) -> chr . fromIntegral . getPosixChar . coerceWith co
197196

198197
-- | /O(n)/ Append a byte to the end of a 'OsString'
199198
--
@@ -731,4 +730,3 @@ findIndex = coerce PF.findIndex
731730
-- @since 1.4.200.0
732731
findIndices :: (OsChar -> Bool) -> OsString -> [Int]
733732
findIndices = coerce PF.findIndices
734-

System/OsString/Internal/Types.hs

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,15 @@ module System.OsString.Internal.Types
2626
, PlatformChar
2727
, OsString(..)
2828
, OsChar(..)
29+
, coercionToPlatformTypes
2930
)
3031
where
3132

3233

3334
import Control.DeepSeq
35+
import Data.Coerce (coerce)
3436
import Data.Data
37+
import Data.Type.Coercion (Coercion(..), coerceWith)
3538
import Data.Word
3639
import Language.Haskell.TH.Syntax
3740
( Lift (..), lift )
@@ -178,47 +181,25 @@ instance Ord OsString where
178181
-- | \"String-Concatenation\" for 'OsString'. This is __not__ the same
179182
-- as '(</>)'.
180183
instance Monoid OsString where
181-
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
182-
mempty = OsString (WindowsString BS.empty)
183-
#if MIN_VERSION_base(4,16,0)
184-
mappend = (<>)
185-
#else
186-
mappend (OsString (WindowsString a)) (OsString (WindowsString b))
187-
= OsString (WindowsString (mappend a b))
188-
#endif
189-
#else
190-
mempty = OsString (PosixString BS.empty)
191-
#if MIN_VERSION_base(4,16,0)
184+
mempty = coerce BS.empty
185+
#if MIN_VERSION_base(4,11,0)
192186
mappend = (<>)
193187
#else
194-
mappend (OsString (PosixString a)) (OsString (PosixString b))
195-
= OsString (PosixString (mappend a b))
196-
#endif
188+
mappend = coerce (mappend :: BS.ShortByteString -> BS.ShortByteString -> BS.ShortByteString))
197189
#endif
190+
198191
#if MIN_VERSION_base(4,11,0)
199192
instance Semigroup OsString where
200-
#if MIN_VERSION_base(4,16,0)
201-
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
202-
(<>) (OsString (WindowsString a)) (OsString (WindowsString b))
203-
= OsString (WindowsString (mappend a b))
204-
#else
205-
(<>) (OsString (PosixString a)) (OsString (PosixString b))
206-
= OsString (PosixString (mappend a b))
207-
#endif
208-
#else
209-
(<>) = mappend
210-
#endif
193+
(<>) = coerce (mappend :: BS.ShortByteString -> BS.ShortByteString -> BS.ShortByteString)
211194
#endif
212195

213196

214197
instance Lift OsString where
215-
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
216-
lift (OsString (WindowsString bs))
217-
= [| OsString (WindowsString (BS.pack $(lift $ BS.unpack bs))) :: OsString |]
218-
#else
219-
lift (OsString (PosixString bs))
220-
= [| OsString (PosixString (BS.pack $(lift $ BS.unpack bs))) :: OsString |]
221-
#endif
198+
lift xs = case coercionToPlatformTypes of
199+
Left (_, co) ->
200+
[| OsString (WindowsString (BS.pack $(lift $ BS.unpack $ coerce $ coerceWith co xs))) :: OsString |]
201+
Right (_, co) ->
202+
[| OsString (PosixString (BS.pack $(lift $ BS.unpack $ coerce $ coerceWith co xs))) :: OsString |]
222203
#if MIN_VERSION_template_haskell(2,17,0)
223204
liftTyped = TH.unsafeCodeCoerce . TH.lift
224205
#elif MIN_VERSION_template_haskell(2,16,0)
@@ -244,3 +225,17 @@ instance Eq OsChar where
244225
instance Ord OsChar where
245226
compare (OsChar a) (OsChar b) = compare a b
246227

228+
-- | This is a type-level evidence that 'OsChar' is a newtype wrapper
229+
-- over 'WindowsChar' or 'PosixChar' and 'OsString' is a newtype wrapper
230+
-- over 'WindowsString' or 'PosixString'. If you pattern match on
231+
-- 'coercionToPlatformTypes', GHC will know that relevant types
232+
-- are coercible to each other. This helps to avoid CPP in certain scenarios.
233+
coercionToPlatformTypes
234+
:: Either
235+
(Coercion OsChar WindowsChar, Coercion OsString WindowsString)
236+
(Coercion OsChar PosixChar, Coercion OsString PosixString)
237+
#if defined(mingw32_HOST_OS)
238+
coercionToPlatformTypes = Left (Coercion, Coercion)
239+
#else
240+
coercionToPlatformTypes = Right (Coercion, Coercion)
241+
#endif

bench/BenchOsString.hs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
module BenchOsString (benchMark) where
1616

17+
import Data.Type.Coercion (coerceWith, sym)
1718
import System.OsString (osstr)
1819
import qualified System.OsString as S
1920
import System.OsString.Internal.Types (OsString(..), OsChar(..), PosixChar(..), WindowsChar(..))
@@ -24,23 +25,20 @@ benchStr :: String
2425
benchStr = "OsString"
2526

2627
w :: Int -> OsChar
27-
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
28-
w i = OsChar (WindowsChar (fromIntegral i))
29-
#else
30-
w i = OsChar (PosixChar (fromIntegral i))
31-
#endif
28+
w = case S.coercionToPlatformTypes of
29+
Left (co, _) -> coerceWith (sym co) . WindowsChar . fromIntegral
30+
Right (co, _) -> coerceWith (sym co) . PosixChar . fromIntegral
3231

3332
hashWord8 :: OsChar -> OsChar
34-
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
35-
hashWord8 (OsChar (WindowsChar w)) = OsChar . WindowsChar . fromIntegral . hashInt . fromIntegral $ w
36-
#else
37-
hashWord8 (OsChar (PosixChar w)) = OsChar . PosixChar . fromIntegral . hashInt . fromIntegral $ w
38-
#endif
33+
hashWord8 = case S.coercionToPlatformTypes of
34+
Left (co, _) ->
35+
coerceWith (sym co) . WindowsChar . fromIntegral . hashInt . fromIntegral .
36+
getWindowsChar . coerceWith co
37+
Right (co, _) ->
38+
coerceWith (sym co) . PosixChar . fromIntegral . hashInt . fromIntegral .
39+
getPosixChar . coerceWith co
3940

4041
iw :: OsChar -> Int
41-
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
42-
iw (OsChar (WindowsChar w)) = fromIntegral w
43-
#else
44-
iw (OsChar (PosixChar w)) = fromIntegral w
45-
#endif
46-
42+
iw = case S.coercionToPlatformTypes of
43+
Left (co, _) -> fromIntegral . getWindowsChar . coerceWith co
44+
Right (co, _) -> fromIntegral . getPosixChar . coerceWith co

tests/bytestring-tests/Properties/Common.hs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ import qualified System.OsString.Data.ByteString.Short as B8
6262
import Data.Word
6363

6464
import Control.Arrow
65+
import Data.Coerce (coerce)
66+
import Data.Type.Coercion (Coercion(..), coerceWith, sym)
6567
import Data.Foldable
6668
import Data.List as L
6769
import Data.Semigroup
@@ -145,28 +147,22 @@ swapWPosix = id
145147

146148
#ifdef OSWORD
147149
isSpace :: OsChar -> Bool
148-
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
149-
isSpace = isSpaceWin . getOsChar
150-
#else
151-
isSpace = isSpacePosix . getOsChar
152-
#endif
150+
isSpace = case OBS.coercionToPlatformTypes of
151+
Left (co, _) -> isSpaceWin . coerceWith co
152+
Right (co, _) -> isSpacePosix . coerceWith co
153153

154154
numWord :: OsString -> Int
155-
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
156-
numWord = numWordWin . getOsString
157-
#else
158-
numWord = numWordPosix . getOsString
159-
#endif
155+
numWord = case OBS.coercionToPlatformTypes of
156+
Left (_, co) -> numWordWin . coerceWith co
157+
Right (_, co) -> numWordPosix . coerceWith co
160158

161159
toElem :: OsChar -> OsChar
162160
toElem = id
163161

164162
swapW :: OsChar -> OsChar
165-
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
166-
swapW = OsChar . swapWWin . getOsChar
167-
#else
168-
swapW = OsChar . swapWPosix . getOsChar
169-
#endif
163+
swapW = case OBS.coercionToPlatformTypes of
164+
Left (co, _) -> coerceWith (sym co) . swapWWin . coerceWith co
165+
Right (co, _) -> coerceWith (sym co) . swapWPosix . coerceWith co
170166

171167
instance Arbitrary OsString where
172168
arbitrary = OsString <$> arbitrary
@@ -184,11 +180,9 @@ deriving instance Num OsChar
184180
deriving instance Bounded OsChar
185181

186182
instance Arbitrary ShortByteString where
187-
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
188-
arbitrary = getWindowsString <$> arbitrary
189-
#else
190-
arbitrary = getPosixString <$> arbitrary
191-
#endif
183+
arbitrary = case OBS.coercionToPlatformTypes of
184+
Left (_, _) -> getWindowsString <$> arbitrary
185+
Right (_, _) -> getPosixString <$> arbitrary
192186

193187
#else
194188

0 commit comments

Comments
 (0)