module Data.Serialize.Describe.Combinators.FText where import GHC.TypeNats import Data.Word import Data.Char import Data.String import Data.Proxy import Data.Text (Text) import qualified Data.Text as T import Data.Serialize.Describe.Descriptor import Data.Serialize.Describe.Class import Control.Monad import Control.Monad.Trans.Class -- | A fixed text descriptor which reads a fixed amount of bytes, discarding all trailing '\0' characters. Upon serializing, the text will either be truncated to the specified fixed length, or padded with '\0' characters to meet it. ftext :: (MonadTrans m, forall x. Monad x => Monad (m x)) => Int -> (s -> Text) -> DescriptorM m s Text ftext maxLen f = fmap (T.takeWhile (/= '\0') . fromString . (fmap (chr . fromIntegral))) <$> forM [0..maxLen-1] $ \i -> field $ \s -> let t = f s p = (<> T.replicate (maxLen - T.length t) "\0") . T.take maxLen $ t in fromIntegral @_ @Word8 . ord $ T.index p i -- | Type-level variant of @ftext@. newtype KnownNat n => FText n = FText { unwrapFText :: Text } deriving (Show) via Text instance KnownNat n => IsString (FText n) where fromString = FText . T.pack instance KnownNat n => Describe (FText n) where describe = FText <$> ftext (fromIntegral (natVal (Proxy :: Proxy n))) unwrapFText