packages feed

hw-xml 0.3.0.0 → 0.4.0.0

raw patch · 31 files changed

+854/−537 lines, 31 filesdep +generic-lensdep +hedgehogdep +hw-hspec-hedgehogdep −QuickCheckdep −conduitdep −hw-conduitdep ~hw-primnew-component:exe:hw-xmlPVP ok

version bump matches the API change (PVP)

Dependencies added: generic-lens, hedgehog, hw-hspec-hedgehog, optparse-applicative, text

Dependencies removed: QuickCheck, conduit, hw-conduit

Dependency ranges changed: hw-prim

API changes (from Hackage documentation)

- HaskellWorks.Data.Xml.Conduit: blankedXmlToBalancedParens :: Monad m => ConduitT ByteString Bool m ()
- HaskellWorks.Data.Xml.Succinct.Cursor.BalancedParens: instance HaskellWorks.Data.Xml.Succinct.Cursor.BlankedXml.FromBlankedXml (HaskellWorks.Data.Xml.Succinct.Cursor.BalancedParens.XmlBalancedParens (HaskellWorks.Data.BalancedParens.Simple.SimpleBalancedParens [GHC.Types.Bool]))
- HaskellWorks.Data.Xml.Succinct.Cursor.BlankedXml: instance HaskellWorks.Data.FromByteString.FromByteString HaskellWorks.Data.Xml.Succinct.Cursor.BlankedXml.BlankedXml
- HaskellWorks.Data.Xml.Succinct.Cursor.Internal: instance Data.String.IsString (HaskellWorks.Data.Xml.Succinct.Cursor.Internal.XmlCursor GHC.Base.String (HaskellWorks.Data.Bits.BitShown.BitShown [GHC.Types.Bool]) (HaskellWorks.Data.BalancedParens.Simple.SimpleBalancedParens [GHC.Types.Bool]))
+ HaskellWorks.Data.Xml.Internal.ToIbBp64: toBalancedParens64 :: BlankedXml -> Vector Word64
+ HaskellWorks.Data.Xml.Internal.ToIbBp64: toBalancedParens64' :: BlankedXml -> [ByteString]
+ HaskellWorks.Data.Xml.Internal.ToIbBp64: toIbBp64 :: BlankedXml -> [(ByteString, ByteString)]
+ HaskellWorks.Data.Xml.Internal.ToIbBp64: toInterestBits64 :: BlankedXml -> Vector Word64
+ HaskellWorks.Data.Xml.Internal.ToIbBp64: toInterestBits64' :: BlankedXml -> [ByteString]
+ HaskellWorks.Data.Xml.Succinct.Cursor.BlankedXml: bsToBlankedXml :: ByteString -> BlankedXml
+ HaskellWorks.Data.Xml.Succinct.Cursor.Create: byteStringAsFastCursor :: ByteString -> FastCursor
+ HaskellWorks.Data.Xml.Succinct.Cursor.Create: byteStringAsSlowCursor :: ByteString -> SlowCursor
+ HaskellWorks.Data.Xml.Succinct.Cursor.InterestBits: genInterestForever :: ByteString -> Maybe (Word8, ByteString)
+ HaskellWorks.Data.Xml.Succinct.Cursor.Load: loadFastCursor :: String -> IO FastCursor
+ HaskellWorks.Data.Xml.Succinct.Cursor.Load: loadSlowCursor :: String -> IO SlowCursor
+ HaskellWorks.Data.Xml.Succinct.Cursor.MMap: mmapFastCursor :: String -> IO FastCursor
+ HaskellWorks.Data.Xml.Succinct.Cursor.MMap: mmapSlowCursor :: String -> IO SlowCursor
+ HaskellWorks.Data.Xml.Succinct.Cursor.MMap: type FastCursor = XmlCursor ByteString CsPoppy1 (RangeMin2 CsPoppy1)
+ HaskellWorks.Data.Xml.Succinct.Cursor.MMap: type SlowCursor = XmlCursor ByteString (BitShown (Vector Word64)) (SimpleBalancedParens (Vector Word64))
+ HaskellWorks.Data.Xml.Succinct.Cursor.Types: type FastCursor = XmlCursor ByteString CsPoppy1 (RangeMin2 CsPoppy1)
+ HaskellWorks.Data.Xml.Succinct.Cursor.Types: type SlowCursor = XmlCursor ByteString (BitShown (Vector Word64)) (SimpleBalancedParens (Vector Word64))
- HaskellWorks.Data.Xml.Conduit: blankedXmlToBalancedParens2 :: Monad m => ConduitT ByteString ByteString m ()
+ HaskellWorks.Data.Xml.Conduit: blankedXmlToBalancedParens2 :: [ByteString] -> [ByteString]
- HaskellWorks.Data.Xml.Conduit: blankedXmlToInterestBits :: Monad m => ConduitT ByteString ByteString m ()
+ HaskellWorks.Data.Xml.Conduit: blankedXmlToInterestBits :: [ByteString] -> [ByteString]
- HaskellWorks.Data.Xml.Conduit: byteStringToBits :: Monad m => ConduitT ByteString Bool m ()
+ HaskellWorks.Data.Xml.Conduit: byteStringToBits :: [ByteString] -> [Bool]
- HaskellWorks.Data.Xml.Conduit: compressWordAsBit :: Monad m => ConduitT ByteString ByteString m ()
+ HaskellWorks.Data.Xml.Conduit: compressWordAsBit :: [ByteString] -> [ByteString]
- HaskellWorks.Data.Xml.Conduit.Blank: blankXml :: MonadThrow m => ConduitT ByteString ByteString m ()
+ HaskellWorks.Data.Xml.Conduit.Blank: blankXml :: [ByteString] -> [ByteString]
- HaskellWorks.Data.Xml.Succinct.Cursor.InterestBits: blankedXmlToInterestBits :: Monad m => ConduitT ByteString ByteString m ()
+ HaskellWorks.Data.Xml.Succinct.Cursor.InterestBits: blankedXmlToInterestBits :: [ByteString] -> [ByteString]
- HaskellWorks.Data.Xml.Value: attributes :: HasValue c_aJEh => Traversal' c_aJEh [(String, String)]
+ HaskellWorks.Data.Xml.Value: attributes :: HasValue c_aHrm => Traversal' c_aHrm [(String, String)]
- HaskellWorks.Data.Xml.Value: cdata :: HasValue c_aJEh => Traversal' c_aJEh String
+ HaskellWorks.Data.Xml.Value: cdata :: HasValue c_aHrm => Traversal' c_aHrm String
- HaskellWorks.Data.Xml.Value: childNodes :: HasValue c_aJEh => Traversal' c_aJEh [Value]
+ HaskellWorks.Data.Xml.Value: childNodes :: HasValue c_aHrm => Traversal' c_aHrm [Value]
- HaskellWorks.Data.Xml.Value: class HasValue c_aJEh
+ HaskellWorks.Data.Xml.Value: class HasValue c_aHrm
- HaskellWorks.Data.Xml.Value: comment :: HasValue c_aJEh => Traversal' c_aJEh String
+ HaskellWorks.Data.Xml.Value: comment :: HasValue c_aHrm => Traversal' c_aHrm String
- HaskellWorks.Data.Xml.Value: errorMessage :: HasValue c_aJEh => Traversal' c_aJEh String
+ HaskellWorks.Data.Xml.Value: errorMessage :: HasValue c_aHrm => Traversal' c_aHrm String
- HaskellWorks.Data.Xml.Value: name :: HasValue c_aJEh => Traversal' c_aJEh String
+ HaskellWorks.Data.Xml.Value: name :: HasValue c_aHrm => Traversal' c_aHrm String
- HaskellWorks.Data.Xml.Value: textValue :: HasValue c_aJEh => Traversal' c_aJEh String
+ HaskellWorks.Data.Xml.Value: textValue :: HasValue c_aHrm => Traversal' c_aHrm String
- HaskellWorks.Data.Xml.Value: value :: HasValue c_aJEh => Lens' c_aJEh Value
+ HaskellWorks.Data.Xml.Value: value :: HasValue c_aHrm => Lens' c_aHrm Value

Files

+ app/App/Commands.hs view
@@ -0,0 +1,15 @@+module App.Commands where++import App.Commands.Count+import App.Commands.Demo+import Data.Semigroup      ((<>))+import Options.Applicative++commands :: Parser (IO ())+commands = commandsGeneral++commandsGeneral :: Parser (IO ())+commandsGeneral = subparser $ mempty+  <>  commandGroup "Commands:"+  <>  cmdCount+  <>  cmdDemo
+ app/App/Commands/Count.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE BangPatterns         #-}+{-# LANGUAGE DataKinds            #-}+{-# LANGUAGE DeriveGeneric        #-}+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE ScopedTypeVariables  #-}+{-# LANGUAGE TypeApplications     #-}+{-# LANGUAGE TypeSynonymInstances #-}++module App.Commands.Count+  ( cmdCount+  ) where++import App.Options+import Control.Lens+import Control.Monad+import Data.Generics.Product.Any+import Data.Semigroup                             ((<>))+import Data.Text                                  (Text)+import HaskellWorks.Data.TreeCursor+import HaskellWorks.Data.Xml.DecodeResult+import HaskellWorks.Data.Xml.RawDecode+import HaskellWorks.Data.Xml.RawValue+import HaskellWorks.Data.Xml.Succinct.Cursor.Load+import HaskellWorks.Data.Xml.Succinct.Cursor.MMap+import HaskellWorks.Data.Xml.Succinct.Index+import HaskellWorks.Data.Xml.Value+import Options.Applicative                        hiding (columns)++import qualified App.Commands.Types as Z+import qualified App.Naive          as NAIVE+import qualified App.XPath.Parser   as XPP+import qualified Data.Text          as T+import qualified System.Exit        as IO+import qualified System.IO          as IO++-- | Document model.  This does not need to be able to completely represent all+-- the data in the XML document.  In fact, having a smaller model may improve+-- Count performance.+data Plant = Plant+  { common :: String+  , price  :: String+  } deriving (Eq, Show)++newtype Catalog = Catalog+  { plants :: [Plant]+  } deriving (Eq, Show)++tags :: Value -> String -> [Value]+tags xml@(XmlElement n _ _) elemName = if n == elemName+  then [xml]+  else []+tags _ _ = []++kids :: Value -> [Value]+kids (XmlElement _ _ cs) = cs+kids _                   = []++countAtPath :: [Text] -> Value -> DecodeResult Int+countAtPath []  _   = return 0+countAtPath [t] xml = return (length (tags xml (T.unpack t)))+countAtPath (t:ts) xml = do+  counts <- forM (tags xml (T.unpack t) >>= kids) $ countAtPath ts+  return (sum counts)++runCount :: Z.CountOptions -> IO ()+runCount opt = do+  let input   = opt ^. the @"input"+  let xpath   = opt ^. the @"xpath"+  let method  = opt ^. the @"method"++  IO.putStrLn $ "XPath: " <> show xpath++  cursorResult <- case method of+    "mmap"   -> Right <$> mmapFastCursor input+    "memory" -> Right <$> loadFastCursor input+    "naive"  -> Right <$> NAIVE.loadFastCursor input+    unknown  -> return (Left ("Unknown method " <> show unknown))++  case cursorResult of+    Right !cursor -> do+      -- Skip the XML declaration to get to the root element cursor+      case nextSibling cursor of+        Just rootCursor -> do+          -- Get the root raw XML value at the root element cursor+          let rootValue = rawValueAt (xmlIndexAt rootCursor)+          -- Show what we have at this cursor+          putStrLn $ "Raw value: " <> take 100 (show rootValue)+          -- Decode the raw XML value+          case countAtPath (xpath ^. the @"path") (rawDecode rootValue) of+            DecodeOk count   -> putStrLn $ "Count: " <> show count+            DecodeFailed msg -> putStrLn $ "Error: " <> show msg+        Nothing -> do+          putStrLn "Could not read XML"+          return ()+    Left msg -> do+      IO.putStrLn $ "Error: " <> msg+      IO.exitFailure++optsCount :: Parser Z.CountOptions+optsCount = Z.CountOptions+  <$> strOption+      (   long "input"+      <>  help "Input file"+      <>  metavar "FILE"+      )+  <*> optionParser XPP.path+      (   long "xpath"+      <>  help "XPath expression"+      <>  metavar "XPATH"+      )+  <*> textOption+      (   long "method"+      <>  help "Read method"+      <>  metavar "METHOD"+      )++cmdCount :: Mod CommandFields (IO ())+cmdCount = command "count"  $ flip info idm $ runCount <$> optsCount
+ app/App/Commands/Demo.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE BangPatterns         #-}+{-# LANGUAGE DataKinds            #-}+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE ScopedTypeVariables  #-}+{-# LANGUAGE TypeApplications     #-}+{-# LANGUAGE TypeSynonymInstances #-}++module App.Commands.Demo+  ( cmdDemo+  ) where++import Data.Foldable+import Data.Maybe+import Data.Semigroup                             ((<>))+import HaskellWorks.Data.TreeCursor+import HaskellWorks.Data.Xml.Decode+import HaskellWorks.Data.Xml.DecodeResult+import HaskellWorks.Data.Xml.RawDecode+import HaskellWorks.Data.Xml.RawValue+import HaskellWorks.Data.Xml.Succinct.Cursor.Load+import HaskellWorks.Data.Xml.Succinct.Index+import HaskellWorks.Data.Xml.Value+import Options.Applicative                        hiding (columns)++import qualified App.Commands.Types as Z++-- | Parse the text of an XML node.+class ParseText a where+  parseText :: Value -> DecodeResult a++instance ParseText String where+  parseText (XmlText text)      = DecodeOk text+  parseText (XmlCData text)     = DecodeOk text+  parseText (XmlElement _ _ cs) = DecodeOk $ concat $ concat $ toList . parseText <$> cs+  parseText _                   = DecodeOk ""++-- | Convert a decode result to a maybe+decodeResultToMaybe :: DecodeResult a -> Maybe a+decodeResultToMaybe (DecodeOk a) = Just a+decodeResultToMaybe _            = Nothing++-- | Document model.  This does not need to be able to completely represent all+-- the data in the XML document.  In fact, having a smaller model may improve+-- query performance.+data Plant = Plant+  { common :: String+  , price  :: String+  } deriving (Eq, Show)++newtype Catalog = Catalog+  { plants :: [Plant]+  } deriving (Eq, Show)++-- | Decode plant element+decodePlant :: Value -> DecodeResult Plant+decodePlant xml = do+  aCommon <- xml /> "common"  >>= parseText+  aPrice  <- xml /> "price"   >>= parseText+  return $ Plant aCommon aPrice++-- | Decode catalog element+decodeCatalog :: Value -> DecodeResult Catalog+decodeCatalog xml = do+  aPlantXmls <- xml />> "plant"+  let aPlants = catMaybes (decodeResultToMaybe . decodePlant <$> aPlantXmls)+  return $ Catalog aPlants++runDemo :: Z.DemoOptions -> IO ()+runDemo _ = do+  -- Read XML into memory as a query-optimised cursor+  !cursor <- loadFastCursor "data/catalog.xml"+  -- Skip the XML declaration to get to the root element cursor+  case nextSibling cursor of+    Just rootCursor -> do+      -- Get the root raw XML value at the root element cursor+      let rootValue = rawValueAt (xmlIndexAt rootCursor)+      -- Show what we have at this cursor+      putStrLn $ "Raw value: " <> take 100 (show rootValue)+      -- Decode the raw XML value+      case decodeCatalog (rawDecode rootValue) of+        DecodeOk catalog -> putStrLn $ "Catalog: " <> show catalog+        DecodeFailed msg -> putStrLn $ "Error: " <> show msg+    Nothing -> do+      putStrLn "Could not read XML"+      return ()++optsDemo :: Parser Z.DemoOptions+optsDemo = pure Z.DemoOptions++cmdDemo :: Mod CommandFields (IO ())+cmdDemo = command "demo"  $ flip info idm $ runDemo <$> optsDemo
+ app/App/Commands/Types.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE DeriveGeneric         #-}+{-# LANGUAGE DuplicateRecordFields #-}++module App.Commands.Types+  ( CountOptions(..)+  , DemoOptions(..)+  ) where++import App.XPath.Types (XPath)+import Data.Text       (Text)+import GHC.Generics++data DemoOptions = DemoOptions deriving (Eq, Show, Generic)++data CountOptions = CountOptions+  { input  :: FilePath+  , xpath  :: XPath+  , method :: Text+  } deriving (Eq, Show, Generic)
+ app/App/Naive.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE BangPatterns         #-}+{-# LANGUAGE DataKinds            #-}+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE ScopedTypeVariables  #-}+{-# LANGUAGE TypeApplications     #-}+{-# LANGUAGE TypeSynonymInstances #-}++module App.Naive+  ( loadSlowCursor+  , loadFastCursor+  ) where++import HaskellWorks.Data.BalancedParens.RangeMin2+import HaskellWorks.Data.BalancedParens.Simple+import HaskellWorks.Data.Bits.BitShown+import HaskellWorks.Data.FromByteString+import HaskellWorks.Data.RankSelect.CsPoppy1+import HaskellWorks.Data.Xml.Succinct.Cursor+import HaskellWorks.Data.Xml.Succinct.Cursor.MMap++import qualified Data.ByteString as BS++-- | Load an XML file into memory and return a raw cursor initialised to the+-- start of the XML document.+loadSlowCursor :: String -> IO SlowCursor+loadSlowCursor path = do+  !bs <- BS.readFile path+  let !cursor = fromByteString bs :: SlowCursor+  return cursor++-- | Load an XML file into memory and return a query-optimised cursor initialised+-- to the start of the XML document.+loadFastCursor :: String -> IO FastCursor+loadFastCursor filename = do+  -- Load the XML file into memory as a raw cursor.+  -- The raw XML data is `text`, and `ib` and `bp` are the indexes.+  -- `ib` and `bp` can be persisted to an index file for later use to avoid+  -- re-parsing the file.+  XmlCursor !text (BitShown !ib) (SimpleBalancedParens !bp) _ <- loadSlowCursor filename+  let !bpCsPoppy = makeCsPoppy bp+  let !rangeMinMax = mkRangeMin2 bpCsPoppy+  let !ibCsPoppy = makeCsPoppy ib+  return $ XmlCursor text ibCsPoppy rangeMinMax 1
+ app/App/Options.hs view
@@ -0,0 +1,16 @@+module App.Options+  ( optionParser+  , textOption+  ) where++import Data.Text (Text)++import qualified Data.Attoparsec.Text as AT+import qualified Data.Text            as T+import qualified Options.Applicative  as OA++optionParser :: AT.Parser a -> OA.Mod OA.OptionFields a -> OA.Parser a+optionParser p = OA.option (OA.eitherReader (AT.parseOnly p . T.pack))++textOption :: OA.Mod OA.OptionFields String -> OA.Parser Text+textOption = fmap T.pack . OA.strOption
+ app/App/Show.hs view
@@ -0,0 +1,10 @@+module App.Show+  ( tshow+  ) where++import Data.Text (Text)++import qualified Data.Text as T++tshow :: Show a => a -> Text+tshow = T.pack . show
+ app/App/XPath/Parser.hs view
@@ -0,0 +1,19 @@+module App.XPath.Parser+  ( path+  ) where++import Control.Applicative+import Data.Attoparsec.Text+import Data.Text            (Text)++import qualified App.XPath.Types as XP+import qualified Data.Text       as T++tag :: Parser Text+tag = T.cons <$> letter <*> tagTail++tagTail :: Parser Text+tagTail = T.pack <$> many (letter <|> digit <|> char '-' <|> char '_')++path :: Parser XP.XPath+path = XP.XPath <$> sepBy1 tag (char '/')
+ app/App/XPath/Types.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE DeriveGeneric #-}++module App.XPath.Types where++import Data.Text    (Text)+import GHC.Generics++newtype XPath = XPath+  { path :: [Text]+  } deriving (Eq, Show, Generic)
app/Main.hs view
@@ -1,112 +1,11 @@-{-# LANGUAGE BangPatterns         #-}-{-# LANGUAGE FlexibleInstances    #-}-{-# LANGUAGE ScopedTypeVariables  #-}-{-# LANGUAGE TypeSynonymInstances #-}- module Main where -import Data.Foldable-import Data.Maybe-import Data.Semigroup                             ((<>))-import Data.Word-import HaskellWorks.Data.BalancedParens.RangeMin2-import HaskellWorks.Data.BalancedParens.Simple-import HaskellWorks.Data.Bits.BitShown-import HaskellWorks.Data.FromByteString-import HaskellWorks.Data.RankSelect.CsPoppy1-import HaskellWorks.Data.TreeCursor-import HaskellWorks.Data.Xml.Decode-import HaskellWorks.Data.Xml.DecodeResult-import HaskellWorks.Data.Xml.RawDecode-import HaskellWorks.Data.Xml.RawValue-import HaskellWorks.Data.Xml.Succinct.Cursor-import HaskellWorks.Data.Xml.Succinct.Index-import HaskellWorks.Data.Xml.Value--import qualified Data.ByteString      as BS-import qualified Data.Vector.Storable as DVS--type RawCursor = XmlCursor BS.ByteString (BitShown (DVS.Vector Word64)) (SimpleBalancedParens (DVS.Vector Word64))-type FastCursor = XmlCursor BS.ByteString CsPoppy1 (RangeMin2 CsPoppy1)---- | Read an XML file into memory and return a raw cursor initialised to the--- start of the XML document.-readRawCursor :: String -> IO RawCursor-readRawCursor path = do-  !bs <- BS.readFile path-  let !cursor = fromByteString bs :: RawCursor-  return cursor---- | Read an XML file into memory and return a query-optimised cursor initialised--- to the start of the XML document.-readFastCursor :: String -> IO FastCursor-readFastCursor filename = do-  -- Load the XML file into memory as a raw cursor.-  -- The raw XML data is `text`, and `ib` and `bp` are the indexes.-  -- `ib` and `bp` can be persisted to an index file for later use to avoid-  -- re-parsing the file.-  XmlCursor !text (BitShown !ib) (SimpleBalancedParens !bp) _ <- readRawCursor filename-  let !bpCsPoppy = makeCsPoppy bp-  let !rangeMinMax = mkRangeMin2 bpCsPoppy-  let !ibCsPoppy = makeCsPoppy ib-  return $ XmlCursor text ibCsPoppy rangeMinMax 1---- | Parse the text of an XML node.-class ParseText a where-  parseText :: Value -> DecodeResult a--instance ParseText String where-  parseText (XmlText text)      = DecodeOk text-  parseText (XmlCData text)     = DecodeOk text-  parseText (XmlElement _ _ cs) = DecodeOk $ concat $ concat $ toList . parseText <$> cs-  parseText _                   = DecodeOk ""---- | Convert a decode result to a maybe-decodeResultToMaybe :: DecodeResult a -> Maybe a-decodeResultToMaybe (DecodeOk a) = Just a-decodeResultToMaybe _            = Nothing---- | Document model.  This does not need to be able to completely represent all--- the data in the XML document.  In fact, having a smaller model may improve--- query performance.-data Plant = Plant-  { common :: String-  , price  :: String-  } deriving (Eq, Show)--newtype Catalog = Catalog-  { plants :: [Plant]-  } deriving (Eq, Show)---- | Decode plant element-decodePlant :: Value -> DecodeResult Plant-decodePlant xml = do-  aCommon <- xml /> "common"  >>= parseText-  aPrice  <- xml /> "price"   >>= parseText-  return $ Plant aCommon aPrice---- | Decode catalog element-decodeCatalog :: Value -> DecodeResult Catalog-decodeCatalog xml = do-  aPlantXmls <- xml />> "plant"-  let aPlants = catMaybes (decodeResultToMaybe . decodePlant <$> aPlantXmls)-  return $ Catalog aPlants+import App.Commands+import Control.Monad+import Data.Semigroup      ((<>))+import Options.Applicative  main :: IO ()-main = do-  -- Read XML into memory as a query-optimised cursor-  !cursor <- readFastCursor "data/catalog.xml"-  -- Skip the XML declaration to get to the root element cursor-  case nextSibling cursor of-    Just rootCursor -> do-      -- Get the root raw XML value at the root element cursor-      let rootValue = rawValueAt (xmlIndexAt rootCursor)-      -- Show what we have at this cursor-      putStrLn $ "Raw value: " <> take 100 (show rootValue)-      -- Decode the raw XML value-      case decodeCatalog (rawDecode rootValue) of-        DecodeOk catalog -> putStrLn $ "Catalog: " <> show catalog-        DecodeFailed msg -> putStrLn $ "Error: " <> show msg-    Nothing -> do-      putStrLn "Could not read XML"-      return ()+main = join $ customExecParser+  (prefs $ showHelpOnEmpty <> showHelpOnError)+  (info (commands <**> helper) idm)
bench/Main.hs view
@@ -3,14 +3,11 @@  module Main where -import Control.Monad.Trans.Resource            (MonadThrow) import Criterion.Main-import Data.Conduit import Data.Word import Foreign import HaskellWorks.Data.BalancedParens.Simple import HaskellWorks.Data.Bits.BitShown-import HaskellWorks.Data.Conduit.List import HaskellWorks.Data.FromByteString import HaskellWorks.Data.Xml.Conduit import HaskellWorks.Data.Xml.Conduit.Blank@@ -30,11 +27,11 @@ loadXml :: BS.ByteString -> XmlCursor BS.ByteString (BitShown (DVS.Vector Word64)) (SimpleBalancedParens (DVS.Vector Word64)) loadXml bs = fromByteString bs :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word64)) (SimpleBalancedParens (DVS.Vector Word64)) -xmlToInterestBits3 :: MonadThrow m => Conduit BS.ByteString m BS.ByteString-xmlToInterestBits3 = blankXml .| blankedXmlToInterestBits+xmlToInterestBits3 :: [BS.ByteString] -> [BS.ByteString]+xmlToInterestBits3 = blankedXmlToInterestBits . blankXml -runCon :: Conduit i [] BS.ByteString -> i -> BS.ByteString-runCon con bs = BS.concat $ runListConduit con [bs]+runCon :: ([i] -> [BS.ByteString]) -> i -> BS.ByteString+runCon con bs = BS.concat $ con [bs]  benchRankXmlCatalogConduits :: [Benchmark] benchRankXmlCatalogConduits =
hw-xml.cabal view
@@ -1,7 +1,7 @@ cabal-version:      2.2  name:               hw-xml-version:            0.3.0.0+version:            0.4.0.0 synopsis:           Conduits for tokenizing streams. description:        Conduits for tokenizing streams. Please see README.md category:           Data, XML, Succinct Data Structures, Data Structures@@ -25,31 +25,31 @@  common base                       { build-depends: base                       >= 4.7        && < 5      } -common QuickCheck                 { build-depends: QuickCheck                 >= 2.13.1     && < 3      } common ansi-wl-pprint             { build-depends: ansi-wl-pprint             >= 0.6.9      && < 0.7    } common array                      { build-depends: array                      >= 0.5.2.0    && < 0.6    } common attoparsec                 { build-depends: attoparsec                 >= 0.13.2.2   && < 0.14   } common bytestring                 { build-depends: bytestring                 >= 0.10.8.2   && < 0.11   } common cereal                     { build-depends: cereal                     >= 0.5.8.1    && < 0.6    }-common conduit                    { build-depends: conduit                    >= 1.3.1.1    && < 1.4    } common containers                 { build-depends: containers                 >= 0.6.2.1    && < 0.7    } common criterion                  { build-depends: criterion                  >= 1.5.5.0    && < 1.6    } common deepseq                    { build-depends: deepseq                    >= 1.4.3.0    && < 1.5    }+common generic-lens               { build-depends: generic-lens               >= 1.1.0.0    && < 1.3    } common ghc-prim                   { build-depends: ghc-prim                   >= 0.5        && < 0.6    } common hedgehog                   { build-depends: hedgehog                   >= 1.0        && < 1.1    } common hspec                      { build-depends: hspec                      >= 2.5        && < 3.0    } common hw-balancedparens          { build-depends: hw-balancedparens          >= 0.3.0.0    && < 0.4    } common hw-bits                    { build-depends: hw-bits                    >= 0.7.0.6    && < 0.8    }-common hw-conduit                 { build-depends: hw-conduit                 >= 0.2.0.5    && < 0.3    } common hw-hspec-hedgehog          { build-depends: hw-hspec-hedgehog          >= 0.1        && < 0.2    } common hw-parser                  { build-depends: hw-parser                  >= 0.1.0.1    && < 0.2    }-common hw-prim                    { build-depends: hw-prim                    >= 0.6.2.28   && < 0.7    }+common hw-prim                    { build-depends: hw-prim                    >= 0.6.2.33   && < 0.7    } common hw-rankselect              { build-depends: hw-rankselect              >= 0.13.2.0   && < 0.14   } common hw-rankselect-base         { build-depends: hw-rankselect-base         >= 0.3.2.1    && < 0.4    } common lens                       { build-depends: lens                       >= 4.17.1     && < 5.0    } common mmap                       { build-depends: mmap                       >= 0.5.9      && < 0.6    } common mtl                        { build-depends: mtl                        >= 2.2.2      && < 3      }+common optparse-applicative       { build-depends: optparse-applicative       >= 0.15.1.0   && < 0.16   } common resourcet                  { build-depends: resourcet                  >= 1.2.2      && < 1.3    }+common text                       { build-depends: text                       >= 1.2.4.0    && < 1.3    } common transformers               { build-depends: transformers               >= 0.5.5.0    && < 0.6    } common vector                     { build-depends: vector                     >= 0.12.0.3   && < 0.13   } common word8                      { build-depends: word8                      >= 0.1.3      && < 0.2    }@@ -65,18 +65,17 @@           , base           , bytestring           , cereal-          , conduit           , containers           , deepseq           , ghc-prim           , hw-balancedparens           , hw-bits-          , hw-conduit           , hw-parser           , hw-prim           , hw-rankselect           , hw-rankselect-base           , lens+          , mmap           , mtl           , resourcet           , transformers@@ -94,13 +93,18 @@     HaskellWorks.Data.Xml.DecodeResult     HaskellWorks.Data.Xml.Grammar     HaskellWorks.Data.Xml.Index+    HaskellWorks.Data.Xml.Internal.ToIbBp64     HaskellWorks.Data.Xml.Lens     HaskellWorks.Data.Xml.Succinct     HaskellWorks.Data.Xml.Succinct.Cursor     HaskellWorks.Data.Xml.Succinct.Cursor.BalancedParens     HaskellWorks.Data.Xml.Succinct.Cursor.BlankedXml+    HaskellWorks.Data.Xml.Succinct.Cursor.Create     HaskellWorks.Data.Xml.Succinct.Cursor.InterestBits     HaskellWorks.Data.Xml.Succinct.Cursor.Internal+    HaskellWorks.Data.Xml.Succinct.Cursor.Load+    HaskellWorks.Data.Xml.Succinct.Cursor.Types+    HaskellWorks.Data.Xml.Succinct.Cursor.MMap     HaskellWorks.Data.Xml.Succinct.Cursor.Token     HaskellWorks.Data.Xml.Succinct.Index     HaskellWorks.Data.Xml.RawDecode@@ -115,32 +119,48 @@   hs-source-dirs:     src   ghc-options:        -Wall -O2 -msse4.2 -executable hw-xml-example+executable hw-xml   import:   base, config+          , attoparsec           , bytestring+          , generic-lens           , hw-balancedparens           , hw-bits           , hw-prim           , hw-rankselect+          , lens+          , mmap+          , mtl+          , optparse-applicative+          , resourcet+          , text           , vector-  main-is:            Main.hs-  other-modules:      Paths_hw_xml-  autogen-modules:    Paths_hw_xml-  build-depends:      hw-xml-  hs-source-dirs:     app-  ghc-options:        -threaded -rtsopts -with-rtsopts=-N -O2 -Wall -msse4.2+  main-is:              Main.hs+  other-modules:        Paths_hw_xml+                        App.Commands+                        App.Commands.Count+                        App.Commands.Demo+                        App.Commands.Types+                        App.Options+                        App.XPath.Parser+                        App.XPath.Types+                        App.Show+                        App.Naive+  autogen-modules:      Paths_hw_xml+  build-depends:        hw-xml+  hs-source-dirs:       app+  ghc-options:          -threaded -rtsopts -with-rtsopts=-N -O2 -Wall -msse4.2  test-suite hw-xml-test   import:   base, config-          , QuickCheck           , attoparsec           , base           , bytestring-          , conduit+          , hedgehog           , hspec           , hw-balancedparens           , hw-bits-          , hw-conduit+          , hw-hspec-hedgehog           , hw-prim           , hw-rankselect           , hw-rankselect-base@@ -166,11 +186,9 @@ benchmark bench   import:   base, config           , bytestring-          , conduit           , criterion           , hw-balancedparens           , hw-bits-          , hw-conduit           , hw-prim           , mmap           , resourcet
src/HaskellWorks/Data/Xml/Conduit.hs view
@@ -4,17 +4,14 @@ module HaskellWorks.Data.Xml.Conduit   ( blankedXmlToInterestBits   , byteStringToBits-  , blankedXmlToBalancedParens   , blankedXmlToBalancedParens2   , compressWordAsBit   , interestingWord8s   , isInterestingWord8   ) where -import Control.Monad import Data.Array.Unboxed             as A import Data.ByteString                as BS-import Data.Conduit import Data.Word import Data.Word8 import HaskellWorks.Data.Bits.BitWise@@ -39,25 +36,22 @@ isInterestingWord8 b = interestingWord8s ! b {-# INLINABLE isInterestingWord8 #-} -blankedXmlToInterestBits :: Monad m => ConduitT BS.ByteString BS.ByteString m ()+blankedXmlToInterestBits :: [BS.ByteString] -> [BS.ByteString] blankedXmlToInterestBits = blankedXmlToInterestBits' "" -blankedXmlToInterestBits' :: Monad m => BS.ByteString -> ConduitT BS.ByteString BS.ByteString m ()-blankedXmlToInterestBits' rs = do-  mbs <- await-  case mbs of-    Just bs -> do-      let cs = if BS.length rs /= 0 then BS.concat [rs, bs] else bs-      let lencs = BS.length cs-      let q = lencs `quot` 8-      let (ds, es) = BS.splitAt (q * 8) cs-      let (fs, _) = BS.unfoldrN q gen ds-      yield fs-      blankedXmlToInterestBits' es-    Nothing -> do-      let lenrs = BS.length rs-      let q = lenrs + 7 `quot` 8-      yield (fst (BS.unfoldrN q gen rs))+blankedXmlToInterestBits' :: BS.ByteString -> [BS.ByteString] -> [BS.ByteString]+blankedXmlToInterestBits' rs is = case is of+  (bs:bss) -> do+    let cs = if BS.length rs /= 0 then BS.concat [rs, bs] else bs+    let lencs = BS.length cs+    let q = lencs `quot` 8+    let (ds, es) = BS.splitAt (q * 8) cs+    let (fs, _) = BS.unfoldrN q gen ds+    fs:blankedXmlToInterestBits' es bss+  [] -> do+    let lenrs = BS.length rs+    let q = lenrs + 7 `quot` 8+    [fst (BS.unfoldrN q gen rs)]   where gen :: ByteString -> Maybe (Word8, ByteString)         gen as = if BS.length as == 0           then Nothing@@ -65,51 +59,24 @@                     , BS.drop 8 as                     ) -blankedXmlToBalancedParens :: Monad m => ConduitT BS.ByteString Bool m ()-blankedXmlToBalancedParens = do-  mbs <- await-  case mbs of-    Just bs -> blankedXmlToBalancedParens' bs-    Nothing -> return ()--blankedXmlToBalancedParens' :: Monad m => BS.ByteString -> ConduitT BS.ByteString Bool m ()-blankedXmlToBalancedParens' bs = case BS.uncons bs of-  Just (c, cs) -> do-    case c of-      d | d == _less         -> yield True-      d | d == _greater      -> yield False-      d | d == _bracketleft  -> yield True-      d | d == _bracketright -> yield False-      d | d == _parenleft    -> yield True-      d | d == _parenright   -> yield False-      d | d == _a            -> yield True >> yield False-      d | d == _v            -> yield True >> yield False-      d | d == _t            -> yield True >> yield False-      _                      -> return ()-    blankedXmlToBalancedParens' cs-  Nothing -> return ()- repartitionMod8 :: BS.ByteString -> BS.ByteString -> (BS.ByteString, BS.ByteString) repartitionMod8 aBS bBS = (BS.take cLen abBS, BS.drop cLen abBS)   where abBS = BS.concat [aBS, bBS]         abLen = BS.length abBS         cLen = (abLen `div` 8) * 8 -compressWordAsBit :: Monad m => ConduitT BS.ByteString BS.ByteString m ()+compressWordAsBit :: [BS.ByteString] -> [BS.ByteString] compressWordAsBit = compressWordAsBit' BS.empty -compressWordAsBit' :: Monad m => BS.ByteString -> ConduitT BS.ByteString BS.ByteString m ()-compressWordAsBit' aBS = do-  mbBS <- await-  case mbBS of-    Just bBS -> do-      let (cBS, dBS) = repartitionMod8 aBS bBS-      let (cs, _) = BS.unfoldrN (BS.length cBS + 7 `div` 8) gen cBS-      yield cs-      compressWordAsBit' dBS-    Nothing -> do-      let (cs, _) = BS.unfoldrN (BS.length aBS + 7 `div` 8) gen aBS-      yield cs+compressWordAsBit' :: BS.ByteString -> [BS.ByteString] -> [BS.ByteString]+compressWordAsBit' aBS iBS = case iBS of+  (bBS:bBSs) -> do+    let (cBS, dBS) = repartitionMod8 aBS bBS+    let (cs, _) = BS.unfoldrN (BS.length cBS + 7 `div` 8) gen cBS+    cs:compressWordAsBit' dBS bBSs+  [] -> do+    let (cs, _) = BS.unfoldrN (BS.length aBS + 7 `div` 8) gen aBS+    [cs]   where gen :: ByteString -> Maybe (Word8, ByteString)         gen xs = if BS.length xs == 0           then Nothing@@ -117,15 +84,12 @@                     , BS.drop 8 xs                     ) -blankedXmlToBalancedParens2 :: Monad m => ConduitT BS.ByteString BS.ByteString m ()-blankedXmlToBalancedParens2 = do-  mbs <- await-  case mbs of-    Just bs -> do-      let (cs, _) = BS.unfoldrN (BS.length bs * 2) gen (Nothing, bs)-      yield cs-      blankedXmlToBalancedParens2-    Nothing -> return ()+blankedXmlToBalancedParens2 :: [BS.ByteString] -> [BS.ByteString]+blankedXmlToBalancedParens2 is = case is of+  (bs:bss) -> do+    let (cs, _) = BS.unfoldrN (BS.length bs * 2) gen (Nothing, bs)+    cs:blankedXmlToBalancedParens2 bss+  [] -> []   where gen :: (Maybe Bool, ByteString) -> Maybe (Word8, (Maybe Bool, ByteString))         gen (Just True  , bs) = Just (0xFF, (Nothing, bs))         gen (Just False , bs) = Just (0x00, (Nothing, bs))@@ -152,23 +116,22 @@     d | d == _v            -> MiniTF     _                      -> MiniN -yieldBitsOfWord8 :: Monad m => Word8 -> ConduitT BS.ByteString Bool m ()-yieldBitsOfWord8 w = do-  yield ((w .&. BITS.bit 0) /= 0)-  yield ((w .&. BITS.bit 1) /= 0)-  yield ((w .&. BITS.bit 2) /= 0)-  yield ((w .&. BITS.bit 3) /= 0)-  yield ((w .&. BITS.bit 4) /= 0)-  yield ((w .&. BITS.bit 5) /= 0)-  yield ((w .&. BITS.bit 6) /= 0)-  yield ((w .&. BITS.bit 7) /= 0)+yieldBitsOfWord8 :: Word8 -> [Bool]+yieldBitsOfWord8 w =+  [ (w .&. BITS.bit 0) /= 0+  , (w .&. BITS.bit 1) /= 0+  , (w .&. BITS.bit 2) /= 0+  , (w .&. BITS.bit 3) /= 0+  , (w .&. BITS.bit 4) /= 0+  , (w .&. BITS.bit 5) /= 0+  , (w .&. BITS.bit 6) /= 0+  , (w .&. BITS.bit 7) /= 0+  ] -yieldBitsofWord8s :: Monad m => [Word8] -> ConduitT BS.ByteString Bool m ()-yieldBitsofWord8s = P.foldr ((>>) . yieldBitsOfWord8) (return ())+yieldBitsofWord8s :: [Word8] -> [Bool]+yieldBitsofWord8s = P.foldr ((++) . yieldBitsOfWord8) [] -byteStringToBits :: Monad m => ConduitT BS.ByteString Bool m ()-byteStringToBits = do-  mbs <- await-  case mbs of-    Just bs -> yieldBitsofWord8s (BS.unpack bs) >> byteStringToBits-    Nothing -> return ()+byteStringToBits :: [BS.ByteString] -> [Bool]+byteStringToBits is = case is of+  (bs:bss) -> yieldBitsofWord8s (BS.unpack bs) ++ byteStringToBits bss+  []       -> []
src/HaskellWorks/Data/Xml/Conduit/Blank.hs view
@@ -7,10 +7,7 @@   , BlankData(..)   ) where -import Control.Monad-import Control.Monad.Trans.Resource        (MonadThrow) import Data.ByteString                     as BS-import Data.Conduit import Data.Monoid                         ((<>)) import Data.Word import Data.Word8@@ -41,39 +38,36 @@   , blankC     :: !ByteString   } -blankXml :: MonadThrow m => ConduitT BS.ByteString BS.ByteString m ()+blankXml :: [BS.ByteString] -> [BS.ByteString] blankXml = blankXmlPlan1 BS.empty InXml -blankXmlPlan1 :: MonadThrow m => BS.ByteString -> BlankState -> ConduitT BS.ByteString BS.ByteString m ()-blankXmlPlan1 as lastState = do-  mbs <- await-  case mbs of-    Just bs -> do-      let cs = as <> bs-      case BS.uncons cs of-        Just (d, ds) -> case BS.uncons ds of-          Just (e, es) -> blankXmlRun False d e es lastState-          Nothing      -> blankXmlPlan1 cs lastState-        Nothing -> blankXmlPlan1 cs lastState-    Nothing -> yield $ BS.map (const _space) as+blankXmlPlan1 :: BS.ByteString -> BlankState -> [BS.ByteString] -> [BS.ByteString]+blankXmlPlan1 as lastState is = case is of+  (bs:bss) -> do+    let cs = as <> bs+    case BS.uncons cs of+      Just (d, ds) -> case BS.uncons ds of+        Just (e, es) -> blankXmlRun False d e es lastState bss+        Nothing      -> blankXmlPlan1 cs lastState bss+      Nothing -> blankXmlPlan1 cs lastState bss+  [] -> [BS.map (const _space) as] -blankXmlPlan2 :: MonadThrow m => Word8 -> Word8 -> BlankState -> ConduitT BS.ByteString BS.ByteString m ()-blankXmlPlan2 a b lastState = do-  mcs <- await-  case mcs of-    Just cs -> blankXmlRun False a b cs lastState-    Nothing -> blankXmlRun True a b (BS.pack [_space, _space]) lastState+blankXmlPlan2 :: Word8 -> Word8 -> BlankState -> [BS.ByteString] -> [BS.ByteString]+blankXmlPlan2 a b lastState is = case is of+  (cs:css) -> blankXmlRun False a b cs lastState css+  []       -> blankXmlRun True a b (BS.pack [_space, _space]) lastState [] -blankXmlRun :: MonadThrow m => Bool -> Word8 -> Word8 -> BS.ByteString -> BlankState -> ConduitT BS.ByteString BS.ByteString m ()-blankXmlRun done a b cs lastState = do+blankXmlRun :: Bool -> Word8 -> Word8 -> BS.ByteString -> BlankState -> [BS.ByteString] -> [BS.ByteString]+blankXmlRun done a b cs lastState is = do   let (!ds, Just (BlankData !nextState _ _ _)) = unfoldrN (BS.length cs) blankByteString (BlankData lastState a b cs)-  yield ds   let (yy, zz) = case BS.unsnoc cs of         Just (ys, z) -> case BS.unsnoc ys of           Just (_, y) -> (y, z)           Nothing     -> (b, z)         Nothing -> (a, b)-  unless done (blankXmlPlan2 yy zz nextState)+  if done+    then [ds]+    else ds:blankXmlPlan2 yy zz nextState is  mkNext :: Word8 -> BlankState -> Word8 -> BS.ByteString -> Maybe (Word8, BlankData) mkNext w s a bs = case BS.uncons bs of
src/HaskellWorks/Data/Xml/Decode.hs view
@@ -4,7 +4,7 @@ import Control.Lens import Control.Monad import Data.Foldable-import Data.Monoid                       ((<>))+import Data.Monoid                        ((<>)) import HaskellWorks.Data.Xml.DecodeError import HaskellWorks.Data.Xml.DecodeResult import HaskellWorks.Data.Xml.Value@@ -21,8 +21,8 @@  (@>) :: Value -> String -> DecodeResult String (@>) (XmlElement _ as _) n = case find (\v -> fst v == n) as of-  Just (_, text)  -> DecodeOk text-  Nothing         -> failDecode $ "No such attribute " <> show n+  Just (_, text) -> DecodeOk text+  Nothing        -> failDecode $ "No such attribute " <> show n (@>) _ n = failDecode $ "Not an element whilst looking up attribute " <> show n  (/>) :: Value -> String -> DecodeResult Value@@ -38,7 +38,7 @@  (~>) :: Value -> String -> DecodeResult Value (~>) e@(XmlElement n' _ _)  n | n' == n = DecodeOk e-(~>) _                      n           = failDecode $ "Expecting parent of element " <> show n+(~>) _                      n = failDecode $ "Expecting parent of element " <> show n  (/>>) :: Value -> String -> DecodeResult [Value] (/>>) v n = v ^. childNodes <&> (~> n) <&> toList & join & pure
+ src/HaskellWorks/Data/Xml/Internal/ToIbBp64.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE InstanceSigs          #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module HaskellWorks.Data.Xml.Internal.ToIbBp64+  ( toBalancedParens64+  , toInterestBits64+  , toBalancedParens64'+  , toInterestBits64'+  , toIbBp64+  ) where++import Control.Applicative+import Data.Word+import HaskellWorks.Data.Xml.Conduit+import HaskellWorks.Data.Xml.Succinct.Cursor.BlankedXml   (BlankedXml (..))+import HaskellWorks.Data.Xml.Succinct.Cursor.InterestBits (blankedXmlToInterestBits, genInterestForever)++import qualified Data.ByteString      as BS+import qualified Data.Vector.Storable as DVS++genBitWordsForever :: BS.ByteString -> Maybe (Word8, BS.ByteString)+genBitWordsForever bs = BS.uncons bs <|> Just (0, bs)+{-# INLINABLE genBitWordsForever #-}++toBalancedParens64 :: BlankedXml -> DVS.Vector Word64+toBalancedParens64 (BlankedXml bj) = DVS.unsafeCast (DVS.unfoldrN newLen genBitWordsForever interestBS)+  where interestBS    = BS.concat (compressWordAsBit (blankedXmlToBalancedParens2 bj))+        newLen        = (BS.length interestBS + 7) `div` 8 * 8++toBalancedParens64' :: BlankedXml -> [BS.ByteString]+toBalancedParens64' (BlankedXml bj) = compressWordAsBit (blankedXmlToBalancedParens2 bj)++toInterestBits64 :: BlankedXml -> DVS.Vector Word64+toInterestBits64 (BlankedXml bj) = DVS.unsafeCast (DVS.unfoldrN newLen genInterestForever interestBS)+    where interestBS    = BS.concat (blankedXmlToInterestBits bj)+          newLen        = (BS.length interestBS + 7) `div` 8 * 8++toInterestBits64' :: BlankedXml -> [BS.ByteString]+toInterestBits64' (BlankedXml bj) = blankedXmlToInterestBits bj++toIbBp64 :: BlankedXml -> [(BS.ByteString, BS.ByteString)]+toIbBp64 bj = zip (toInterestBits64' bj) (toBalancedParens64' bj)
src/HaskellWorks/Data/Xml/Succinct/Cursor/BalancedParens.hs view
@@ -9,10 +9,8 @@   ) where  import Control.Applicative-import Data.Conduit import Data.Word import HaskellWorks.Data.BalancedParens                 as BP-import HaskellWorks.Data.Conduit.List import HaskellWorks.Data.Xml.Conduit import HaskellWorks.Data.Xml.Succinct.Cursor.BlankedXml @@ -28,25 +26,22 @@ genBitWordsForever bs = BS.uncons bs <|> Just (0, bs) {-# INLINABLE genBitWordsForever #-} -instance FromBlankedXml (XmlBalancedParens (SimpleBalancedParens [Bool])) where-  fromBlankedXml (BlankedXml bj) = XmlBalancedParens (SimpleBalancedParens (runListConduit blankedXmlToBalancedParens bj))- instance FromBlankedXml (XmlBalancedParens (SimpleBalancedParens (DVS.Vector Word8))) where   fromBlankedXml bj    = XmlBalancedParens (SimpleBalancedParens (DVS.unsafeCast (DVS.unfoldrN newLen genBitWordsForever interestBS)))-    where interestBS    = BS.concat (runListConduit (blankedXmlToBalancedParens2 .| compressWordAsBit) (getBlankedXml bj))+    where interestBS    = BS.concat (compressWordAsBit (blankedXmlToBalancedParens2 (getBlankedXml bj)))           newLen        = (BS.length interestBS + 7) `div` 8 * 8  instance FromBlankedXml (XmlBalancedParens (SimpleBalancedParens (DVS.Vector Word16))) where   fromBlankedXml bj    = XmlBalancedParens (SimpleBalancedParens (DVS.unsafeCast (DVS.unfoldrN newLen genBitWordsForever interestBS)))-    where interestBS    = BS.concat (runListConduit (blankedXmlToBalancedParens2 .| compressWordAsBit) (getBlankedXml bj))+    where interestBS    = BS.concat (compressWordAsBit (blankedXmlToBalancedParens2 (getBlankedXml bj)))           newLen        = (BS.length interestBS + 7) `div` 8 * 8  instance FromBlankedXml (XmlBalancedParens (SimpleBalancedParens (DVS.Vector Word32))) where   fromBlankedXml bj    = XmlBalancedParens (SimpleBalancedParens (DVS.unsafeCast (DVS.unfoldrN newLen genBitWordsForever interestBS)))-    where interestBS    = BS.concat (runListConduit (blankedXmlToBalancedParens2 .| compressWordAsBit) (getBlankedXml bj))+    where interestBS    = BS.concat (compressWordAsBit (blankedXmlToBalancedParens2 (getBlankedXml bj)))           newLen        = (BS.length interestBS + 7) `div` 8 * 8  instance FromBlankedXml (XmlBalancedParens (SimpleBalancedParens (DVS.Vector Word64))) where   fromBlankedXml bj    = XmlBalancedParens (SimpleBalancedParens (DVS.unsafeCast (DVS.unfoldrN newLen genBitWordsForever interestBS)))-    where interestBS    = BS.concat (runListConduit (blankedXmlToBalancedParens2 .| compressWordAsBit) (getBlankedXml bj))+    where interestBS    = BS.concat (compressWordAsBit (blankedXmlToBalancedParens2 (getBlankedXml bj)))           newLen        = (BS.length interestBS + 7) `div` 8 * 8
src/HaskellWorks/Data/Xml/Succinct/Cursor/BlankedXml.hs view
@@ -3,11 +3,10 @@   ( BlankedXml(..)   , FromBlankedXml(..)   , getBlankedXml+  , bsToBlankedXml   ) where  import HaskellWorks.Data.ByteString-import HaskellWorks.Data.Conduit.List-import HaskellWorks.Data.FromByteString import HaskellWorks.Data.Xml.Conduit.Blank  import qualified Data.ByteString as BS@@ -20,6 +19,5 @@ class FromBlankedXml a where   fromBlankedXml :: BlankedXml -> a --instance FromByteString BlankedXml where-  fromByteString bs = BlankedXml (runListConduit blankXml (chunkedBy 4064 bs))+bsToBlankedXml :: BS.ByteString -> BlankedXml+bsToBlankedXml bs = BlankedXml (blankXml (chunkedBy 4064 bs))
+ src/HaskellWorks/Data/Xml/Succinct/Cursor/Create.hs view
@@ -0,0 +1,34 @@+module HaskellWorks.Data.Xml.Succinct.Cursor.Create+  ( byteStringAsFastCursor+  , byteStringAsSlowCursor+  ) where++import Data.Coerce+import HaskellWorks.Data.BalancedParens.RangeMin2+import HaskellWorks.Data.BalancedParens.Simple+import HaskellWorks.Data.Bits.BitShown+import HaskellWorks.Data.RankSelect.CsPoppy1+import HaskellWorks.Data.Vector.Storable+import HaskellWorks.Data.Xml.Succinct.Cursor+import HaskellWorks.Data.Xml.Succinct.Cursor.BlankedXml+import HaskellWorks.Data.Xml.Succinct.Cursor.Types++import qualified Data.ByteString                         as BS+import qualified HaskellWorks.Data.Xml.Internal.ToIbBp64 as I++byteStringAsSlowCursor :: BS.ByteString -> SlowCursor+byteStringAsSlowCursor bs = XmlCursor+  { cursorText      = bs+  , interests       = BitShown ib+  , balancedParens  = SimpleBalancedParens bp+  , cursorRank      = 1+  }+  where blankedXml = bsToBlankedXml bs+        (ib, bp) = construct64UnzipN (BS.length bs) (I.toIbBp64 blankedXml)++byteStringAsFastCursor :: BS.ByteString -> FastCursor+byteStringAsFastCursor bs = XmlCursor bs ibCsPoppy rangeMinMax r+  where XmlCursor _ ib bp r = byteStringAsSlowCursor bs+        bpCsPoppy           = makeCsPoppy (coerce bp)+        rangeMinMax         = mkRangeMin2 bpCsPoppy+        ibCsPoppy           = makeCsPoppy (coerce ib)
src/HaskellWorks/Data/Xml/Succinct/Cursor/InterestBits.hs view
@@ -8,13 +8,13 @@   , getXmlInterestBits   , blankedXmlToInterestBits   , blankedXmlBssToInterestBitsBs+  , genInterestForever   ) where  import Control.Applicative import Data.ByteString.Internal import Data.Word import HaskellWorks.Data.Bits.BitShown-import HaskellWorks.Data.Conduit.List import HaskellWorks.Data.FromByteString import HaskellWorks.Data.RankSelect.Poppy512 import HaskellWorks.Data.Xml.Conduit@@ -29,7 +29,7 @@ getXmlInterestBits (XmlInterestBits a) = a  blankedXmlBssToInterestBitsBs :: [ByteString] -> ByteString-blankedXmlBssToInterestBitsBs bss = BS.concat $ runListConduit blankedXmlToInterestBits bss+blankedXmlBssToInterestBitsBs bss = BS.concat $ blankedXmlToInterestBits bss  genInterest :: ByteString -> Maybe (Word8, ByteString) genInterest = BS.uncons@@ -38,7 +38,7 @@ genInterestForever bs = BS.uncons bs <|> Just (0, bs)  instance FromBlankedXml (XmlInterestBits (BitShown [Bool])) where-  fromBlankedXml = XmlInterestBits . fromByteString . BS.concat . runListConduit blankedXmlToInterestBits . getBlankedXml+  fromBlankedXml = XmlInterestBits . fromByteString . BS.concat . blankedXmlToInterestBits . getBlankedXml  instance FromBlankedXml (XmlInterestBits (BitShown BS.ByteString)) where   fromBlankedXml = XmlInterestBits . BitShown . BS.unfoldr genInterest . blankedXmlBssToInterestBitsBs . getBlankedXml
src/HaskellWorks/Data/Xml/Succinct/Cursor/Internal.hs view
@@ -10,7 +10,7 @@   , xmlCursorPos   ) where -import Control.DeepSeq                                    (NFData(..))+import Control.DeepSeq                                    (NFData (..)) import Data.ByteString.Internal                           as BSI import Data.String import Data.Word@@ -54,18 +54,7 @@     , cursorRank      = 1     }     where blankedXml :: BlankedXml-          blankedXml = fromByteString bs--instance IsString (XmlCursor String (BitShown [Bool]) (BP.SimpleBalancedParens [Bool])) where-  fromString :: String -> XmlCursor String (BitShown [Bool]) (BP.SimpleBalancedParens [Bool])-  fromString s = XmlCursor-    { cursorText      = s-    , cursorRank      = 1-    , interests       = getXmlInterestBits (fromBlankedXml blankedXml)-    , balancedParens  = CBP.getXmlBalancedParens (fromBlankedXml blankedXml)-    }-    where blankedXml :: BlankedXml-          blankedXml = fromByteString (BSC.pack s)+          blankedXml = bsToBlankedXml bs  instance IsString (XmlCursor BS.ByteString (BitShown (DVS.Vector Word8)) (BP.SimpleBalancedParens (DVS.Vector Word8))) where   fromString = fromByteString . BSC.pack
+ src/HaskellWorks/Data/Xml/Succinct/Cursor/Load.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE ScopedTypeVariables #-}++module HaskellWorks.Data.Xml.Succinct.Cursor.Load+  ( loadSlowCursor+  , loadFastCursor+  ) where++import HaskellWorks.Data.Xml.Succinct.Cursor.Create+import HaskellWorks.Data.Xml.Succinct.Cursor.Types++import qualified Data.ByteString as BS++-- | Load an XML file into memory and return a raw cursor initialised to the+-- start of the XML document.+loadSlowCursor :: String -> IO SlowCursor+loadSlowCursor = fmap byteStringAsSlowCursor . BS.readFile++-- | Load an XML file into memory and return a query-optimised cursor initialised+-- to the start of the XML document.+loadFastCursor :: String -> IO FastCursor+loadFastCursor = fmap byteStringAsFastCursor . BS.readFile
+ src/HaskellWorks/Data/Xml/Succinct/Cursor/MMap.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE ScopedTypeVariables #-}++module HaskellWorks.Data.Xml.Succinct.Cursor.MMap+  ( SlowCursor+  , FastCursor+  , mmapSlowCursor+  , mmapFastCursor+  ) where++import Data.Word+import Foreign.ForeignPtr+import HaskellWorks.Data.BalancedParens.RangeMin2+import HaskellWorks.Data.BalancedParens.Simple+import HaskellWorks.Data.Bits.BitShown+import HaskellWorks.Data.RankSelect.CsPoppy1+import HaskellWorks.Data.Vector.Storable+import HaskellWorks.Data.Xml.Succinct.Cursor+import HaskellWorks.Data.Xml.Succinct.Cursor.BlankedXml+import HaskellWorks.Data.Xml.Succinct.Cursor.Types++import qualified Data.ByteString.Internal                as BSI+import qualified HaskellWorks.Data.Xml.Internal.ToIbBp64 as I+import qualified System.IO.MMap                          as IO++mmapSlowCursor :: String -> IO SlowCursor+mmapSlowCursor filePath = do+  (fptr :: ForeignPtr Word8, offset, size) <- IO.mmapFileForeignPtr filePath IO.ReadOnly Nothing+  let !bs = BSI.fromForeignPtr (castForeignPtr fptr) offset size+  let blankedXml = bsToBlankedXml bs+  let (ib, bp) = construct64UnzipN (fromIntegral size) (I.toIbBp64 blankedXml)+  let !cursor = XmlCursor+        { cursorText      = bs+        , interests       = BitShown ib+        , balancedParens  = SimpleBalancedParens bp+        , cursorRank      = 1+        }++  return cursor++mmapFastCursor :: String -> IO FastCursor+mmapFastCursor filename = do+  -- Load the XML file into memory as a raw cursor.+  -- The raw XML data is `text`, and `ib` and `bp` are the indexes.+  -- `ib` and `bp` can be persisted to an index file for later use to avoid+  -- re-parsing the file.+  XmlCursor !text (BitShown !ib) (SimpleBalancedParens !bp) _ <- mmapSlowCursor filename+  let !bpCsPoppy = makeCsPoppy bp+  let !rangeMinMax = mkRangeMin2 bpCsPoppy+  let !ibCsPoppy = makeCsPoppy ib+  return $ XmlCursor text ibCsPoppy rangeMinMax 1
+ src/HaskellWorks/Data/Xml/Succinct/Cursor/Types.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE ScopedTypeVariables #-}++module HaskellWorks.Data.Xml.Succinct.Cursor.Types+  ( SlowCursor+  , FastCursor+  ) where++import Data.Word+import HaskellWorks.Data.BalancedParens.RangeMin2+import HaskellWorks.Data.BalancedParens.Simple+import HaskellWorks.Data.Bits.BitShown+import HaskellWorks.Data.RankSelect.CsPoppy1+import HaskellWorks.Data.Xml.Succinct.Cursor++import qualified Data.ByteString      as BS+import qualified Data.Vector.Storable as DVS++type SlowCursor = XmlCursor BS.ByteString (BitShown (DVS.Vector Word64)) (SimpleBalancedParens (DVS.Vector Word64))++type FastCursor = XmlCursor BS.ByteString CsPoppy1 (RangeMin2 CsPoppy1)
test/HaskellWorks/Data/Xml/Conduit/BlankSpec.hs view
@@ -4,22 +4,24 @@ module HaskellWorks.Data.Xml.Conduit.BlankSpec (spec) where  import Data.Char-import Data.Monoid+import Data.Semigroup                      ((<>)) import HaskellWorks.Data.ByteString-import HaskellWorks.Data.Conduit.List import HaskellWorks.Data.Xml.Conduit.Blank+import HaskellWorks.Hspec.Hedgehog+import Hedgehog import Test.Hspec-import Test.QuickCheck  import qualified Data.ByteString as BS+import qualified Hedgehog.Gen    as G+import qualified Hedgehog.Range  as R  {-# ANN module ("HLint: ignore Redundant do" :: String) #-} {-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}  whenBlankedXmlShouldBe :: BS.ByteString -> BS.ByteString -> Spec whenBlankedXmlShouldBe original expected = do-  it (show original <> " when blanked xml should be " <> show expected) $ do-    BS.concat (runListConduit blankXml [original]) `shouldBe` expected+  it (show original <> " when blanked xml should be " <> show expected) $ requireTest $ do+    BS.concat (blankXml [original]) === expected  repeatBS :: Int -> BS.ByteString -> BS.ByteString repeatBS n bs | n > 0   = bs <> repeatBS (n - 1) bs@@ -68,50 +70,52 @@     "<a><c>00</c><s/></a>"                    `whenBlankedXmlShouldBe` "<  <  t    ><  >   >"     "<a><c>0</c><s/></a>"                     `whenBlankedXmlShouldBe` "<  <  t   ><  >   >" -  it "Can blank across chunk boundaries with basic tags" $ do+  it "Can blank across chunk boundaries with basic tags" $ requireTest $ do     let inputOriginalPrefix = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<statistics>\n  <attack>"     let inputOriginalSuffix = "\n  </attack>\n  <attack></attack>\n  <attack></attack>\n  <attack></attack>\n  <attack></attack>\n</statistics>\n"     let inputOriginal = inputOriginalPrefix <> inputOriginalSuffix     let inputOriginalChunked = chunkedBy 16 inputOriginal-    let inputOriginalBlanked = runListConduit blankXml inputOriginalChunked+    let inputOriginalBlanked = blankXml inputOriginalChunked -    forAll (choose (0, 16)) $ \(n :: Int) -> do-      let inputShifted = inputOriginalPrefix <> repeatBS n " " <> inputOriginalSuffix-      let inputShiftedChunked = chunkedBy 16 inputShifted-      let inputShiftedBlanked = runListConduit blankXml inputShiftedChunked+    n <- forAll $ G.int (R.linear 0 16) -      noSpaces (BS.concat inputShiftedBlanked) `shouldBe` noSpaces (BS.concat inputOriginalBlanked)-  it "Can blank across chunk boundaries with auto-close tags" $ do+    let inputShifted = inputOriginalPrefix <> repeatBS n " " <> inputOriginalSuffix+    let inputShiftedChunked = chunkedBy 16 inputShifted+    let inputShiftedBlanked = blankXml inputShiftedChunked++    noSpaces (BS.concat inputShiftedBlanked) === noSpaces (BS.concat inputOriginalBlanked)+  it "Can blank across chunk boundaries with auto-close tags" $ requireTest $ do     let inputOriginalPrefix = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><statistics><attack>"     let inputOriginalSuffix = "<inner/></attack><attack></attack></statistics>\n"     let inputOriginal = inputOriginalPrefix <> inputOriginalSuffix     let inputOriginalChunked = chunkedBy 16 inputOriginal-    let inputOriginalBlanked = runListConduit blankXml inputOriginalChunked+    let inputOriginalBlanked = blankXml inputOriginalChunked -    forAll (choose (0, 16)) $ \(n :: Int) -> do-      let inputShifted = inputOriginalPrefix <> repeatBS n " " <> inputOriginalSuffix-      let inputShiftedChunked = chunkedBy 16 inputShifted-      let inputShiftedBlanked = runListConduit blankXml inputShiftedChunked+    n <- forAll $ G.int (R.linear 0 16) -      -- putStrLn $ show (BS.concat inputShiftedBlanked) <> " vs " <> show (BS.concat inputOriginalBlanked)-      let actual    = Annotated (noSpaces (BS.concat inputShiftedBlanked )) (inputShiftedBlanked, n)-      let expected  = Annotated (noSpaces (BS.concat inputOriginalBlanked)) (inputOriginalBlanked, n)+    let inputShifted = inputOriginalPrefix <> repeatBS n " " <> inputOriginalSuffix+    let inputShiftedChunked = chunkedBy 16 inputShifted+    let inputShiftedBlanked = blankXml inputShiftedChunked -      actual `shouldBe` expected-  it "Can blank across chunk boundaries with auto-close tags" $ do+    -- putStrLn $ show (BS.concat inputShiftedBlanked) <> " vs " <> show (BS.concat inputOriginalBlanked)+    let actual    = Annotated (noSpaces (BS.concat inputShiftedBlanked )) (inputShiftedBlanked, n)+    let expected  = Annotated (noSpaces (BS.concat inputOriginalBlanked)) (inputOriginalBlanked, n)++    actual === expected+  it "Can blank across chunk boundaries with auto-close tags" $ requireTest $ do     let inputOriginalPrefix = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><statistics><attack>"     let inputOriginalSuffix = "<inner/></attack><attack></attack></statistics>\n"     let inputOriginal = inputOriginalPrefix <> inputOriginalSuffix     let inputOriginalChunked = chunkedBy 16 inputOriginal-    let inputOriginalBlanked = runListConduit blankXml inputOriginalChunked+    let inputOriginalBlanked = blankXml inputOriginalChunked      let n = 15     let inputShifted = inputOriginalPrefix <> repeatBS n " " <> inputOriginalSuffix     let inputShiftedChunked = chunkedBy 16 inputShifted-    let inputShiftedBlanked = runListConduit blankXml inputShiftedChunked+    let inputShiftedBlanked = blankXml inputShiftedChunked      -- putStrLn $ show (BS.concat inputShiftedBlanked) <> " vs " <> show (BS.concat inputOriginalBlanked)     let actual    = Annotated (noSpaces (BS.concat inputShiftedBlanked )) (inputShiftedBlanked, n)     let expected  = Annotated (noSpaces (BS.concat inputOriginalBlanked)) (inputOriginalBlanked, n) -    actual `shouldBe` expected+    actual === expected
test/HaskellWorks/Data/Xml/RawValueSpec.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE FlexibleContexts          #-} {-# LANGUAGE FlexibleInstances         #-} {-# LANGUAGE InstanceSigs              #-}+{-# LANGUAGE MonoLocalBinds            #-} {-# LANGUAGE MultiParamTypeClasses     #-} {-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE OverloadedStrings         #-}@@ -12,21 +13,22 @@ module HaskellWorks.Data.Xml.RawValueSpec (spec) where  import Control.Monad-import Data.Monoid+import Data.Semigroup                                  ((<>)) import Data.String import Data.Word import HaskellWorks.Data.BalancedParens.BalancedParens import HaskellWorks.Data.BalancedParens.Simple import HaskellWorks.Data.Bits.BitShown import HaskellWorks.Data.Bits.BitWise-import HaskellWorks.Data.FromForeignRegion import HaskellWorks.Data.RankSelect.Base.Rank0 import HaskellWorks.Data.RankSelect.Base.Rank1 import HaskellWorks.Data.RankSelect.Base.Select1 import HaskellWorks.Data.RankSelect.Poppy512+import HaskellWorks.Data.Xml.RawValue import HaskellWorks.Data.Xml.Succinct.Cursor           as C import HaskellWorks.Data.Xml.Succinct.Index-import HaskellWorks.Data.Xml.RawValue+import HaskellWorks.Hspec.Hedgehog+import Hedgehog import Test.Hspec  import qualified Data.ByteString              as BS@@ -35,11 +37,9 @@  {-# ANN module ("HLint: ignore Redundant do"        :: String) #-} {-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}---{-# ANN module ("HLint: ignore Redundant bracket"   :: String) #-}  fc = TC.firstChild ns = TC.nextSibling--- cd = TC.depth  attrs :: [(String, String)] -> RawValue attrs as = RawAttrList $ as >>= (\(k, v) -> [RawAttrName k, RawAttrValue v])@@ -59,18 +59,14 @@   Nothing -> RawError "No such element"  genSpec :: forall t u.-  ( Eq                t-  , Show              t+  ( Show              t   , Select1           t-  , Eq                u   , Show              u   , Rank0             u   , Rank1             u   , BalancedParens    u   , TestBit           u-  , FromForeignRegion (XmlCursor BS.ByteString t u)   , IsString          (XmlCursor BS.ByteString t u)-  , XmlIndexAt        (XmlCursor BS.ByteString t u)   )   => String -> XmlCursor BS.ByteString t u -> SpecWith () genSpec t _ = do@@ -78,47 +74,47 @@     let forXml (cursor :: XmlCursor BS.ByteString t u) f = describe ("of value " <> show cursor) (f cursor)      forXml "<a/>" $ \cursor -> do-      it "should have correct value"      $ rawValueVia (Just cursor) `shouldBe` RawElement "a" []+      it "should have correct value" $ requireTest $ rawValueVia (Just cursor) === RawElement "a" []      forXml "<a attr='value'/>" $ \cursor -> do-      it "should have correct value"    $ rawValueVia (Just cursor) `shouldBe`+      it "should have correct value"    $ requireTest $ rawValueVia (Just cursor) ===         RawElement "a" [attrs [("attr", "value")]]      forXml "<a attr='value'><b attr='value' /></a>" $ \cursor -> do-      it "should have correct value"    $ rawValueVia (Just cursor) `shouldBe`+      it "should have correct value"  $ requireTest $ rawValueVia (Just cursor) ===         RawElement "a" [attrs [("attr", "value")],           RawElement "b" [attrs [("attr", "value")]]]      forXml "<a>value text</a>" $ \cursor -> do-      it "should have correct value"      $ rawValueVia (Just cursor) `shouldBe`+      it "should have correct value"  $ requireTest $ rawValueVia (Just cursor) ===         RawElement "a" [RawText "value text"]      forXml "<!-- some comment -->" $ \cursor -> do-      it "should parse space separared comment" $ rawValueVia (Just cursor) `shouldBe`+      it "should parse space separared comment" $ requireTest $ rawValueVia (Just cursor) ===         RawComment " some comment "      forXml "<!--some comment ->-->" $ \cursor -> do-      it "should parse space separared comment" $ rawValueVia (Just cursor) `shouldBe`+      it "should parse space separared comment" $ requireTest $ rawValueVia (Just cursor) ===         RawComment "some comment ->"      forXml "<![CDATA[a <br/> tag]]>" $ \cursor -> do-      it "should parse cdata data" $ rawValueVia (Just cursor) `shouldBe`+      it "should parse cdata data" $ requireTest $ rawValueVia (Just cursor) ===         RawCData "a <br/> tag"      forXml "<!DOCTYPE greeting [<!ELEMENT greeting (#PCDATA)>]>" $ \cursor -> do-      it "should parse metas" $ rawValueVia (Just cursor) `shouldBe`+      it "should parse metas" $ requireTest $ rawValueVia (Just cursor) ===         RawMeta "DOCTYPE" [RawMeta "ELEMENT" []]      forXml "<?xml version=\"1.0\" encoding=\"UTF-8\"?><a text='value'>free</a>" $ \cursor -> do-      it "should parse xml header" $ rawValueVia (Just cursor) `shouldBe`+      it "should parse xml header" $ requireTest $ rawValueVia (Just cursor) ===         RawDocument [           attrs [("version", "1.0"), ("encoding", "UTF-8")],           RawElement "a" [attrs [("text", "value")],           RawText "free"]] -      it "navigate around" $ do-        rawValueVia (ns cursor) `shouldBe` RawElement "a" [attrs [("text", "value")], RawText "free"]-        rawValueVia ((ns >=> fc) cursor) `shouldBe` attrs [("text", "value")]-        rawValueVia ((ns >=> fc >=> fc) cursor) `shouldBe` RawAttrName "text"-        rawValueVia ((ns >=> fc >=> fc >=> ns) cursor) `shouldBe` RawAttrValue "value"-        rawValueVia ((ns >=> fc >=> ns) cursor) `shouldBe` RawText "free"+      it "navigate around" $ requireTest $ do+        rawValueVia (ns cursor) === RawElement "a" [attrs [("text", "value")], RawText "free"]+        rawValueVia ((ns >=> fc) cursor) === attrs [("text", "value")]+        rawValueVia ((ns >=> fc >=> fc) cursor) === RawAttrName "text"+        rawValueVia ((ns >=> fc >=> fc >=> ns) cursor) === RawAttrValue "value"+        rawValueVia ((ns >=> fc >=> ns) cursor) === RawText "free"
test/HaskellWorks/Data/Xml/Succinct/Cursor/BalancedParensSpec.hs view
@@ -3,16 +3,15 @@  module HaskellWorks.Data.Xml.Succinct.Cursor.BalancedParensSpec(spec) where -import Data.Conduit import Data.Monoid                                      ((<>)) import Data.String import HaskellWorks.Data.Bits.BitShown import HaskellWorks.Data.ByteString-import HaskellWorks.Data.Conduit.List import HaskellWorks.Data.Xml.Conduit import HaskellWorks.Data.Xml.Conduit.Blank-import HaskellWorks.Data.Xml.Conduit.Blank import HaskellWorks.Data.Xml.Succinct.Cursor.BlankedXml+import HaskellWorks.Hspec.Hedgehog+import Hedgehog import Test.Hspec  import qualified Data.ByteString as BS@@ -21,55 +20,55 @@  spec :: Spec spec = describe "HaskellWorks.Data.Xml.Succinct.Cursor.BalancedParensSpec" $ do-  it "Blanking XML should work 1" $ do+  it "Blanking XML should work 1" $ requireTest $ do     let blankedXml = BlankedXml ["<t<t>>"]-    let bp = BitShown $ BS.concat (runListConduit (blankedXmlToBalancedParens2 .| compressWordAsBit) (getBlankedXml blankedXml))-    bp `shouldBe` fromString "11011000"-  it "Blanking XML should work 2" $ do+    let bp = BitShown $ BS.concat (compressWordAsBit (blankedXmlToBalancedParens2 (getBlankedXml blankedXml)))+    bp === fromString "11011000"+  it "Blanking XML should work 2" $ requireTest $ do     let blankedXml = BlankedXml           [ "<><><><><><><><>"           , "<><><><><><><><>"           ]-    let bp = BitShown $ BS.concat (runListConduit (blankedXmlToBalancedParens2 .| compressWordAsBit) (getBlankedXml blankedXml))-    bp `shouldBe` fromString+    let bp = BitShown $ BS.concat (compressWordAsBit (blankedXmlToBalancedParens2 (getBlankedXml blankedXml)))+    bp === fromString           "1010101010101010\           \1010101010101010"    let unchunkedInput = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<micro_stats>\n  <metric>\n  </metric>\n  <metric></metric>\n  <metric></metric>\n  <metric></metric>\n  <metric></metric>\n</micro_stats>\n"   let chunkedInput = chunkedBy 15 unchunkedInput-  let chunkedBlank = runListConduit blankXml chunkedInput+  let chunkedBlank = blankXml chunkedInput    let unchunkedBadInput = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<micro_stats>\n  <metric>       \n  </metric>\n  <metric></metric>\n  <metric></metric>\n  <metric></metric>\n  <metric></metric>\n</micro_stats>\n"   let chunkedBadInput = chunkedBy 15 unchunkedBadInput-  let chunkedBadBlank = runListConduit blankXml chunkedBadInput+  let chunkedBadBlank = blankXml chunkedBadInput -  it "Same input" $ do-    unchunkedInput `shouldBe` BS.concat chunkedInput+  it "Same input" $ requireTest $ do+    unchunkedInput === BS.concat chunkedInput -  it "Blanking XML should work 3" $ do-    let bp = BitShown $ BS.concat (runListConduit (blankedXmlToBalancedParens2 .| compressWordAsBit) chunkedBlank)-    putStrLn $ "Good: " <> show chunkedBlank-    bp `shouldBe` fromString "11101010 10001101 01010100"+  it "Blanking XML should work 3" $ requireTest $ do+    let bp = BitShown $ BS.concat (compressWordAsBit (blankedXmlToBalancedParens2 chunkedBlank))+    annotate $ "Good: " <> show chunkedBlank+    bp === fromString "11101010 10001101 01010100" -  it "Blanking XML should work 3" $ do-    let bp = BitShown $ BS.concat (runListConduit (blankedXmlToBalancedParens2 .| compressWordAsBit) chunkedBadBlank)-    putStrLn $ "Bad: " <> show chunkedBadBlank-    bp `shouldBe` fromString "11101010 10001101 01010100"+  it "Blanking XML should work 3" $ requireTest $do+    let bp = BitShown $ BS.concat (compressWordAsBit (blankedXmlToBalancedParens2 chunkedBadBlank))+    annotate $ "Bad: " <> show chunkedBadBlank+    bp === fromString "11101010 10001101 01010100"    describe "Chunking works" $ do     let document = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><a text='value'>free</a>"     let whole = mkBlank 4096 document     let chunked = mkBlank 15 document -    it "should BP the same with chanks" $ do-      BS.concat chunked `shouldBe` BS.concat whole+    it "should BP the same with chanks" $ requireTest $do+      BS.concat chunked === BS.concat whole -    it "should produce same bits" $ do-      BS.concat (mkBits chunked) `shouldBe` BS.concat (mkBits whole)+    it "should produce same bits" $ requireTest $do+      BS.concat (mkBits chunked) === BS.concat (mkBits whole)   mkBlank :: Int -> BS.ByteString -> [BS.ByteString]-mkBlank csize bs = runListConduit blankXml (chunkedBy csize bs)+mkBlank csize bs = blankXml (chunkedBy csize bs)  mkBits :: [BS.ByteString] -> [BS.ByteString]-mkBits = runListConduit (blankedXmlToBalancedParens2 .| compressWordAsBit)+mkBits = compressWordAsBit . blankedXmlToBalancedParens2
test/HaskellWorks/Data/Xml/Succinct/Cursor/InterestBitsSpec.hs view
@@ -7,10 +7,11 @@ import Data.String import Data.Word import HaskellWorks.Data.Bits.BitShown-import HaskellWorks.Data.Conduit.List import HaskellWorks.Data.FromByteString import HaskellWorks.Data.Xml.Succinct.Cursor.BlankedXml import HaskellWorks.Data.Xml.Succinct.Cursor.InterestBits+import HaskellWorks.Hspec.Hedgehog+import Hedgehog import Test.Hspec  import qualified Data.ByteString      as BS@@ -19,21 +20,21 @@ {-# ANN module ("HLint: ignore Redundant do"        :: String) #-}  interestBitsOf :: FromBlankedXml (XmlInterestBits a) => BS.ByteString -> a-interestBitsOf = getXmlInterestBits . fromBlankedXml . fromByteString+interestBitsOf = getXmlInterestBits . fromBlankedXml . bsToBlankedXml  spec :: Spec spec = describe "HaskellWorks.Data.Xml.Succinct.Cursor.InterestBitsSpec" $ do-  it "Evaluating interest bits" $ do-    (interestBitsOf ""               :: BitShown (DVS.Vector Word8)) `shouldBe` fromString ""-    (interestBitsOf "  \n \r \t "    :: BitShown (DVS.Vector Word8)) `shouldBe` fromString "00000000"-    (interestBitsOf "<el atr"        :: BitShown (DVS.Vector Word8)) `shouldBe` fromString "10011000"-    (interestBitsOf "[alse "         :: BitShown (DVS.Vector Word8)) `shouldBe` fromString "10000000"-    (interestBitsOf "(rue "          :: BitShown (DVS.Vector Word8)) `shouldBe` fromString "10000000"-    (interestBitsOf "<e><c></e>"     :: BitShown (DVS.Vector Word8)) `shouldBe` fromString "10010000 00000000"-    (interestBitsOf " <e p='a'/> "   :: BitShown (DVS.Vector Word8)) `shouldBe` fromString "01011010 00000000"-    (interestBitsOf " <!-- u -->"    :: BitShown (DVS.Vector Word8)) `shouldBe` fromString "01000000 00000000"-    (interestBitsOf "<![CDATA[ x"    :: BitShown (DVS.Vector Word8)) `shouldBe` fromString "10000000 00000000"-  it "Can build interest bits across boundaries" $ do+  it "Evaluating interest bits" $ requireTest $ do+    (interestBitsOf ""               :: BitShown (DVS.Vector Word8)) === fromString ""+    (interestBitsOf "  \n \r \t "    :: BitShown (DVS.Vector Word8)) === fromString "00000000"+    (interestBitsOf "<el atr"        :: BitShown (DVS.Vector Word8)) === fromString "10011000"+    (interestBitsOf "[alse "         :: BitShown (DVS.Vector Word8)) === fromString "10000000"+    (interestBitsOf "(rue "          :: BitShown (DVS.Vector Word8)) === fromString "10000000"+    (interestBitsOf "<e><c></e>"     :: BitShown (DVS.Vector Word8)) === fromString "10010000 00000000"+    (interestBitsOf " <e p='a'/> "   :: BitShown (DVS.Vector Word8)) === fromString "01011010 00000000"+    (interestBitsOf " <!-- u -->"    :: BitShown (DVS.Vector Word8)) === fromString "01000000 00000000"+    (interestBitsOf "<![CDATA[ x"    :: BitShown (DVS.Vector Word8)) === fromString "10000000 00000000"+  it "Can build interest bits across boundaries" $ requireTest $do     let blanked =           [ "<    (a "           , "      v "@@ -43,13 +44,13 @@           , "<  <     "           , ">   >"           ]-    putStrLn $ "Blanked: " <> show blanked+    annotate $ "Blanked: " <> show blanked     let ib :: XmlInterestBits (BitShown (DVS.Vector Word8))         ib = XmlInterestBits (getXmlInterestBits (fromBlankedXml (BlankedXml blanked)))     let moo :: [BS.ByteString]-        moo = runListConduit blankedXmlToInterestBits blanked -- :: XmlInterestBits (BitShown (DVS.Vector Word8))-    putStrLn $ "Moo:       " <> show (BitShown . BS.unpack <$> moo)+        moo = blankedXmlToInterestBits blanked -- :: XmlInterestBits (BitShown (DVS.Vector Word8))+    annotate $ "Moo:       " <> show (BitShown . BS.unpack <$> moo)     let actual = getXmlInterestBits ib :: BitShown (DVS.Vector Word8)     let expected = fromString "10000110 00000010 00001000 00000100 00000001 00100000 00000000" -    actual `shouldBe` expected+    actual === expected
test/HaskellWorks/Data/Xml/Succinct/CursorSpec.hs view
@@ -19,14 +19,14 @@ import HaskellWorks.Data.Bits.BitShow import HaskellWorks.Data.Bits.BitShown import HaskellWorks.Data.Bits.BitWise-import HaskellWorks.Data.FromForeignRegion import HaskellWorks.Data.RankSelect.Base.Rank0 import HaskellWorks.Data.RankSelect.Base.Rank1 import HaskellWorks.Data.RankSelect.Base.Select1 import HaskellWorks.Data.RankSelect.Poppy512 import HaskellWorks.Data.Xml.Succinct.Cursor           as C-import HaskellWorks.Data.Xml.Succinct.Index import HaskellWorks.Data.Xml.Token+import HaskellWorks.Hspec.Hedgehog+import Hedgehog import Test.Hspec  import qualified Data.ByteString              as BS@@ -45,38 +45,19 @@  spec :: Spec spec = describe "HaskellWorks.Data.Xml.Succinct.CursorSpec" $ do-  describe "Cursor for Element" $ do-    it "depth at top" $ do-      let cursor = "<widget debug='on'/>" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      cd cursor `shouldBe` Just 1-    it "depth at attribute list" $ do-      let cursor = "<widget debug='on' />" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      (fc >=> cd) cursor `shouldBe` Just 2-    it "depth first attribute" $ do-      let cursor = "<widget debug='on' enabled='on' />" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      (fc >=> fc >=> cd) cursor `shouldBe` Just 3-    it "depth second attribute" $ do-      let cursor = "<widget debug='on' enabled='on' />" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      (fc >=> fc >=> ns >=> cd) cursor `shouldBe` Just 3-    it "depth at value" $ do-      let cursor = "<widget debug='on'>text</widget>" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      (fc >=> ns >=> cd) cursor `shouldBe` Just 2-    xit "depth at first child of object at second child of array" $ do-      let cursor = "[null, {\"field\": 1}]" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      (fc >=> ns >=> fc >=> ns >=> cd) cursor `shouldBe` Just 3   genSpec "DVS.Vector Word8"  (undefined :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word8)) (SimpleBalancedParens (DVS.Vector Word8)))   genSpec "DVS.Vector Word16" (undefined :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word16)) (SimpleBalancedParens (DVS.Vector Word16)))   genSpec "DVS.Vector Word32" (undefined :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word32)) (SimpleBalancedParens (DVS.Vector Word32)))   genSpec "DVS.Vector Word64" (undefined :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word64)) (SimpleBalancedParens (DVS.Vector Word64)))   genSpec "Poppy512"          (undefined :: XmlCursor BS.ByteString Poppy512 (SimpleBalancedParens (DVS.Vector Word64)))-  it "Loads same Xml consistentally from different backing vectors" $ do+  it "Loads same Xml consistentally from different backing vectors" $ requireTest $ do     let cursor8   = "{\n    \"widget\": {\n        \"debug\": \"on\"  } }" :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word8)) (SimpleBalancedParens (DVS.Vector Word8))     let cursor16  = "{\n    \"widget\": {\n        \"debug\": \"on\"  } }" :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word16)) (SimpleBalancedParens (DVS.Vector Word16))     let cursor32  = "{\n    \"widget\": {\n        \"debug\": \"on\"  } }" :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word32)) (SimpleBalancedParens (DVS.Vector Word32))     let cursor64  = "{\n    \"widget\": {\n        \"debug\": \"on\"  } }" :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word64)) (SimpleBalancedParens (DVS.Vector Word64))-    cursorText cursor8 `shouldBe` cursorText cursor16-    cursorText cursor8 `shouldBe` cursorText cursor32-    cursorText cursor8 `shouldBe` cursorText cursor64+    cursorText cursor8 === cursorText cursor16+    cursorText cursor8 === cursorText cursor32+    cursorText cursor8 === cursorText cursor64     let ic8   = bitShow $ interests cursor8     let ic16  = bitShow $ interests cursor16     let ic32  = bitShow $ interests cursor32@@ -85,8 +66,8 @@     ic32 `shouldBeginWith` ic16     ic64 `shouldBeginWith` ic32 -shouldBeginWith :: (Eq a, Show a) => [a] -> [a] -> IO ()-shouldBeginWith as bs = take (length bs) as `shouldBe` bs+shouldBeginWith :: (Eq a, Show a) => [a] -> [a] -> PropertyT IO ()+shouldBeginWith as bs = take (length bs) as === bs  genSpec :: forall t u.   ( Eq                t@@ -98,24 +79,22 @@   , Rank1             u   , BalancedParens    u   , TestBit           u-  , FromForeignRegion (XmlCursor BS.ByteString t u)   , IsString          (XmlCursor BS.ByteString t u)-  , XmlIndexAt        (XmlCursor BS.ByteString t u)   )   => String -> XmlCursor BS.ByteString t u -> SpecWith () genSpec t _ = do   describe ("Cursor for (" ++ t ++ ")") $ do     let forXml (cursor :: XmlCursor BS.ByteString t u) f = describe ("of value " ++ show cursor) (f cursor)     forXml "[null]" $ \cursor -> do-      it "depth at top"                   $ cd          cursor `shouldBe` Just 1-      xit "depth at first child of array"  $ (fc >=> cd) cursor `shouldBe` Just 2+      it "depth at top"                   $ requireTest $ cd          cursor === Just 1+      xit "depth at first child of array" $ requireTest $ (fc >=> cd) cursor === Just 2     forXml "[null, {\"field\": 1}]" $ \cursor -> do-      xit "depth at second child of array" $ do-        (fc >=> ns >=> cd) cursor `shouldBe` Just 2-      xit "depth at first child of object at second child of array" $ do-        (fc >=> ns >=> fc >=> cd) cursor `shouldBe` Just 3-      xit "depth at first child of object at second child of array" $ do-        (fc >=> ns >=> fc >=> ns >=> cd) cursor `shouldBe` Just 3+      xit "depth at second child of array" $ requireTest $do+        (fc >=> ns >=> cd) cursor === Just 2+      xit "depth at first child of object at second child of array" $ requireTest $ do+        (fc >=> ns >=> fc >=> cd) cursor === Just 3+      xit "depth at first child of object at second child of array" $ requireTest $ do+        (fc >=> ns >=> fc >=> ns >=> cd) cursor === Just 3      describe "For sample XML" $ do       let cursor =  "<widget debug=\"on\"> \@@ -125,39 +104,39 @@                     \    <dimension>    false   </dimension> \                     \  </window> \                     \</widget>" :: XmlCursor BS.ByteString t u-      xit "can get token at cursor" $ do-        (xmlTokenAt                                                                      ) cursor `shouldBe` Just (XmlTokenBraceL                 )-        (fc                                                                >=> xmlTokenAt) cursor `shouldBe` Just (XmlTokenString   "widget"      )-        (fc >=> ns                                                         >=> xmlTokenAt) cursor `shouldBe` Just (XmlTokenBraceL                 )-        (fc >=> ns >=> fc                                                  >=> xmlTokenAt) cursor `shouldBe` Just (XmlTokenString   "debug"       )-        (fc >=> ns >=> fc >=> ns                                           >=> xmlTokenAt) cursor `shouldBe` Just (XmlTokenString   "on"          )-        (fc >=> ns >=> fc >=> ns >=> ns                                    >=> xmlTokenAt) cursor `shouldBe` Just (XmlTokenString   "window"      )-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns                             >=> xmlTokenAt) cursor `shouldBe` Just (XmlTokenBraceL                 )-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc                      >=> xmlTokenAt) cursor `shouldBe` Just (XmlTokenString   "name"        )-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns               >=> xmlTokenAt) cursor `shouldBe` Just (XmlTokenString   "main_window" )-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns        >=> xmlTokenAt) cursor `shouldBe` Just (XmlTokenString   "dimensions"  )-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns >=> ns >=> xmlTokenAt) cursor `shouldBe` Just (XmlTokenBracketL               )-      xit "can navigate up" $ do-        (                                                                      pn) cursor `shouldBe` Nothing-        (fc                                                                >=> pn) cursor `shouldBe`                                    Just cursor-        (fc >=> ns                                                         >=> pn) cursor `shouldBe`                                    Just cursor-        (fc >=> ns >=> fc                                                  >=> pn) cursor `shouldBe` (fc >=> ns                            ) cursor-        (fc >=> ns >=> fc >=> ns                                           >=> pn) cursor `shouldBe` (fc >=> ns                            ) cursor-        (fc >=> ns >=> fc >=> ns >=> ns                                    >=> pn) cursor `shouldBe` (fc >=> ns                            ) cursor-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns                             >=> pn) cursor `shouldBe` (fc >=> ns                            ) cursor-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc                      >=> pn) cursor `shouldBe` (fc >=> ns >=> fc >=> ns >=> ns >=> ns) cursor-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns               >=> pn) cursor `shouldBe` (fc >=> ns >=> fc >=> ns >=> ns >=> ns) cursor-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns        >=> pn) cursor `shouldBe` (fc >=> ns >=> fc >=> ns >=> ns >=> ns) cursor-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns >=> ns >=> pn) cursor `shouldBe` (fc >=> ns >=> fc >=> ns >=> ns >=> ns) cursor-      xit "can get subtree size" $ do-        (                                                                      ss) cursor `shouldBe` Just 16-        (fc                                                                >=> ss) cursor `shouldBe` Just 1-        (fc >=> ns                                                         >=> ss) cursor `shouldBe` Just 14-        (fc >=> ns >=> fc                                                  >=> ss) cursor `shouldBe` Just 1-        (fc >=> ns >=> fc >=> ns                                           >=> ss) cursor `shouldBe` Just 1-        (fc >=> ns >=> fc >=> ns >=> ns                                    >=> ss) cursor `shouldBe` Just 1-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns                             >=> ss) cursor `shouldBe` Just 10-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc                      >=> ss) cursor `shouldBe` Just 1-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns               >=> ss) cursor `shouldBe` Just 1-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns        >=> ss) cursor `shouldBe` Just 1-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns >=> ns >=> ss) cursor `shouldBe` Just 6+      xit "can get token at cursor" $ requireTest $ do+        (xmlTokenAt                                                                      ) cursor === Just (XmlTokenBraceL                 )+        (fc                                                                >=> xmlTokenAt) cursor === Just (XmlTokenString   "widget"      )+        (fc >=> ns                                                         >=> xmlTokenAt) cursor === Just (XmlTokenBraceL                 )+        (fc >=> ns >=> fc                                                  >=> xmlTokenAt) cursor === Just (XmlTokenString   "debug"       )+        (fc >=> ns >=> fc >=> ns                                           >=> xmlTokenAt) cursor === Just (XmlTokenString   "on"          )+        (fc >=> ns >=> fc >=> ns >=> ns                                    >=> xmlTokenAt) cursor === Just (XmlTokenString   "window"      )+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns                             >=> xmlTokenAt) cursor === Just (XmlTokenBraceL                 )+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc                      >=> xmlTokenAt) cursor === Just (XmlTokenString   "name"        )+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns               >=> xmlTokenAt) cursor === Just (XmlTokenString   "main_window" )+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns        >=> xmlTokenAt) cursor === Just (XmlTokenString   "dimensions"  )+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns >=> ns >=> xmlTokenAt) cursor === Just (XmlTokenBracketL               )+      xit "can navigate up" $ requireTest $ do+        (                                                                      pn) cursor === Nothing+        (fc                                                                >=> pn) cursor ===                                    Just cursor+        (fc >=> ns                                                         >=> pn) cursor ===                                    Just cursor+        (fc >=> ns >=> fc                                                  >=> pn) cursor === (fc >=> ns                            ) cursor+        (fc >=> ns >=> fc >=> ns                                           >=> pn) cursor === (fc >=> ns                            ) cursor+        (fc >=> ns >=> fc >=> ns >=> ns                                    >=> pn) cursor === (fc >=> ns                            ) cursor+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns                             >=> pn) cursor === (fc >=> ns                            ) cursor+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc                      >=> pn) cursor === (fc >=> ns >=> fc >=> ns >=> ns >=> ns) cursor+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns               >=> pn) cursor === (fc >=> ns >=> fc >=> ns >=> ns >=> ns) cursor+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns        >=> pn) cursor === (fc >=> ns >=> fc >=> ns >=> ns >=> ns) cursor+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns >=> ns >=> pn) cursor === (fc >=> ns >=> fc >=> ns >=> ns >=> ns) cursor+      xit "can get subtree size" $ requireTest $ do+        (                                                                      ss) cursor === Just 16+        (fc                                                                >=> ss) cursor === Just 1+        (fc >=> ns                                                         >=> ss) cursor === Just 14+        (fc >=> ns >=> fc                                                  >=> ss) cursor === Just 1+        (fc >=> ns >=> fc >=> ns                                           >=> ss) cursor === Just 1+        (fc >=> ns >=> fc >=> ns >=> ns                                    >=> ss) cursor === Just 1+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns                             >=> ss) cursor === Just 10+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc                      >=> ss) cursor === Just 1+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns               >=> ss) cursor === Just 1+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns        >=> ss) cursor === Just 1+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> ns >=> ns >=> ns >=> ss) cursor === Just 6
test/HaskellWorks/Data/Xml/Token/TokenizeSpec.hs view
@@ -4,6 +4,8 @@  import Data.ByteString                      as BS import HaskellWorks.Data.Xml.Token.Tokenize+import HaskellWorks.Hspec.Hedgehog+import Hedgehog import Test.Hspec  import qualified Data.Attoparsec.ByteString.Char8 as BC@@ -16,35 +18,35 @@ spec :: Spec spec = describe "Data.Conduit.Succinct.XmlSpec" $ do   describe "When parsing single token at beginning of text" $ do-    it "Empty Xml should produce no bits" $-      parseXmlToken' "" `shouldBe` Left "not enough input"-    it "Xml with one space should produce whitespace token" $-      parseXmlToken' " " `shouldBe` Right XmlTokenWhitespace-    it "Xml with two spaces should produce whitespace token" $-      parseXmlToken' "  " `shouldBe` Right XmlTokenWhitespace-    it "Spaces and newlines should produce no bits" $-      parseXmlToken' "  \n \r \t " `shouldBe` Right XmlTokenWhitespace-    it "`null` at beginning should produce one bit" $-      parseXmlToken' "null " `shouldBe` Right XmlTokenNull-    it "number at beginning should produce one bit" $-      parseXmlToken' "1234 " `shouldBe` Right (XmlTokenNumber 1234)-    it "false at beginning should produce one bit" $-      parseXmlToken' "false " `shouldBe` Right (XmlTokenBoolean False)-    it "true at beginning should produce one bit" $-      parseXmlToken' "true " `shouldBe` Right (XmlTokenBoolean True)-    it "string at beginning should produce one bit" $-      parseXmlToken' "\"hello\" " `shouldBe` Right (XmlTokenString "hello")-    it "quoted string should parse" $-      parseXmlToken' "\"\\\"\" " `shouldBe` Right (XmlTokenString "\"")-    it "left brace at beginning should produce one bit" $-      parseXmlToken' "{ " `shouldBe` Right XmlTokenBraceL-    it "right brace at beginning should produce one bit" $-      parseXmlToken' "} " `shouldBe` Right XmlTokenBraceR-    it "left bracket at beginning should produce one bit" $-      parseXmlToken' "[ " `shouldBe` Right XmlTokenBracketL-    it "right bracket at beginning should produce one bit" $-      parseXmlToken' "] " `shouldBe` Right XmlTokenBracketR-    it "right bracket at beginning should produce one bit" $-      parseXmlToken' ": " `shouldBe` Right XmlTokenColon-    it "right bracket at beginning should produce one bit" $-      parseXmlToken' ", " `shouldBe` Right XmlTokenComma+    it "Empty Xml should produce no bits" $ requireTest $+      parseXmlToken' "" === Left "not enough input"+    it "Xml with one space should produce whitespace token" $ requireTest $+      parseXmlToken' " " === Right XmlTokenWhitespace+    it "Xml with two spaces should produce whitespace token" $ requireTest $+      parseXmlToken' "  " === Right XmlTokenWhitespace+    it "Spaces and newlines should produce no bits" $ requireTest $+      parseXmlToken' "  \n \r \t " === Right XmlTokenWhitespace+    it "`null` at beginning should produce one bit" $ requireTest $+      parseXmlToken' "null " === Right XmlTokenNull+    it "number at beginning should produce one bit" $ requireTest $+      parseXmlToken' "1234 " === Right (XmlTokenNumber 1234)+    it "false at beginning should produce one bit" $ requireTest $+      parseXmlToken' "false " === Right (XmlTokenBoolean False)+    it "true at beginning should produce one bit" $ requireTest $+      parseXmlToken' "true " === Right (XmlTokenBoolean True)+    it "string at beginning should produce one bit" $ requireTest $+      parseXmlToken' "\"hello\" " === Right (XmlTokenString "hello")+    it "quoted string should parse" $ requireTest $+      parseXmlToken' "\"\\\"\" " === Right (XmlTokenString "\"")+    it "left brace at beginning should produce one bit" $ requireTest $+      parseXmlToken' "{ " === Right XmlTokenBraceL+    it "right brace at beginning should produce one bit" $ requireTest $+      parseXmlToken' "} " === Right XmlTokenBraceR+    it "left bracket at beginning should produce one bit" $ requireTest $+      parseXmlToken' "[ " === Right XmlTokenBracketL+    it "right bracket at beginning should produce one bit" $ requireTest $+      parseXmlToken' "] " === Right XmlTokenBracketR+    it "right bracket at beginning should produce one bit" $ requireTest $+      parseXmlToken' ": " === Right XmlTokenColon+    it "right bracket at beginning should produce one bit" $ requireTest $+      parseXmlToken' ", " === Right XmlTokenComma
test/HaskellWorks/Data/Xml/TypeSpec.hs view
@@ -7,7 +7,8 @@ {-# LANGUAGE OverloadedStrings         #-} {-# LANGUAGE ScopedTypeVariables       #-} -{-# OPTIONS_GHC -fno-warn-missing-signatures #-}+{-# OPTIONS_GHC -fno-warn-missing-signatures              #-}+{-# OPTIONS_GHC -fno-warn-simplifiable-class-constraints  #-}  module HaskellWorks.Data.Xml.TypeSpec (spec) where @@ -18,14 +19,14 @@ import HaskellWorks.Data.BalancedParens.Simple import HaskellWorks.Data.Bits.BitShown import HaskellWorks.Data.Bits.BitWise-import HaskellWorks.Data.FromForeignRegion import HaskellWorks.Data.RankSelect.Base.Rank0 import HaskellWorks.Data.RankSelect.Base.Rank1 import HaskellWorks.Data.RankSelect.Base.Select1 import HaskellWorks.Data.RankSelect.Poppy512 import HaskellWorks.Data.Xml.Succinct.Cursor           as C-import HaskellWorks.Data.Xml.Succinct.Index import HaskellWorks.Data.Xml.Type+import HaskellWorks.Hspec.Hedgehog+import Hedgehog import Test.Hspec  import qualified Data.ByteString              as BS@@ -41,76 +42,44 @@  spec :: Spec spec = describe "HaskellWorks.Data.Xml.TypeSpec" $ do-  describe "Cursor for [Bool]" $ do-    it "initialises to beginning of empty object" $ do-      let cursor = "<elem />" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      xmlTypeAt cursor `shouldBe` Just XmlTypeElement-    it "initialises to beginning of empty object preceded by spaces" $ do-      let cursor = " <elem />" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      xmlTypeAt cursor `shouldBe` Just XmlTypeElement-    it "cursor can navigate to attr list" $ do-      let cursor = "<a foo='bar' boo='buzz'/>" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      (fc >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeAttrList-    it "cursor can navigate through attrs" $ do-      let cursor = "<a foo='bar' boo='buzz'/>" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      (fc >=> fc >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeToken --foo-      (fc >=> fc >=> ns >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeToken --bar-      (fc >=> fc >=> ns >=> ns >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeToken --boo-      (fc >=> fc >=> ns >=> ns >=> ns >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeToken --buzz-      (fc >=> fc >=> ns >=> ns >=> ns >=> ns >=> xmlTypeAt) cursor `shouldBe` Nothing --back off!-    it "cursor can navigate to children" $ do-      let cursor = "<a><b /><c /></a>" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      (fc >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeElement --b-      (fc >=> ns >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeElement --c-      (fc >=> ns >=> ns >=> xmlTypeAt) cursor `shouldBe` Nothing --back off!-    it "cursor recognises child element as an element child next to attr list" $ do-      let cursor = "<a foo='bar'><inner /></a>" :: XmlCursor String (BitShown [Bool]) (SimpleBalancedParens [Bool])-      (fc >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeAttrList-      (fc >=> ns >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeElement-      (fc >=> ns >=> ns >=> xmlTypeAt) cursor `shouldBe` Nothing -- no more!--  genSpec "DVS.Vector Word8"  (undefined :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word8)) (SimpleBalancedParens (DVS.Vector Word8)))+  genSpec "DVS.Vector Word8"  (undefined :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word8 )) (SimpleBalancedParens (DVS.Vector Word8 )))   genSpec "DVS.Vector Word16" (undefined :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word16)) (SimpleBalancedParens (DVS.Vector Word16)))   genSpec "DVS.Vector Word32" (undefined :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word32)) (SimpleBalancedParens (DVS.Vector Word32)))   genSpec "DVS.Vector Word64" (undefined :: XmlCursor BS.ByteString (BitShown (DVS.Vector Word64)) (SimpleBalancedParens (DVS.Vector Word64)))   genSpec "Poppy512"          (undefined :: XmlCursor BS.ByteString Poppy512 (SimpleBalancedParens (DVS.Vector Word64)))  genSpec :: forall t u.-  ( Eq                t-  , Show              t+  ( Show              t   , Select1           t-  , Eq                u   , Show              u   , Rank0             u   , Rank1             u   , BalancedParens    u   , TestBit           u-  , FromForeignRegion (XmlCursor BS.ByteString t u)   , IsString          (XmlCursor BS.ByteString t u)-  , XmlIndexAt        (XmlCursor BS.ByteString t u)   )   => String -> (XmlCursor BS.ByteString t u) -> SpecWith () genSpec t _ = do   describe ("XML cursor of type " ++ t) $ do     let forXml (cursor :: XmlCursor BS.ByteString t u) f = describe ("of value " ++ show cursor) (f cursor)     forXml "<elem/>" $ \cursor -> do-      it "should have correct type"       $         xmlTypeAt  cursor `shouldBe` Just XmlTypeElement+      it "should have correct type" . requireTest $ xmlTypeAt cursor === Just XmlTypeElement     forXml " <elem />" $ \cursor -> do-      it "should have correct type"       $         xmlTypeAt  cursor `shouldBe` Just XmlTypeElement+      it "should have correct type" . requireTest $ xmlTypeAt cursor === Just XmlTypeElement     forXml "<a foo='bar' boo='buzz'><inner data='none' /></a>" $ \cursor -> do-      it "cursor can navigate to second attribute" $ do-        (fc >=> fc >=> ns >=> ns >=> xmlTypeAt)  cursor  `shouldBe` Just XmlTypeToken-      it "cursor can navigate to first attribute of an inner element" $ do-        (fc >=> ns >=> fc >=> fc >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeToken-      it "cursor can navigate to first atrribute value of an inner element" $ do-        (fc >=> ns >=> fc >=> fc >=> ns >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeToken+      it "cursor can navigate to second attribute" $ requireTest $ do+        (fc >=> fc >=> ns >=> ns >=> xmlTypeAt)  cursor  === Just XmlTypeToken+      it "cursor can navigate to first attribute of an inner element" $ requireTest $ do+        (fc >=> ns >=> fc >=> fc >=> xmlTypeAt) cursor === Just XmlTypeToken+      it "cursor can navigate to first atrribute value of an inner element" $ requireTest $ do+        (fc >=> ns >=> fc >=> fc >=> ns >=> xmlTypeAt) cursor === Just XmlTypeToken     describe "For a single element" $ do       let cursor =  "<a>text</a>" :: XmlCursor BS.ByteString t u-      it "can navigate down and forwards" $ do-        (                     xmlTypeAt) cursor `shouldBe` Just XmlTypeElement-        (fc               >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeToken-        (fc >=> ns        >=> xmlTypeAt) cursor `shouldBe` Nothing-        (fc >=> ns >=> ns >=> xmlTypeAt) cursor `shouldBe` Nothing+      it "can navigate down and forwards" $ requireTest $ do+        (                     xmlTypeAt) cursor === Just XmlTypeElement+        (fc               >=> xmlTypeAt) cursor === Just XmlTypeToken+        (fc >=> ns        >=> xmlTypeAt) cursor === Nothing+        (fc >=> ns >=> ns >=> xmlTypeAt) cursor === Nothing     describe "For sample Xml" $ do       let cursor = "<widget debug=\"on\"> \                     \  <window name=\"main_window\"> \@@ -119,12 +88,12 @@                     \    <dimension>    false   </dimension> \                     \  </window> \                     \</widget>" :: XmlCursor BS.ByteString t u-      it "can navigate down and forwards" $ do-        (                                                                      xmlTypeAt) cursor `shouldBe` Just XmlTypeElement     --widget-        (fc                                                                >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeAttrList    --widget attrs-        (fc >=> ns                                                         >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeElement     --window-        (fc >=> ns >=> fc                                                  >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeAttrList    --window attrs-        (fc >=> ns >=> fc >=> ns                                           >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeElement     --dimension 500-        (fc >=> ns >=> fc >=> ns >=> ns                                    >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeElement     --dimension 600-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns                             >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeElement     --dimension false-        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc                      >=> xmlTypeAt) cursor `shouldBe` Just XmlTypeToken       --false+      it "can navigate down and forwards" $ requireTest $ do+        (                                                 xmlTypeAt) cursor === Just XmlTypeElement     --widget+        (fc                                           >=> xmlTypeAt) cursor === Just XmlTypeAttrList    --widget attrs+        (fc >=> ns                                    >=> xmlTypeAt) cursor === Just XmlTypeElement     --window+        (fc >=> ns >=> fc                             >=> xmlTypeAt) cursor === Just XmlTypeAttrList    --window attrs+        (fc >=> ns >=> fc >=> ns                      >=> xmlTypeAt) cursor === Just XmlTypeElement     --dimension 500+        (fc >=> ns >=> fc >=> ns >=> ns               >=> xmlTypeAt) cursor === Just XmlTypeElement     --dimension 600+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns        >=> xmlTypeAt) cursor === Just XmlTypeElement     --dimension false+        (fc >=> ns >=> fc >=> ns >=> ns >=> ns >=> fc >=> xmlTypeAt) cursor === Just XmlTypeToken       --false