Arboricx.hs (2956B)
1 module ContentStore.Arboricx 2 ( merkleNodeDomain 3 , putNode 4 , getNode 5 , treeTermDomain 6 , encodeTreeTerm 7 , decodeTreeTerm 8 , putTreeTerm 9 , getTreeTerm 10 , putTree 11 , getTree 12 ) where 13 14 import ContentStore.Filesystem 15 import ContentStore.Object 16 import Research 17 18 import qualified Data.ByteString as BS 19 20 merkleNodeDomain :: Domain 21 merkleNodeDomain = Domain "arboricx.merkle.node.v1" 22 23 treeTermDomain :: Domain 24 treeTermDomain = Domain "arboricx.tree-term.v1" 25 26 putNode :: StorePath -> Node -> IO ObjectHash 27 putNode store node = putObject store merkleNodeDomain (serializeNode node) 28 29 getNode :: StorePath -> ObjectHash -> IO (Maybe Node) 30 getNode store h = fmap deserializeNode <$> getObject store h 31 32 -- | Store a complete normal tree as one content object. Merkle nodes remain 33 -- available for DAG use cases, but module executable exports use this object 34 -- kind to avoid filesystem writes for every subtree of large normal forms. 35 encodeTreeTerm :: T -> BS.ByteString 36 encodeTreeTerm Leaf = BS.pack [0x00] 37 encodeTreeTerm (Stem t) = BS.cons 0x01 (encodeTreeTerm t) 38 encodeTreeTerm (Fork l r) = BS.cons 0x02 (encodeTreeTerm l <> encodeTreeTerm r) 39 40 decodeTreeTerm :: BS.ByteString -> Either String T 41 decodeTreeTerm payload = do 42 (term, rest) <- getTerm payload 43 if BS.null rest 44 then Right term 45 else Left "trailing bytes after tree term" 46 where 47 getTerm bs = case BS.uncons bs of 48 Nothing -> Left "unexpected end of tree term" 49 Just (0x00, rest) -> Right (Leaf, rest) 50 Just (0x01, rest) -> do 51 (child, afterChild) <- getTerm rest 52 Right (Stem child, afterChild) 53 Just (0x02, rest) -> do 54 (left, afterLeft) <- getTerm rest 55 (right, afterRight) <- getTerm afterLeft 56 Right (Fork left right, afterRight) 57 Just (tag, _) -> Left $ "unknown tree term tag: " ++ show tag 58 59 putTreeTerm :: StorePath -> T -> IO ObjectHash 60 putTreeTerm store = putObject store treeTermDomain . encodeTreeTerm 61 62 getTreeTerm :: StorePath -> ObjectHash -> IO (Maybe T) 63 getTreeTerm store h = do 64 mPayload <- getObject store h 65 case mPayload of 66 Nothing -> pure Nothing 67 Just payload -> case decodeTreeTerm payload of 68 Left err -> fail $ "invalid tree term " ++ show h ++ ": " ++ err 69 Right term -> pure (Just term) 70 71 putTree :: StorePath -> T -> IO ObjectHash 72 putTree store = go 73 where 74 go Leaf = putNode store NLeaf 75 go (Stem t) = do 76 child <- go t 77 putNode store (NStem child) 78 go (Fork l r) = do 79 left <- go l 80 right <- go r 81 putNode store (NFork left right) 82 83 getTree :: StorePath -> ObjectHash -> IO (Maybe T) 84 getTree store root = do 85 mNode <- getNode store root 86 case mNode of 87 Nothing -> return Nothing 88 Just node -> case node of 89 NLeaf -> return (Just Leaf) 90 NStem child -> fmap Stem <$> getTree store child 91 NFork left right -> do 92 ml <- getTree store left 93 mr <- getTree store right 94 return $ Fork <$> ml <*> mr