module Data.Bitstream.Internal
( packPackets
, lePacketsFromNBits
, bePacketsFromNBits
, lePacketsToBits
, bePacketsToBits
)
where
import Data.Bits
import Data.Bitstream.Generic
import Data.Bitstream.Packet
import Data.Vector.Fusion.Stream.Monadic (Stream(..), Step(..))
import Data.Vector.Fusion.Stream.Size
import Prelude hiding (length, null)
import Prelude.Unicode
packPackets ∷ (Bitstream (Packet d), Monad m) ⇒ Stream m Bool → Stream m (Packet d)
packPackets (Stream step s0 sz) = Stream step' ((∅), Just s0) sz'
where
sz' ∷ Size
sz' = case sz of
Exact n → Exact ((n+7) `div` 8)
Max n → Max ((n+7) `div` 8)
Unknown → Unknown
step' (p, Just s)
= do r ← step s
case r of
Yield b s'
| full p → return $ Yield p (singleton b, Just s')
| otherwise → return $ Skip (p `snoc` b , Just s')
Skip s' → return $ Skip (p , Just s')
Done
| null p → return Done
| otherwise → return $ Yield p ((⊥) , Nothing)
step' (_, Nothing)
= return Done
nOctets ∷ Integral n ⇒ n → Int
nOctets nBits
= (fromIntegral nBits + 7) `div` 8
lePacketsFromNBits ∷ ( Integral n
, Integral β
, Bits β
, Monad m
)
⇒ n
→ β
→ Stream m (Packet Left)
lePacketsFromNBits n0 β0 = Stream step (n0, β0) (Exact (nOctets n0))
where
step (n, β)
| n > 0
= let !n' = min 8 n
!n'' = n n'
!p = fromNBits n' β
!β' = β `shiftR` 8
in
return $ Yield p (n'', β')
| otherwise
= return Done
bePacketsFromNBits ∷ ( Integral n
, Integral β
, Bits β
, Monad m
)
⇒ n
→ β
→ Stream m (Packet Right)
bePacketsFromNBits n0 β = Stream step (n0, nOctets n0 ⋅ 8) (Exact (nOctets n0))
where
step (n, r)
| n > 0
= let !r' = r 8
!n' = n fromIntegral r'
!n'' = n n'
!p = fromNBits n' (β `shiftR` r')
in
return $ Yield p (n'', r')
| otherwise
= return Done
lePacketsToBits ∷ (Monad m, Bits β) ⇒ Stream m (Packet Left) → m β
lePacketsToBits (Stream step s0 _) = go (s0, 0, 0)
where
go (s, o, n)
= do r ← step s
case r of
Yield p s' → let !n' = (toBits p `shiftL` o) .|. n
!o' = o + length p
in
go (s', o', n')
Skip s' → go (s', o, n)
Done → return n
bePacketsToBits ∷ (Monad m, Bits β) ⇒ Stream m (Packet Right) → m β
bePacketsToBits (Stream step s0 _) = go (s0, 0)
where
go (s, n)
= do r ← step s
case r of
Yield p s' → let !o = length p
!n' = (n `shiftL` o) .|. toBits p
in
go (s', n')
Skip s' → go (s', n)
Done → return n