moonlight-planar-1.1.0.0: test/serialization/Moonlight/Planar/SerializationV6Oracle.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GADTs #-}
{-# OPTIONS_GHC -fexpose-all-unfoldings #-}
-- | Test-only V6 wire oracle retained from the gathered encoder. It deliberately
-- does not call the production encoder or the new storage producers.
-- Its unfolding visibility matches the serialize component so the benchmark
-- compares both encoders under the same cross-module specialization policy.
module Moonlight.Planar.SerializationV6Oracle (encodeV6Gathered) where
import Data.Binary (Binary (..))
import Data.Binary.Put
( putDoublebe, putWord16be, putWord32be, putWord64be, putWord8, runPut )
import qualified Data.ByteString.Lazy as BL
import Data.Proxy (Proxy (..))
import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as U
import Data.Word (Word16, Word64, Word8)
import Moonlight.Planar.Internal.BoxedPaged (BoxedFill (..), boxedFill, boxedToVector)
import Moonlight.Planar.Internal.Paged (toVector)
import Moonlight.Planar.Internal.Representation (Triangulation (..), authoringElementDefaults)
import Moonlight.Planar.Internal.Types
( ConstraintMode (..), ElementDefaults (..), KnownConstraintMode (..) )
formatMagic :: Word64
formatMagic = 0x5350414445485307
serializationVersion :: Word16
serializationVersion = 6
binary64EncodingTag :: Word8
binary64EncodingTag = 2
modeProxy :: Triangulation mode vertex directed undirected face -> Proxy mode
modeProxy _ = Proxy
modeTag :: ConstraintMode -> Word8
modeTag Unconstrained = 0
modeTag Constrained = 1
encodeV6Gathered
:: forall mode vertex directed undirected face. (KnownConstraintMode mode, Binary vertex, Binary directed, Binary undirected, Binary face)
=> Triangulation mode vertex directed undirected face
-> BL.ByteString
encodeV6Gathered triangulation = runPut $ do
putWord64be formatMagic
putWord16be serializationVersion
putWord8 (modeTag (constraintModeValue (modeProxy triangulation)))
putWord8 binary64EncodingTag
let ElementDefaults directedDefault undirectedDefault faceDefault = authoringElementDefaults triangulation
pointXs = toVector (triPointX triangulation)
pointYs = toVector (triPointY triangulation)
vertexDefault = case boxedFill (triVertexData triangulation) of
NoFill -> Nothing
Fill value -> Just value
vertexDataVector = boxedToVector (triVertexData triangulation)
vertexOut = toVector (triVertexOut triangulation)
topology = toVector (triHalfTopology triangulation)
directedDataVector = boxedToVector (triDirectedData triangulation)
undirectedDataVector = boxedToVector (triUndirectedData triangulation)
faceEdge = toVector (triFaceEdge triangulation)
faceDataVector = boxedToVector (triFaceData triangulation)
constraints = toVector (triConstraint triangulation)
vertexCount = U.length pointXs
directedEdgeCount = U.length topology `quot` 4
faceCount = U.length faceEdge
-- Version 6 commits every structural count in one prefix. The decoder can
-- prove their relationships and resource bounds before defaults, payloads,
-- or section bodies are evaluated.
putWord64be (fromIntegral vertexCount)
putWord64be (fromIntegral directedEdgeCount)
putWord64be (fromIntegral faceCount)
putWord64be (fromIntegral (triConstraintCount triangulation))
put directedDefault
put undirectedDefault
put faceDefault
-- Geometry and payloads are independent components. Persist the authoritative
-- coordinate pages rather than attempting to recover them from annotations.
U.mapM_ putDoublebe pointXs
U.mapM_ putDoublebe pointYs
put vertexDefault
V.mapM_ put vertexDataVector
U.mapM_ putWord32be vertexOut
-- The wire format stores the four topology planes separately; the interleaved
-- arena is a resident layout, not a serialization concern.
let plane field = U.generate directedEdgeCount (\edge -> topology U.! (4 * edge + field))
U.mapM_ putWord32be (plane 0)
U.mapM_ putWord32be (plane 1)
U.mapM_ putWord32be (plane 2)
U.mapM_ putWord32be (plane 3)
V.mapM_ put directedDataVector
V.mapM_ put undirectedDataVector
U.mapM_ putWord32be faceEdge
V.mapM_ put faceDataVector
U.mapM_ putWord8 constraints