packages feed

moonlight-core-0.1.0.0: src-numeric/Moonlight/Core/ExactToken.hs

{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE UnboxedTuples #-}

-- | Self-delimiting byte encodings of exact values: an 'ExactToken' is the canonical serialized witness used for structural identity.
module Moonlight.Core.ExactToken
  ( ExactToken,
    ExactEncoding,
    ExactEncodingAtom (..),
    ExactEncodingError (..),
    exactTokenFromEncoding,
    exactTokenBytes,
    exactTokenLength,
    exactEncodingLength,
    exactAtomEncoding,
    exactSequenceEncoding,
    exactSequenceMapEncoding,
  )
where

import Data.Bits (shiftR)
import Data.ByteString.Short.Internal (ShortByteString (SBS))
import Data.ByteString.Short.Internal qualified as ShortByteString
import Data.Foldable (foldr)
import Data.Int (Int64)
import Data.Kind (Type)
import Data.Word (Word64)
import GHC.Exts
  ( Int (I#),
    Int#,
    MutableByteArray#,
    State#,
    newByteArray#,
    unsafeFreezeByteArray#,
    writeWord8Array#,
    (<#),
    (+#),
  )
import GHC.ST (ST (..), runST)
import GHC.Word (Word8 (W8#))
import Prelude
  ( Bool (False),
    Either (..),
    Eq (..),
    Foldable,
    Ord (..),
    Ordering (GT, LT),
    Show (..),
    fromIntegral,
    id,
    (<>),
  )

type ExactToken :: Type
data ExactToken
  = CompactExactToken !ShortByteString
  | OversizedExactToken ExactStructure

instance Eq ExactToken where
  left == right =
    case (left, right) of
      (CompactExactToken leftBytes, CompactExactToken rightBytes) -> leftBytes == rightBytes
      (OversizedExactToken leftStructure, OversizedExactToken rightStructure) -> leftStructure == rightStructure
      _ -> False

instance Ord ExactToken where
  compare left right =
    case (left, right) of
      (CompactExactToken leftBytes, CompactExactToken rightBytes) -> compare leftBytes rightBytes
      (OversizedExactToken leftStructure, OversizedExactToken rightStructure) -> compare leftStructure rightStructure
      (CompactExactToken _, OversizedExactToken _) -> LT
      (OversizedExactToken _, CompactExactToken _) -> GT

instance Show ExactToken where
  show token =
    case token of
      CompactExactToken bytes -> "ExactToken " <> show bytes
      OversizedExactToken structure -> "OversizedExactToken " <> show structure

type ExactEncoding :: Type
data ExactEncoding = ExactEncoding ExactStructure {-# UNPACK #-} !ExactLength ExactEncodingWriter

type ExactStructure :: Type
data ExactStructure
  = ExactAtomStructure !ExactEncodingAtom
  | ExactSequenceStructure [ExactStructure]
  deriving stock (Eq, Ord, Show)

type ExactLength :: Type
data ExactLength
  = ValidExactLength Int#
  | ExactLengthOverflow

type ExactEncodingAtom :: Type
data ExactEncodingAtom
  = ExactWord8 Word8
  | ExactInt Int
  deriving stock (Eq, Ord, Show)

type ExactEncodingError :: Type
data ExactEncodingError
  = ExactEncodingLengthExceedsPlatformLimit
  deriving stock (Eq, Show)

exactTokenFromEncoding :: ExactEncoding -> ExactToken
exactTokenFromEncoding (ExactEncoding structure byteLength writer) =
  case byteLength of
    ValidExactLength validByteLength ->
      CompactExactToken (sealExactEncoding# validByteLength writer)
    ExactLengthOverflow ->
      OversizedExactToken structure

exactTokenBytes :: ExactToken -> Either ExactEncodingError ShortByteString
exactTokenBytes token =
  case token of
    CompactExactToken bytes -> Right bytes
    OversizedExactToken _structure -> Left ExactEncodingLengthExceedsPlatformLimit

exactTokenLength :: ExactToken -> Either ExactEncodingError Int
exactTokenLength token =
  case token of
    CompactExactToken bytes -> Right (ShortByteString.length bytes)
    OversizedExactToken _structure -> Left ExactEncodingLengthExceedsPlatformLimit

exactEncodingLength :: ExactEncoding -> Either ExactEncodingError Int
exactEncodingLength (ExactEncoding _structure byteLength _writer) =
  case byteLength of
    ValidExactLength validByteLength -> Right (I# validByteLength)
    ExactLengthOverflow -> Left ExactEncodingLengthExceedsPlatformLimit

exactAtomEncoding :: ExactEncodingAtom -> ExactEncoding
exactAtomEncoding atom =
  case atom of
    ExactWord8 byteValue ->
      ExactEncoding
        (ExactAtomStructure atom)
        (ValidExactLength 2#)
        (writeExactWord8 0x01 `appendExactEncodingWriter` writeExactWord8 byteValue)
    ExactInt intValue ->
      ExactEncoding
        (ExactAtomStructure atom)
        (ValidExactLength 9#)
        (writeExactWord8 0x02 `appendExactEncodingWriter` exactInt64BEWriter intValue)
{-# INLINE exactAtomEncoding #-}

-- The grammar is prefix-decodable: atoms have fixed payload widths, while
-- 0x03 and 0x04 delimit a sequence. Recursive decoding therefore determines
-- every child boundary without redundant per-child lengths.
exactSequenceEncoding :: Foldable values => values ExactEncoding -> ExactEncoding
exactSequenceEncoding =
  exactSequenceMapEncoding id
{-# INLINE exactSequenceEncoding #-}

exactSequenceMapEncoding :: Foldable values => (value -> ExactEncoding) -> values value -> ExactEncoding
exactSequenceMapEncoding project values =
  let SequenceEncoding childByteLength childWriter =
        foldr
          (\value suffix -> prependSequenceEncoding (project value) suffix)
          emptySequenceEncoding
          values
   in ExactEncoding
        ( ExactSequenceStructure
            (foldr (\value suffix -> exactEncodingStructure (project value) : suffix) [] values)
        )
        (checkedLengthAdd (ValidExactLength 2#) childByteLength)
        ( writeExactWord8 0x03
            `appendExactEncodingWriter` childWriter
            `appendExactEncodingWriter` writeExactWord8 0x04
        )
{-# INLINE exactSequenceMapEncoding #-}

type SequenceEncoding :: Type
data SequenceEncoding = SequenceEncoding {-# UNPACK #-} !ExactLength ExactEncodingWriter

emptySequenceEncoding :: SequenceEncoding
emptySequenceEncoding =
  SequenceEncoding (ValidExactLength 0#) emptyExactEncodingWriter

prependSequenceEncoding :: ExactEncoding -> SequenceEncoding -> SequenceEncoding
prependSequenceEncoding (ExactEncoding _structure childByteLength childWriter) (SequenceEncoding suffixByteLength suffixWriter) =
  SequenceEncoding
    (checkedLengthAdd childByteLength suffixByteLength)
    (appendExactEncodingWriter childWriter suffixWriter)
{-# INLINE prependSequenceEncoding #-}

exactEncodingStructure :: ExactEncoding -> ExactStructure
exactEncodingStructure (ExactEncoding structure _byteLength _writer) =
  structure

checkedLengthAdd :: ExactLength -> ExactLength -> ExactLength
checkedLengthAdd left right =
  case (left, right) of
    (ValidExactLength leftValue#, ValidExactLength rightValue#) ->
      case leftValue# +# rightValue# of
        sumValue# ->
          case sumValue# <# 0# of
            0# -> ValidExactLength sumValue#
            _ -> ExactLengthOverflow
    _ -> ExactLengthOverflow
{-# INLINE checkedLengthAdd #-}

exactInt64BEWriter :: Int -> ExactEncodingWriter
exactInt64BEWriter intValue =
  writeExactWord64BE (fromIntegral (fromIntegral intValue :: Int64))

sealExactEncoding# :: Int# -> ExactEncodingWriter -> ShortByteString
sealExactEncoding# byteLength# writer =
  runST (ST createExactTokenBytes)
  where
    createExactTokenBytes :: State# s -> (# State# s, ShortByteString #)
    createExactTokenBytes state0 =
      case newByteArray# byteLength# state0 of
        (# state1, mutableBytes #) ->
          case writer mutableBytes 0# state1 of
            (# state2, _endOffset #) ->
              case unsafeFreezeByteArray# mutableBytes state2 of
                (# state3, frozenBytes #) -> (# state3, SBS frozenBytes #)

type ExactEncodingWriter :: Type
type ExactEncodingWriter =
  forall s.
  MutableByteArray# s ->
  Int# ->
  State# s ->
  (# State# s, Int# #)

appendExactEncodingWriter :: ExactEncodingWriter -> ExactEncodingWriter -> ExactEncodingWriter
appendExactEncodingWriter leftWriter rightWriter mutableBytes offset state0 =
  case leftWriter mutableBytes offset state0 of
    (# state1, offset1 #) -> rightWriter mutableBytes offset1 state1

emptyExactEncodingWriter :: ExactEncodingWriter
emptyExactEncodingWriter _mutableBytes offset state =
  (# state, offset #)

writeExactWord64BE :: Word64 -> ExactEncodingWriter
writeExactWord64BE wordValue =
  writeExactWord8 (fromIntegral (wordValue `shiftR` 56))
    `appendExactEncodingWriter` writeExactWord8 (fromIntegral (wordValue `shiftR` 48))
    `appendExactEncodingWriter` writeExactWord8 (fromIntegral (wordValue `shiftR` 40))
    `appendExactEncodingWriter` writeExactWord8 (fromIntegral (wordValue `shiftR` 32))
    `appendExactEncodingWriter` writeExactWord8 (fromIntegral (wordValue `shiftR` 24))
    `appendExactEncodingWriter` writeExactWord8 (fromIntegral (wordValue `shiftR` 16))
    `appendExactEncodingWriter` writeExactWord8 (fromIntegral (wordValue `shiftR` 8))
    `appendExactEncodingWriter` writeExactWord8 (fromIntegral wordValue)

writeExactWord8 :: Word8 -> ExactEncodingWriter
writeExactWord8 (W8# byteValue) mutableBytes offset state0 =
  case writeWord8Array# mutableBytes offset byteValue state0 of
    state1 -> (# state1, offset +# 1# #)