content: {-# LANGUAGE CPP #-}
  -- |
  -- Module      : Streamly.FileSystem.Path
  -- Copyright   : (c) 2023 Composewell Technologies
  -- License     : BSD3
  -- Maintainer  : streamly@composewell.com
  -- Portability : GHC
  --
  -- File system paths that are extensible, high-performance and preserve the OS
  -- and filesystem encoding.
  --
  -- The 'Path' type is built on top of Streamly's 'Array' type, leveraging all
  -- its operations — including support for both pinned and unpinned
  -- representations. The API integrates with streams, prioritizes safety,
  -- flexibility, and performance. It supports configurable equality for
  -- cross-platform compatibility and user-defined path matching. It is designed
  -- for extensibility and fine-grained type safety as well. For type-safe
  -- adaptations, see the "Streamly.Internal.FileSystem.Path.*" modules.
  --
  -- 'Path' is interconvertible with the 'OsPath' type from the @filepath@
  -- package at zero runtime cost. While the API is mostly compatible with that
  -- of the @filepath@ package, some differences exist due to a slightly
  -- different design philosophy focused on better safety.
  --
  -- = Rooted vs Unrooted Paths
  --
  -- To ensure the safety of the path append operation, we distinguish between
  -- rooted paths and free path segments or unrooted paths. A path that starts
  -- from an explicit or implicit file system root is called a rooted path or an
  -- anchored path. For example, @\/usr\/bin@ is a rooted path with @/@ as an
  -- explicit root directory. Similarly, @.\/bin@ is a rooted path with the
  -- current directoy \".\" as an implicit root. A path that is not rooted is
  -- called an unrooted path or unanchored path; for example, @local\/bin@ is an
  -- unrooted path.
  --
  -- This distinction ensures the safety of the path append operation. You can
  -- append only an unrooted path to another path, it does not make sense to
  -- append a rooted path to another path. The default append operation in the
  -- Path module checks for this and fails if the operation is invalid.
  --
  -- Rooted vs unrooted distinction is a stricter form of relative vs absolute
  -- path distinction. In this model, for better safety, paths relative to the
  -- current directory are also treated in the same way as absolute paths, from
  -- the perspective of a path append operation. This is because the  meaning of
  -- current directory is context dependent and dynamic, therefore, appending it
  -- to another path is not allowed. Only unrooted path segments (e.g.
  -- @local/bin@) can be appended to any other path using safe operations.
  --
  -- = File vs. Directory Paths
  --
  -- By default, a path with a trailing separator (e.g. @local/@) is implicitly
  -- considered a directory path. However, the absence of a trailing separator
  -- does not indicate whether the path is a file or a directory — it could be
  -- either. Therefore, when using the @Path@ type, the append operation allows
  -- appending to paths even if they lack a trailing separator.
  --
  -- = Compatibility with the filepath package
  --
  -- Any path type can be converted to the 'FilePath' type from the @filepath@
  -- package by using the 'toString' operation. Operations to convert to and from
  -- the 'OsPath' type at zero cost are provided in the @streamly-filepath@
  -- package. Zero-cost interconversion is possible because the 'Path' type uses
  -- an underlying representation which is compatible with the 'OsPath' type.
  --
  -- = Path Creation Quasiquoter
  --
  -- The 'path' quasiquoter is useful in creating valid paths that are checked
  -- during the compile time.
  
  module Streamly.FileSystem.Path
      (
      -- * Setup
      -- | To execute the code examples provided in this module in ghci, please
      -- run the following commands first.
      --
      -- $setup
  
      -- * Type
        Path
      , OsWord
  
      -- * Construction
      , validatePath
      , fromArray
      , fromString
      , fromString_
  
      -- * Statically Verified String Literals
      -- | Quasiquoters.
      , path
  
      -- * Statically Verified Strings
      -- | Template Haskell expression splices.
      , pathE
  
      -- * Elimination
      , toArray
      -- , toChars -- need fromChars as well
      , toString
      -- , asOsCString
  
      -- * Path Info
      , isRooted
      , isUnrooted
  
      -- * Joining
      , unsafeJoin
      , join
      , joinStr
  
      -- * Splitting root
      , splitRoot
  
      -- * Splitting path components
      , splitPath
      -- , splitPath_
  
      -- * Splitting file extension
      , splitExtension
      , takeExtension
      , dropExtension
      -- , addExtension
      -- , replaceExtension
  
      -- * Splitting file and dir
      , splitFile
      , takeFileName
      , takeDirectory
      , takeFileBase
  
      -- * Equality
      , EqCfg
      , ignoreCase
      , ignoreTrailingSeparators
      , allowRelativeEquality
  
      , eqPath
      )
  where
  
  {- Documentation on typed paths. We can add this back into the module level
   documentation when we introduce the typed paths.
  
  -- = Rooted Paths vs Branches
  --
  -- /Flexible typing/: 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 in stricter types.
  
  -- The "Streamly.FileSystem.Path.Seg" module provides explicit types for path
  -- segments, distinguishing rooted paths from branches. Rooted paths use the
  -- @Rooted Path@ type, and branches use the @Branch Path@ type. If you use the
  -- generic 'Path' type, append may fail at run time if you attempt to append
  -- a rooted path to another rooted path. In contrast, using the @Rooted Path@
  -- and @Branch Path@ types guarantees compile-time safety, preventing such errors.
  
  -- = File vs. Directory Paths
  --
  -- Independent of the rooted or branch distinction, you can also make a
  -- type-level distinction between file and directory nodes using the
  -- "Streamly.FileSystem.Path.Node" module. The type @File Path@ represents a
  -- file, whereas @Dir Path@ represents a directory. This distinction provides
  -- safety against appending to file type paths — append operations are not
  -- allowed on paths of type 'File'.
  
  -- = Flexible Typing
  --
  -- You can use the 'Rooted', 'Branch', 'Dir', and 'File' types independently by
  -- importing only the required modules. If you want both types of distinctions,
  -- you can use them together via the "Streamly.FileSystem.Path.SegNode" module.
  -- For example, @Rooted (Dir Path)@ represents a rooted path that is a
  -- directory. You can append other paths only to paths that have a 'Dir' type,
  -- and only a path of type 'Branch' can be appended.
  --
  -- You may choose to use the basic 'Path' type or any combination of the safer
  -- types. You can upgrade or downgrade the safety level by converting between
  -- types using the @adapt@ operation. When converting from a less restrictive
  -- type to a more restrictive one, run-time checks are performed, and the
  -- conversion may fail. However, converting from a more restrictive type to a
  -- less restrictive one is always allowed.
  --
  -- = Extensibility
  --
  -- You can define your own newtype wrappers similar to 'File' or 'Dir' to
  -- provide custom restrictions if you want.
  --
  
  -}
  
  import Streamly.Internal.FileSystem.Path
  
  #include "DocTestFileSystemPath.hs"
  