{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
module System.Filesystem.PathComponent
( PathComponent
, pathComponent
, isPathComponent
, getPC
, slashify
, splitPathComponents
) where
import Control.Monad.Fail
import qualified Data.ByteString as B
import Data.Maybe (fromMaybe)
import Data.Semigroup
import Data.String
import Prelude hiding (fail)
import System.Posix.FilePath
import Text.Printf
newtype PathComponent = PC {
getPC :: B.ByteString
} deriving (Eq, Ord, Show, Semigroup)
instance IsString PathComponent where
fromString = fromMaybe (error "not a PathComponent") . pathComponent . fromString
pathComponent :: MonadFail m => B.ByteString -> m PathComponent
pathComponent b | isPathComponent b = pure (PC b)
| otherwise = fail (printf "Not a valud PathComponent (%s)" (show b))
isPathComponent :: B.ByteString -> Bool
isPathComponent "" = False
isPathComponent b = B.all (`B.notElem` "\x00/") b
slashify :: PathComponent -> B.ByteString
slashify (PC p) = B.snoc p 0x2f
splitPathComponents :: MonadFail m => RawFilePath -> m [PathComponent]
splitPathComponents =
maybe (fail "path contained a null byte") pure . mapM pathComponent . splitDirectories