haskell / filepath

Haskell FilePath core library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Provide conversions between PosixPath and WindowsPath

Bodigrim opened this issue · comments

haskell/tar#88 introduces

-- | We assume UTF-8 on posix and UTF-16 on windows.
toWindowsPath :: MonadThrow m => PosixPath -> m WindowsPath
toWindowsPath posix = do
  str <- PFP.decodeUtf posix
  win <- WFP.encodeUtf str
  pure $ WS.map (\c -> if WFP.isPathSeparator c then WFP.pathSeparator else c) win

-- | We assume UTF-8 on posix and UTF-16 on windows.
toPosixPath :: MonadThrow m => WindowsPath -> m PosixPath
toPosixPath win = do
  str   <- WFP.decodeUtf win
  posix <- PFP.encodeUtf str
  pure $ PS.map (\c -> if PFP.isPathSeparator c then PFP.pathSeparator else c) posix

IMHO such utilities should better be provided by filepath itself, ideally optimized to a single pass without any intermediate structures.

Our primitives rely on the TextEncoding modules in base and use peekCStringLen etc.

See:

-- | Decode with the given 'TextEncoding'.
decodeWithTE :: TextEncoding -> BS8.ShortByteString -> Either EncodingException String
decodeWithTE enc ba = unsafePerformIO $ do
  r <- try @SomeException $ BS8.useAsCStringLen ba $ \fp -> GHC.peekCStringLen enc fp
  evaluate $ force $ first (flip EncodingError Nothing . displayException) r

-- | Encode with the given 'TextEncoding'.
encodeWithTE :: TextEncoding -> String -> Either EncodingException BS8.ShortByteString
encodeWithTE enc str = unsafePerformIO $ do
  r <- try @SomeException $ GHC.withCStringLen enc str $ \cstr -> BS8.packCStringLen cstr
  evaluate $ force $ first (flip EncodingError Nothing . displayException) r

The encoders/decoders API don't work well with non-String afair: https://hackage.haskell.org/package/base-4.19.0.0/docs/GHC-IO-Encoding.html

Because e.g. TextEncoder is fixed to char: type TextDecoder state = BufferCodec Word8 CharBufElem state.

How do you propose we get the API with TextEncoding for free and avoid intermediate representations? Can we not just rely on list fusion or so?

Can we not just rely on list fusion or so?

Given that PFP.decodeUtf is monadic, all effects must happen before we proceed to the next line. This almost certainly prevents any list fusion.

I suggest to write toWindowsPath and toPosixPath manually, without reliance on GHC.IO.Encoding. UTF-8 to UTF-16 and back conversion is reasonably simple.

That sounds hard. Can we cry for help?