packages feed

spire-protobuf-0.1.0.0: src/Spire/Protobuf/Field.hs

-- | Type-level field numbers for protobuf messages.
--
-- The 'Field' newtype embeds a compile-time field number (proto3 field tag)
-- into the type. At runtime it is a zero-cost wrapper (via 'coerce').
--
-- @
-- data User = User
--   { name :: Field 1 Text
--   , age  :: Field 2 Int32
--   }
-- @
module Spire.Protobuf.Field
  ( Field (..)
  , fieldVal
    -- * Signed integer wrappers (zigzag encoding)
  , SInt32 (..)
  , SInt64 (..)
    -- * Proto3 map fields
  , ProtoMap (..)
  ) where

import Data.Int (Int32, Int64)
import Data.Map.Strict (Map)
import GHC.TypeLits (Nat, KnownNat, natVal)
import Data.Proxy (Proxy(..))

-- | A protobuf field with a compile-time field number.
--
-- The field number is used for wire encoding; at runtime, 'Field' is
-- just a newtype wrapper (zero overhead via coerce).
newtype Field (n :: Nat) a = Field { unField :: a }
  deriving (Show, Eq, Ord, Functor)

-- | Get the field number at runtime.
fieldVal :: forall n a. KnownNat n => Field n a -> Int
fieldVal _ = fromIntegral (natVal (Proxy @n))
{-# INLINE fieldVal #-}


-- | Signed 32-bit integer using zigzag encoding on the wire.
-- Use for fields declared as @sint32@ in .proto files.
-- Zigzag encoding maps small-magnitude values (positive or negative)
-- to small varints, unlike plain @int32@ which uses 10 bytes for negatives.
newtype SInt32 = SInt32 { unSInt32 :: Int32 }
  deriving (Show, Eq, Ord)

-- | Signed 64-bit integer using zigzag encoding on the wire.
-- Use for fields declared as @sint64@ in .proto files.
newtype SInt64 = SInt64 { unSInt64 :: Int64 }
  deriving (Show, Eq, Ord)


-- | Proto3 map field: @map\<K, V\>@.
--
-- On the wire, a map is encoded as a repeated message where each entry
-- has field 1 = key and field 2 = value. This newtype wraps 'Map' and
-- provides the correct protobuf encoding/decoding.
--
-- @
-- data Config = Config
--   { settings :: Field 1 (ProtoMap Text Text)
--   , counts   :: Field 2 (ProtoMap Text Int32)
--   } deriving (Generic)
-- instance ProtoMessage Config
-- @
newtype ProtoMap k v = ProtoMap { unProtoMap :: Map k v }
  deriving (Show, Eq, Ord)