-- |
-- Module      : Streamly.FileSystem.Path
-- Copyright   : (c) 2023 Composewell Technologies
-- License     : BSD3
-- Maintainer  : streamly@composewell.com
-- Portability : GHC
--
-- File system paths with flexible (gradual) typing, extensible,
-- high-performance, preserving the OS and filesystem encoding.
--
-- /Flexible/: you can choose the level of type safety you want. 'Path' is the
-- basic path type which can represent a file, directory, absolute or relative
-- path with no restrictions. Depending on how much type safety you want, you
-- can choose appropriate type wrappers or a combination of those to wrap the
-- 'Path' type.
--
-- = Rooted Paths vs Branches
--
-- For the safety of the path append operation we make the distinction of
-- rooted paths vs branches. A path that starts from some implicit or
-- explicit root in the file system is a rooted path, for example, @\/usr\/bin@
-- is a rooted path starting from an explicit file system root directory @/@.
-- Similarly, @.\/bin@ is a path with an implicit root, this path is hanging
-- from the current directory. A path that is not rooted is called a branch
-- e.g. @local\/bin@ is a branch.
--
-- This distinction affords safety to the path append operation. We can always
-- append a branch to a rooted path or to another branch. However, it does
-- not make sense to append a rooted path to another rooted path. The default
-- append operation in the Path module checks for this and fails if the
-- operation is incorrect. However, the programmer can force it by using the
-- unsafe version of the append operation. You can also drop the root
-- explicitly and use the safe append operation.
--
-- The "Streamly.FileSystem.Path.Seg" module provides explicit typing of path
-- segments e.g. rooted paths vs branches. Rooted paths are represented by the
-- @Rooted Path@ type and branches are represented by the @Branch Path@ type.
-- If you use the 'Path' type then append can fail if you try to append a
-- rooted path to another path, but if you use @Rooted Path@ and @Branch Path@
-- types then append can never fail at run time as the types would not allow it
-- at compile time.
--
-- = Absolute vs Relative Rooted Paths
--
-- Rooted paths can be absolute or relative. Absolute paths have an absolute
-- root e.g. @\/usr\/bin@. Relative paths have a dynamic or relative root e.g.
-- @.\/local\/bin@, or @.@, in these cases the root is current directory which
-- is not absolute but can change dynamically. Note that there is no type level
-- distinction for absolute and relative paths. The append operation requires a
-- distinction between Rooted and Branch only.
--
-- = File vs Directory Paths
--
-- Independent of the rooted or branch distinction you can also make a type
-- level distinction between file and directory type nodes using the
-- "Streamly.FileSystem.Path.Node" module. @File Path@ type represents a file
-- whereas @Dir Path@ represents a directory. This distinction provides safety
-- against appending a path to a file. Append operation does not allow
-- appending to 'File' types.
--
-- By default a path with a trailing separator is implicitly considered a
-- directory path. However, the absence of a trailing separator does not convey
-- any information, it could either be a directory or a file. Thus the append
-- operation allows appending to even paths that do not have a trailing
-- separator. However, when creating a typed path of 'File' type the conversion
-- fails unless we explicitly drop the trailing separator.
--
-- = Flexible Typing
--
-- You can use the 'Rooted', 'Branch' or 'Dir', 'File' types independent of
-- each other by using only the required module. If you want both types of
-- distinctions then you can use them together as well using the
-- "Streamly.FileSystem.Path.SegNode" module.  For example, the @Rooted (Dir
-- Path)@ represents a rooted path which is a directory. You can only append to
-- a path that has 'Dir' in it and you can only append a 'Branch' type.
--
-- You can choose to use just the basic 'Path' type or any combination of safer
-- types. You can upgrade or downgrade the safety by converting types using the
-- @adapt@ operation. Whenever a less restrictive path type is converted to a
-- more restrictive path type, the conversion involves run-time checks and it
-- may fail. However, a more restrictive path type can be freely converted to a
-- less restrictive one.
--
-- = Extensibility
--
-- You can define your own newtype wrappers similar to 'File' or 'Dir' to
-- provide custom restrictions if you want.
--
-- = Compatibility
--
-- Any path type can be converted to the 'FilePath' type using the 'toString'
-- operation. Operations to convert to and from 'OsPath' type at zero cost are
-- provided in the @streamly-filepath@ package. This is possible because the
-- types use an underlying representation which is compatible with the 'OsPath'
-- type.
--
-- = String Creation Quasiquoter
--
-- You may find the 'str' quasiquoter from "Streamly.Unicode.String" to be
-- useful in creating paths.
--

module Streamly.FileSystem.Path
    (
    -- * Type
      Path

    -- * Conversions
    , IsPath (..)
    , adapt

    -- * Construction
    , fromString

    -- * Statically Verified String Literals
    -- | Quasiquoters.
    , path

    -- * Statically Verified Strings
    -- | Template Haskell expression splices.
    , pathE

    -- * Elimination
    , toString

    -- * Operations
    -- , dropTrailingSeparators
    , isRooted
    , isBranch

    -- * Combinators
    , append
    )
where

import Streamly.Internal.FileSystem.Path