{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Sync.MerkleTree.Types where import System.FilePath import Data.Int import Crypto.Hash import Data.Ord import GHC.Generics import qualified Data.Text as T import Sync.MerkleTree.Trie import qualified Data.Bytes.Serial as SE import qualified Data.Bytes.Put as P -- | Information about a file that we expect to change, when the contents change. data File = File { f_name :: Path , f_size :: FileSize , f_modtime :: FileModTime } deriving (Eq, Ord, Generic) instance SE.Serial File data Entry = FileEntry File | DirectoryEntry Path deriving (Eq, Generic) instance SE.Serial Entry newtype FileSize = FileSize { unFileSize :: Int64 } deriving (Eq, Ord, Generic, Num) instance SE.Serial FileSize data FileModTime = FileModTime { unModTime :: !Int64 } deriving (Eq, Ord, Generic) instance SE.Serial FileModTime -- | Representation for paths below the synchronization root directory data Path = Root | Path T.Text Path deriving (Eq, Ord, Generic) -- | Returns the string representation of a path toFilePath :: FilePath -> Path -> FilePath toFilePath fp p = case p of Root -> fp Path x y -> (toFilePath fp y) (T.unpack x) instance SE.Serial Path -- | Entries are sorted first according to their depth in the path which is useful for directory -- operations instance Ord Entry where compare = comparing withLevel where withLevel entry = (levelOf entry, toEither entry) toEither entry = case entry of DirectoryEntry p -> Right p FileEntry f -> Left f -- | Return the depth of an entries path levelOf :: Entry -> Int levelOf e = case e of DirectoryEntry p -> level p FileEntry f -> level $ f_name f where level Root = 0 level (Path _ p) = 1 + level p instance HasDigest Entry where digest = hash . P.runPutS . SE.serialize