module Data.Columbia.WithAddress (WithAddress, addressOf, dataOf, withAddresses, writeBackAddresses) where
import Data.Word
import Data.Function
import Data.Generics.SYB.WithClass.Basics
import Data.Copointed
import Data.Pointed
import Generics.Pointless.Functors hiding (Functor)
import Control.Monad
import Control.Monad.Reader
import Data.Columbia.CompoundData
import Data.Columbia.CycleDetection
import Data.Columbia.FRecord
import Data.Columbia.Integral
data WithAddress t = WithAddress Word32 t
deriving (Eq, Ord, Show, Typeable)
instance Copointed WithAddress where
copoint(WithAddress _ x) = x
instance Pointed WithAddress where
point = WithAddress 0
addressOf :: WithAddress t -> Word32
addressOf(WithAddress n _) = n
dataOf :: WithAddress t -> t
dataOf = copoint
instance (Sat(ctx Word32), Sat(ctx(WithAddress t)), Data ctx t) => Data ctx(WithAddress t) where
gfoldl _ o k (WithAddress n x) = k WithAddress `o` n `o` x
gunfold _ f k _ = f(f(k WithAddress))
dataTypeOf proxy _ =
let ty = DataType "Data.Columbia.WithAddresses.WithAddress" (AlgRep[
Constr(AlgConstr 1) "WithAddress" [] Prefix ty]) in
ty
toConstr proxy x = case dataTypeOf proxy x of
DataType _(AlgRep ls) -> head ls
dataCast1 _ f = gcast1 f
instance (Typeable t) => RW(WithAddress t)
instance KeyComparable(WithAddress t) where
isKeyed (WithAddress 0 _) = False
isKeyed _ = True
keyCompare = compare `on` addressOf
withAddresses :: forall ctx m d. (Data ctx d, Monad m) => PolyTraversal ctx m d
withAddresses proxy m = case dataCast1 proxy(do
addr <- readIntegral
relSeek(4)
liftM(WithAddress addr) m) of
Just m2 -> m2
Nothing -> m
newtype Fl m t = Fl { unFl :: t -> ReaderT(SeekableWriter m Word8) m () }
writeBackAddresses :: forall ctx m d. (Data ctx d, Monad m) => PolyTraversalW ctx m d
writeBackAddresses proxy f d = case dataCast1 proxy(Fl$ \d2 -> if addressOf d2==0 then f$dataOf d2 else writeIntegral$addressOf d2) of
Just fl -> unFl fl d
Nothing -> f d