{-# LANGUAGE OverloadedStrings, BangPatterns #-}
module Network.Wai.Application.Classic.Path (
Path
, pathString
, fromString
, (</>), (<\>), (<.>)
, breakAtSeparator, hasLeadingPathSeparator, hasTrailingPathSeparator
, isSuffixOf
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as B8
import Data.String
import Data.Word
type Path = ByteString
pathString :: Path -> String
pathString = B8.unpack
{-# INLINE pathString #-}
pathDotBS :: ByteString
pathDotBS = "."
pathSep :: Word8
pathSep = 47
pathSepBS :: ByteString
pathSepBS = "/"
hasLeadingPathSeparator :: Path -> Bool
hasLeadingPathSeparator bs
| BS.null bs = False
| BS.head bs == pathSep = True
| otherwise = False
{-# INLINE hasLeadingPathSeparator #-}
hasTrailingPathSeparator :: Path -> Bool
hasTrailingPathSeparator bs
| BS.null bs = False
| BS.last bs == pathSep = True
| otherwise = False
{-# INLINE hasTrailingPathSeparator #-}
(</>) :: Path -> Path -> Path
p1 </> p2 = p
where
!has1 = hasTrailingPathSeparator p1
!has2 = hasLeadingPathSeparator p2
!p | has1 && not has2 = p1 `BS.append` p2
| not has1 && has2 = p1 `BS.append` p2
| has1 = p1 `BS.append` BS.tail p2
| otherwise = BS.concat [p1,pathSepBS,p2]
{-# INLINE (</>) #-}
(<\>) :: Path -> Path -> Path
p1 <\> p2 = p
where
!p = BS.drop (BS.length p2) p1
{-# INLINE (<\>) #-}
(<.>) :: Path -> Path -> Path
p1 <.> p2 = p
where
!p = BS.concat [p1,pathDotBS,p2]
{-# INLINE (<.>) #-}
breakAtSeparator :: Path -> (Path,Path)
breakAtSeparator p = BS.break (== pathSep) p
{-# INLINE breakAtSeparator #-}
isSuffixOf :: Path -> Path -> Bool
isSuffixOf = BS.isSuffixOf
{-# INLINE isSuffixOf #-}