binrep 0.1.0 → 0.2.0
raw patch · 44 files changed
+3240/−423 lines, 44 filesdep +QuickCheckdep +binrepdep +eitherdep −cerealdep −refined-withdep ~refinedPVP ok
version bump matches the API change (PVP)
Dependencies added: QuickCheck, binrep, either, flatparse, generic-random, hspec, mason, megaparsec, quickcheck-instances, strongweak, text-icu, vector, vector-sized
Dependencies removed: cereal, refined-with
Dependency ranges changed: refined
API changes (from Hackage documentation)
- Binrep.ByteLen: blen :: ByteLen a => a -> Natural
- Binrep.ByteLen: class ByteLen a
- Binrep.ByteLen: instance Binrep.ByteLen.ByteLen a => Binrep.ByteLen.ByteLen [a]
- Binrep.Codec: binDecode :: BinaryCodec a => ByteString -> Either String a
- Binrep.Codec: binDecodeWith :: BinaryCodecWith r a => r -> ByteString -> Either String a
- Binrep.Codec: binEncode :: BinaryCodec a => a -> ByteString
- Binrep.Codec: binEncodeWith :: BinaryCodecWith r a => r -> a -> Either String ByteString
- Binrep.Codec: class BinaryCodec a
- Binrep.Codec: class BinaryCodecWith r a
- Binrep.Codec: fromBin :: BinaryCodec a => Get a
- Binrep.Codec: fromBinWith :: (BinaryCodecWith r a, BinaryCodec a) => r -> Get a
- Binrep.Codec: instance Binrep.Codec.BinaryCodec a => Binrep.Codec.BinaryCodec [a]
- Binrep.Codec: toBin :: BinaryCodec a => Putter a
- Binrep.Codec: toBinWith :: (BinaryCodecWith r a, BinaryCodec a) => r -> a -> Either String Builder
- Binrep.Predicates.NullPadTo: data NullPadTo (n :: Nat)
- Binrep.Predicates.NullPadTo: getNNulls :: Natural -> Get ()
- Binrep.Predicates.NullPadTo: instance (Binrep.ByteLen.ByteLen a, GHC.TypeNats.KnownNat n) => Refined.Predicate (Binrep.Predicates.NullPadTo.NullPadTo n) a
- Binrep.Predicates.NullPadTo: instance (Binrep.Codec.BinaryCodec a, Binrep.ByteLen.ByteLen a, GHC.TypeNats.KnownNat n) => Binrep.Codec.BinaryCodec (Refined.WithRefine.WithRefine 'Refined.WithRefine.Enforced (Binrep.Predicates.NullPadTo.NullPadTo n) a)
- Binrep.Predicates.NullPadTo: instance GHC.TypeNats.KnownNat n => Binrep.ByteLen.ByteLen (Refined.WithRefine.WithRefine 'Refined.WithRefine.Enforced (Binrep.Predicates.NullPadTo.NullPadTo n) a)
- Binrep.Types.Ints: BE :: Endianness
- Binrep.Types.Ints: I :: IRep sign size -> I (sign :: ISign) (size :: ISize) (e :: Endianness)
- Binrep.Types.Ints: I1 :: ISize
- Binrep.Types.Ints: I2 :: ISize
- Binrep.Types.Ints: I4 :: ISize
- Binrep.Types.Ints: I8 :: ISize
- Binrep.Types.Ints: LE :: Endianness
- Binrep.Types.Ints: S :: ISign
- Binrep.Types.Ints: U :: ISign
- Binrep.Types.Ints: [getI] :: I (sign :: ISign) (size :: ISize) (e :: Endianness) -> IRep sign size
- Binrep.Types.Ints: data Endianness
- Binrep.Types.Ints: data ISign
- Binrep.Types.Ints: data ISize
- Binrep.Types.Ints: instance Binrep.ByteLen.ByteLen (Binrep.Types.Ints.I s 'Binrep.Types.Ints.I1 e)
- Binrep.Types.Ints: instance Binrep.ByteLen.ByteLen (Binrep.Types.Ints.I s 'Binrep.Types.Ints.I2 e)
- Binrep.Types.Ints: instance Binrep.ByteLen.ByteLen (Binrep.Types.Ints.I s 'Binrep.Types.Ints.I4 e)
- Binrep.Types.Ints: instance Binrep.ByteLen.ByteLen (Binrep.Types.Ints.I s 'Binrep.Types.Ints.I8 e)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.S 'Binrep.Types.Ints.I1 e)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.S 'Binrep.Types.Ints.I2 'Binrep.Types.Ints.BE)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.S 'Binrep.Types.Ints.I2 'Binrep.Types.Ints.LE)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.S 'Binrep.Types.Ints.I4 'Binrep.Types.Ints.BE)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.S 'Binrep.Types.Ints.I4 'Binrep.Types.Ints.LE)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.S 'Binrep.Types.Ints.I8 'Binrep.Types.Ints.BE)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.S 'Binrep.Types.Ints.I8 'Binrep.Types.Ints.LE)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.U 'Binrep.Types.Ints.I1 e)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.U 'Binrep.Types.Ints.I2 'Binrep.Types.Ints.BE)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.U 'Binrep.Types.Ints.I2 'Binrep.Types.Ints.LE)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.U 'Binrep.Types.Ints.I4 'Binrep.Types.Ints.BE)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.U 'Binrep.Types.Ints.I4 'Binrep.Types.Ints.LE)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.U 'Binrep.Types.Ints.I8 'Binrep.Types.Ints.BE)
- Binrep.Types.Ints: instance Binrep.Codec.BinaryCodec (Binrep.Types.Ints.I 'Binrep.Types.Ints.U 'Binrep.Types.Ints.I8 'Binrep.Types.Ints.LE)
- Binrep.Types.Ints: instance Data.Aeson.Types.FromJSON.FromJSON (Binrep.Types.Ints.IRep sign size) => Data.Aeson.Types.FromJSON.FromJSON (Binrep.Types.Ints.I sign size e)
- Binrep.Types.Ints: instance Data.Aeson.Types.ToJSON.ToJSON (Binrep.Types.Ints.IRep sign size) => Data.Aeson.Types.ToJSON.ToJSON (Binrep.Types.Ints.I sign size e)
- Binrep.Types.Ints: instance GHC.Classes.Eq (Binrep.Types.Ints.IRep sign size) => GHC.Classes.Eq (Binrep.Types.Ints.I sign size e)
- Binrep.Types.Ints: instance GHC.Classes.Ord (Binrep.Types.Ints.IRep sign size) => GHC.Classes.Ord (Binrep.Types.Ints.I sign size e)
- Binrep.Types.Ints: instance GHC.Enum.Bounded (Binrep.Types.Ints.IRep sign size) => GHC.Enum.Bounded (Binrep.Types.Ints.I sign size e)
- Binrep.Types.Ints: instance GHC.Enum.Enum (Binrep.Types.Ints.IRep sign size) => GHC.Enum.Enum (Binrep.Types.Ints.I sign size e)
- Binrep.Types.Ints: instance GHC.Generics.Generic (Binrep.Types.Ints.I sign size e)
- Binrep.Types.Ints: instance GHC.Num.Num (Binrep.Types.Ints.IRep sign size) => GHC.Num.Num (Binrep.Types.Ints.I sign size e)
- Binrep.Types.Ints: instance GHC.Real.Integral (Binrep.Types.Ints.IRep sign size) => GHC.Real.Integral (Binrep.Types.Ints.I sign size e)
- Binrep.Types.Ints: instance GHC.Real.Real (Binrep.Types.Ints.IRep sign size) => GHC.Real.Real (Binrep.Types.Ints.I sign size e)
- Binrep.Types.Ints: instance GHC.Show.Show (Binrep.Types.Ints.IRep sign size) => GHC.Show.Show (Binrep.Types.Ints.I sign size e)
- Binrep.Types.Ints: newtype I (sign :: ISign) (size :: ISize) (e :: Endianness)
- Binrep.Types.Ints: type family IRep (sign :: ISign) (size :: ISize)
- Binrep.Types.Strings: C :: StrRep
- Binrep.Types.Strings: Pascal :: ISize -> Endianness -> StrRep
- Binrep.Types.Strings: Str :: ByteString -> Str (rep :: StrRep)
- Binrep.Types.Strings: [getStr] :: Str (rep :: StrRep) -> ByteString
- Binrep.Types.Strings: data StrRep
- Binrep.Types.Strings: data WellSized
- Binrep.Types.Strings: fromBinCString :: Get ByteString
- Binrep.Types.Strings: instance (Binrep.ByteLen.ByteLen a, itype GHC.Types.~ Binrep.Types.Ints.I 'Binrep.Types.Ints.U size e, Binrep.ByteLen.ByteLen itype) => Binrep.ByteLen.ByteLen (Refined.WithRefine.WithRefine 'Refined.WithRefine.Enforced (Binrep.Types.Strings.LenPfx size e) a)
- Binrep.Types.Strings: instance (Binrep.Codec.BinaryCodec a, irep GHC.Types.~ Binrep.Types.Ints.IRep 'Binrep.Types.Ints.U size, itype GHC.Types.~ Binrep.Types.Ints.I 'Binrep.Types.Ints.U size e, GHC.Num.Num irep, GHC.Real.Integral irep, Binrep.Codec.BinaryCodec itype) => Binrep.Codec.BinaryCodec (Refined.WithRefine.WithRefine 'Refined.WithRefine.Enforced (Binrep.Types.Strings.LenPfx size e) [a])
- Binrep.Types.Strings: instance (Data.Foldable.Foldable f, Data.Typeable.Internal.Typeable f, Data.Typeable.Internal.Typeable e) => Refined.Predicate (Binrep.Types.Strings.LenPfx 'Binrep.Types.Ints.I4 e) (f a)
- Binrep.Types.Strings: instance Binrep.ByteLen.ByteLen (Binrep.Types.Ints.I 'Binrep.Types.Ints.U size e) => Binrep.ByteLen.ByteLen (Binrep.Types.Strings.Str ('Binrep.Types.Strings.Pascal size e))
- Binrep.Types.Strings: instance Binrep.ByteLen.ByteLen (Binrep.Types.Strings.Str 'Binrep.Types.Strings.C)
- Binrep.Types.Strings: instance Binrep.Codec.BinaryCodec (Binrep.Types.Strings.Str 'Binrep.Types.Strings.C)
- Binrep.Types.Strings: instance Binrep.Codec.BinaryCodec (Refined.WithRefine.WithRefine 'Refined.WithRefine.Enforced Binrep.Types.Strings.WellSized (Binrep.Types.Strings.Str ('Binrep.Types.Strings.Pascal 'Binrep.Types.Ints.I1 e)))
- Binrep.Types.Strings: instance Binrep.Codec.BinaryCodecWith Binrep.Types.Strings.StrRep Data.ByteString.Internal.ByteString
- Binrep.Types.Strings: instance Binrep.Codec.BinaryCodecWith _r (Binrep.Types.Strings.Str 'Binrep.Types.Strings.C)
- Binrep.Types.Strings: newtype Str (rep :: StrRep)
- Binrep.Types.Strings: type LenPfx size e = Str ('Pascal size e)
+ Binrep.BLen: blen :: (BLen a, KnownNat (CBLen a)) => a -> BLenT
+ Binrep.BLen: cblen :: forall a n. (n ~ CBLen a, KnownNat n) => BLenT
+ Binrep.BLen: class BLen a
+ Binrep.BLen: instance (Binrep.BLen.BLen a, Binrep.BLen.BLen b) => Binrep.BLen.BLen (a, b)
+ Binrep.BLen: instance Binrep.BLen.BLen Data.ByteString.Internal.ByteString
+ Binrep.BLen: instance Binrep.BLen.BLen GHC.Int.Int16
+ Binrep.BLen: instance Binrep.BLen.BLen GHC.Int.Int32
+ Binrep.BLen: instance Binrep.BLen.BLen GHC.Int.Int64
+ Binrep.BLen: instance Binrep.BLen.BLen GHC.Int.Int8
+ Binrep.BLen: instance Binrep.BLen.BLen GHC.Word.Word16
+ Binrep.BLen: instance Binrep.BLen.BLen GHC.Word.Word32
+ Binrep.BLen: instance Binrep.BLen.BLen GHC.Word.Word64
+ Binrep.BLen: instance Binrep.BLen.BLen GHC.Word.Word8
+ Binrep.BLen: instance Binrep.BLen.BLen a => Binrep.BLen.BLen [a]
+ Binrep.BLen: type BLenT = Int
+ Binrep.BLen: typeNatToBLen :: forall n. KnownNat n => BLenT
+ Binrep.BLen.Internal.AsBLen: class AsBLen a
+ Binrep.BLen.Internal.AsBLen: instance Binrep.BLen.Internal.AsBLen.AsBLen GHC.Num.Natural.Natural
+ Binrep.BLen.Internal.AsBLen: instance Binrep.BLen.Internal.AsBLen.AsBLen GHC.Types.Int
+ Binrep.BLen.Internal.AsBLen: natToBLen :: AsBLen a => Natural -> a
+ Binrep.BLen.Internal.AsBLen: posIntToBLen :: AsBLen a => Int -> a
+ Binrep.BLen.Internal.AsBLen: safeBLenSub :: AsBLen a => a -> a -> Maybe a
+ Binrep.BLen.Internal.AsBLen: wordToBLen# :: AsBLen a => Word# -> a
+ Binrep.CBLen: type family CBLen a :: Natural
+ Binrep.Example: DCS1 :: DCS
+ Binrep.Example: DCS2 :: DCS
+ Binrep.Example: DCS3 :: DCS
+ Binrep.Example: DCS4 :: DCS
+ Binrep.Example: DCS5 :: DCS
+ Binrep.Example: DSS :: I 'U 'I1 'LE -> I 'U 'I2 'LE -> I 'U 'I4 'LE -> I 'U 'I8 'LE -> I 'U 'I1 'LE -> DSS
+ Binrep.Example: DU :: DU
+ Binrep.Example: DX :: DU -> DX
+ Binrep.Example: [dss1] :: DSS -> I 'U 'I1 'LE
+ Binrep.Example: [dss2] :: DSS -> I 'U 'I2 'LE
+ Binrep.Example: [dss3] :: DSS -> I 'U 'I4 'LE
+ Binrep.Example: [dss4] :: DSS -> I 'U 'I8 'LE
+ Binrep.Example: [dss5] :: DSS -> I 'U 'I1 'LE
+ Binrep.Example: brCfgDCS :: Cfg (I 'U 'I1 'LE)
+ Binrep.Example: brCfgNoSum :: Cfg (I 'U 'I1 'LE)
+ Binrep.Example: data DCS
+ Binrep.Example: data DSS
+ Binrep.Example: data DU
+ Binrep.Example: data DV
+ Binrep.Example: data DX
+ Binrep.Example: instance Binrep.BLen.BLen Binrep.Example.DCS
+ Binrep.Example: instance Binrep.BLen.BLen Binrep.Example.DSS
+ Binrep.Example: instance Binrep.BLen.BLen Binrep.Example.DU
+ Binrep.Example: instance Binrep.BLen.BLen Binrep.Example.DX
+ Binrep.Example: instance Binrep.Get.Get Binrep.Example.DCS
+ Binrep.Example: instance Binrep.Get.Get Binrep.Example.DSS
+ Binrep.Example: instance Binrep.Get.Get Binrep.Example.DU
+ Binrep.Example: instance Binrep.Put.Put Binrep.Example.DCS
+ Binrep.Example: instance Binrep.Put.Put Binrep.Example.DSS
+ Binrep.Example: instance Binrep.Put.Put Binrep.Example.DU
+ Binrep.Example: instance Data.Data.Data Binrep.Example.DCS
+ Binrep.Example: instance Data.Data.Data Binrep.Example.DSS
+ Binrep.Example: instance Data.Data.Data Binrep.Example.DU
+ Binrep.Example: instance Data.Data.Data Binrep.Example.DV
+ Binrep.Example: instance Data.Data.Data Binrep.Example.DX
+ Binrep.Example: instance GHC.Classes.Eq Binrep.Example.DCS
+ Binrep.Example: instance GHC.Classes.Eq Binrep.Example.DSS
+ Binrep.Example: instance GHC.Classes.Eq Binrep.Example.DU
+ Binrep.Example: instance GHC.Classes.Eq Binrep.Example.DX
+ Binrep.Example: instance GHC.Generics.Generic Binrep.Example.DCS
+ Binrep.Example: instance GHC.Generics.Generic Binrep.Example.DSS
+ Binrep.Example: instance GHC.Generics.Generic Binrep.Example.DU
+ Binrep.Example: instance GHC.Generics.Generic Binrep.Example.DV
+ Binrep.Example: instance GHC.Generics.Generic Binrep.Example.DX
+ Binrep.Example: instance GHC.Show.Show Binrep.Example.DCS
+ Binrep.Example: instance GHC.Show.Show Binrep.Example.DSS
+ Binrep.Example: instance GHC.Show.Show Binrep.Example.DU
+ Binrep.Example: instance GHC.Show.Show Binrep.Example.DX
+ Binrep.Example.FileTable: Entry :: a -> SW s (Refined (SizeLessThan (IMax 'U 'I1)) BS) -> Entry s a
+ Binrep.Example.FileTable: Table :: SW s (LenPfx 'I1 'LE (Entry s a)) -> Table s a
+ Binrep.Example.FileTable: [entryData] :: Entry s a -> SW s (Refined (SizeLessThan (IMax 'U 'I1)) BS)
+ Binrep.Example.FileTable: [entryName] :: Entry s a -> a
+ Binrep.Example.FileTable: [unTable] :: Table s a -> SW s (LenPfx 'I1 'LE (Entry s a))
+ Binrep.Example.FileTable: data Entry s a
+ Binrep.Example.FileTable: exBs :: BS
+ Binrep.Example.FileTable: getEntry :: Get a => Addr# -> Getter (Entry 'Strong a)
+ Binrep.Example.FileTable: getFileTable :: Get a => Getter (Table 'Strong a)
+ Binrep.Example.FileTable: instance (Binrep.Put.Put a, Binrep.BLen.BLen a) => Binrep.Put.Put (Binrep.Example.FileTable.Table 'Strongweak.Weaken.Strong a)
+ Binrep.Example.FileTable: instance Binrep.Get.Get a => Binrep.Get.Get (Binrep.Example.FileTable.Table 'Strongweak.Weaken.Strong a)
+ Binrep.Example.FileTable: instance Binrep.Get.Get a => Binrep.Get.GetWith GHC.Prim.Addr# (Binrep.Example.FileTable.Entry 'Strongweak.Weaken.Strong a)
+ Binrep.Example.FileTable: instance GHC.Classes.Eq a => GHC.Classes.Eq (Binrep.Example.FileTable.Entry 'Strongweak.Weaken.Strong a)
+ Binrep.Example.FileTable: instance GHC.Classes.Eq a => GHC.Classes.Eq (Binrep.Example.FileTable.Entry 'Strongweak.Weaken.Weak a)
+ Binrep.Example.FileTable: instance GHC.Generics.Generic (Binrep.Example.FileTable.Entry s a)
+ Binrep.Example.FileTable: instance GHC.Show.Show a => GHC.Show.Show (Binrep.Example.FileTable.Entry 'Strongweak.Weaken.Strong a)
+ Binrep.Example.FileTable: instance GHC.Show.Show a => GHC.Show.Show (Binrep.Example.FileTable.Entry 'Strongweak.Weaken.Weak a)
+ Binrep.Example.FileTable: instance Strongweak.Strengthen.Strengthen (Binrep.Example.FileTable.Entry 'Strongweak.Weaken.Strong a)
+ Binrep.Example.FileTable: instance Strongweak.Weaken.Weaken (Binrep.Example.FileTable.Entry 'Strongweak.Weaken.Strong a)
+ Binrep.Example.FileTable: newtype Table s a
+ Binrep.Example.FileTable: prepEntry :: (Put a, BLen a) => Entry 'Strong a -> (BLenT, Word8 -> Builder, BS)
+ Binrep.Example.FileTable: putFileTable :: (Put a, BLen a) => Table 'Strong a -> Builder
+ Binrep.Example.FileTable: type BS = ByteString
+ Binrep.Example.FileTable: w8i# :: Word8# -> Int#
+ Binrep.Example.Tar: Tar :: NullPadded 100 BS -> TarNat 8 -> TarNat 8 -> TarNat 8 -> TarNat 12 -> TarNat 12 -> Tar
+ Binrep.Example.Tar: TarNat :: AsciiNat 8 -> TarNat n
+ Binrep.Example.Tar: [getTarNat] :: TarNat n -> AsciiNat 8
+ Binrep.Example.Tar: [tarFileFileSize] :: Tar -> TarNat 12
+ Binrep.Example.Tar: [tarFileLastMod] :: Tar -> TarNat 12
+ Binrep.Example.Tar: [tarFileMode] :: Tar -> TarNat 8
+ Binrep.Example.Tar: [tarFileName] :: Tar -> NullPadded 100 BS
+ Binrep.Example.Tar: [tarFileUIDGroup] :: Tar -> TarNat 8
+ Binrep.Example.Tar: [tarFileUIDOwner] :: Tar -> TarNat 8
+ Binrep.Example.Tar: brCfgNoSum :: Cfg (I 'U 'I1 'LE)
+ Binrep.Example.Tar: data Tar
+ Binrep.Example.Tar: instance Binrep.BLen.BLen Binrep.Example.Tar.Tar
+ Binrep.Example.Tar: instance Binrep.Get.Get Binrep.Example.Tar.Tar
+ Binrep.Example.Tar: instance Binrep.Put.Put Binrep.Example.Tar.Tar
+ Binrep.Example.Tar: instance GHC.Classes.Eq Binrep.Example.Tar.Tar
+ Binrep.Example.Tar: instance GHC.Generics.Generic Binrep.Example.Tar.Tar
+ Binrep.Example.Tar: instance GHC.Show.Show Binrep.Example.Tar.Tar
+ Binrep.Example.Tar: instance GHC.TypeNats.KnownNat n => Binrep.BLen.BLen (Binrep.Example.Tar.TarNat n)
+ Binrep.Example.Tar: instance GHC.TypeNats.KnownNat n => Binrep.Get.Get (Binrep.Example.Tar.TarNat n)
+ Binrep.Example.Tar: instance GHC.TypeNats.KnownNat n => Binrep.Put.Put (Binrep.Example.Tar.TarNat n)
+ Binrep.Example.Tar: instance forall k (n :: k). GHC.Classes.Eq (Binrep.Example.Tar.TarNat n)
+ Binrep.Example.Tar: instance forall k (n :: k). GHC.Generics.Generic (Binrep.Example.Tar.TarNat n)
+ Binrep.Example.Tar: instance forall k (n :: k). GHC.Show.Show (Binrep.Example.Tar.TarNat n)
+ Binrep.Example.Tar: newtype TarNat n
+ Binrep.Example.Tar: type BS = ByteString
+ Binrep.Example.Tiff: TiffBody :: Magic (TiffMagic end) -> I 'U 'I4 end -> TiffBody (end :: Endianness)
+ Binrep.Example.Tiff: [Tiff] :: (Put (I 'U 'I4 end), bs ~ MagicVals (TiffMagic end), ByteVals bs, KnownNat (Length bs)) => TiffBody end -> Tiff
+ Binrep.Example.Tiff: [tiffBodyExInt] :: TiffBody (end :: Endianness) -> I 'U 'I4 end
+ Binrep.Example.Tiff: [tiffBodyMagic] :: TiffBody (end :: Endianness) -> Magic (TiffMagic end)
+ Binrep.Example.Tiff: brCfgNoSum :: Cfg W8
+ Binrep.Example.Tiff: data Tiff
+ Binrep.Example.Tiff: data TiffBody (end :: Endianness)
+ Binrep.Example.Tiff: instance (GHC.TypeLits.KnownSymbol (Binrep.Example.Tiff.TiffMagic end), Data.Typeable.Internal.Typeable end) => Data.Data.Data (Binrep.Example.Tiff.TiffBody end)
+ Binrep.Example.Tiff: instance (bs GHC.Types.~ Binrep.Type.Magic.MagicVals (Binrep.Example.Tiff.TiffMagic end), Binrep.Type.Byte.ByteVals bs, irep GHC.Types.~ Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I4 end, Binrep.Get.Get irep) => Binrep.Get.Get (Binrep.Example.Tiff.TiffBody end)
+ Binrep.Example.Tiff: instance (bs GHC.Types.~ Binrep.Type.Magic.MagicVals (Binrep.Example.Tiff.TiffMagic end), Binrep.Type.Byte.ByteVals bs, irep GHC.Types.~ Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I4 end, Binrep.Put.Put irep) => Binrep.Put.Put (Binrep.Example.Tiff.TiffBody end)
+ Binrep.Example.Tiff: instance (bs GHC.Types.~ Binrep.Type.Magic.MagicVals (Binrep.Example.Tiff.TiffMagic end), GHC.TypeNats.KnownNat (Binrep.Type.Byte.Length bs)) => Binrep.BLen.BLen (Binrep.Example.Tiff.TiffBody end)
+ Binrep.Example.Tiff: instance Binrep.BLen.BLen Binrep.Example.Tiff.Tiff
+ Binrep.Example.Tiff: instance Binrep.Get.Get Binrep.Example.Tiff.Tiff
+ Binrep.Example.Tiff: instance Binrep.Put.Put Binrep.Example.Tiff.Tiff
+ Binrep.Example.Tiff: instance GHC.Classes.Eq (Binrep.Example.Tiff.TiffBody end)
+ Binrep.Example.Tiff: instance GHC.Generics.Generic (Binrep.Example.Tiff.TiffBody end)
+ Binrep.Example.Tiff: instance GHC.Show.Show (Binrep.Example.Tiff.TiffBody end)
+ Binrep.Example.Tiff: instance GHC.Show.Show Binrep.Example.Tiff.Tiff
+ Binrep.Example.Tiff: tiffBEbs :: ByteString
+ Binrep.Example.Tiff: tiffLEbs :: ByteString
+ Binrep.Example.Tiff: type W8 = I 'U 'I1 'LE
+ Binrep.Example.Tiff: type family TiffMagic (end :: Endianness) :: Symbol
+ Binrep.Example.Wav: WavHeader :: Magic "RIFF" -> W32 -> Magic "WAVE" -> Magic "fmt " -> W16 -> W16 -> WavHeader
+ Binrep.Example.Wav: [wavHeaderChannels] :: WavHeader -> W16
+ Binrep.Example.Wav: [wavHeaderChunkSize] :: WavHeader -> W32
+ Binrep.Example.Wav: [wavHeaderFmtChunkMarker] :: WavHeader -> Magic "fmt "
+ Binrep.Example.Wav: [wavHeaderFmtType] :: WavHeader -> W16
+ Binrep.Example.Wav: [wavHeaderFmt] :: WavHeader -> Magic "WAVE"
+ Binrep.Example.Wav: [wavHeaderMagic] :: WavHeader -> Magic "RIFF"
+ Binrep.Example.Wav: brCfgNoSum :: Cfg (I 'U 'I1 'LE)
+ Binrep.Example.Wav: data WavHeader
+ Binrep.Example.Wav: instance Binrep.BLen.BLen Binrep.Example.Wav.WavHeader
+ Binrep.Example.Wav: instance Binrep.Get.Get Binrep.Example.Wav.WavHeader
+ Binrep.Example.Wav: instance Binrep.Put.Put Binrep.Example.Wav.WavHeader
+ Binrep.Example.Wav: instance Data.Data.Data Binrep.Example.Wav.WavHeader
+ Binrep.Example.Wav: instance GHC.Classes.Eq Binrep.Example.Wav.WavHeader
+ Binrep.Example.Wav: instance GHC.Generics.Generic Binrep.Example.Wav.WavHeader
+ Binrep.Example.Wav: instance GHC.Show.Show Binrep.Example.Wav.WavHeader
+ Binrep.Example.Wav: type E = 'LE
+ Binrep.Example.Wav: type W16 = I 'U 'I2 E
+ Binrep.Example.Wav: type W32 = I 'U 'I4 E
+ Binrep.Extra.HexByteString: Hex :: a -> Hex a
+ Binrep.Extra.HexByteString: [unHex] :: Hex a -> a
+ Binrep.Extra.HexByteString: instance Data.Aeson.Types.FromJSON.FromJSON (Binrep.Extra.HexByteString.Hex Data.ByteString.Internal.ByteString)
+ Binrep.Extra.HexByteString: instance Data.Aeson.Types.FromJSON.FromJSON (Binrep.Extra.HexByteString.Hex Data.ByteString.Short.Internal.ShortByteString)
+ Binrep.Extra.HexByteString: instance Data.Aeson.Types.ToJSON.ToJSON (Binrep.Extra.HexByteString.Hex Data.ByteString.Internal.ByteString)
+ Binrep.Extra.HexByteString: instance Data.Aeson.Types.ToJSON.ToJSON (Binrep.Extra.HexByteString.Hex Data.ByteString.Short.Internal.ShortByteString)
+ Binrep.Extra.HexByteString: instance Data.Data.Data a => Data.Data.Data (Binrep.Extra.HexByteString.Hex a)
+ Binrep.Extra.HexByteString: instance GHC.Classes.Eq a => GHC.Classes.Eq (Binrep.Extra.HexByteString.Hex a)
+ Binrep.Extra.HexByteString: instance GHC.Generics.Generic (Binrep.Extra.HexByteString.Hex a)
+ Binrep.Extra.HexByteString: instance GHC.Show.Show (Binrep.Extra.HexByteString.Hex Data.ByteString.Internal.ByteString)
+ Binrep.Extra.HexByteString: instance GHC.Show.Show (Binrep.Extra.HexByteString.Hex Data.ByteString.Short.Internal.ShortByteString)
+ Binrep.Extra.HexByteString: newtype Hex a
+ Binrep.Extra.HexByteString: parseHexByte :: (MonadParsec e s m, Token s ~ Char, Num a) => m a
+ Binrep.Extra.HexByteString: parseHexByteString :: (MonadParsec e s m, Token s ~ Char) => ([Word8] -> a) -> m a
+ Binrep.Extra.HexByteString: prettyHexByte :: (Char -> Char) -> Word8 -> (Char, Char)
+ Binrep.Extra.HexByteString: prettyHexByteString :: (a -> [Word8]) -> a -> Text
+ Binrep.Extra.HexByteString: prettyHexByteStringCompact :: (a -> [Word8]) -> a -> Text
+ Binrep.Extra.HexByteString: type HexByteString = Hex ByteString
+ Binrep.Generic: Cfg :: (String -> a) -> Cfg a
+ Binrep.Generic: [cSumTag] :: Cfg a -> String -> a
+ Binrep.Generic: blenGeneric :: (Generic a, GBLen (Rep a), BLen w) => Cfg w -> a -> BLenT
+ Binrep.Generic: cDef :: Cfg (AsByteString 'C)
+ Binrep.Generic: cSumTagHex :: forall a. Integral a => (String -> String) -> String -> a
+ Binrep.Generic: cSumTagNullTerm :: String -> AsByteString 'C
+ Binrep.Generic: data Cfg a
+ Binrep.Generic: getGeneric :: (Generic a, GGet (Rep a), Get w, Eq w, Show w) => Cfg w -> Parser String a
+ Binrep.Generic: putGeneric :: (Generic a, GPut (Rep a), Put w) => Cfg w -> a -> Builder
+ Binrep.Generic: type CBLenGeneric w a = GCBLen w (Rep a)
+ Binrep.Generic.BLen: blenGeneric :: (Generic a, GBLen (Rep a), BLen w) => Cfg w -> a -> BLenT
+ Binrep.Generic.BLen: class GBLen f
+ Binrep.Generic.BLen: class GBLenSum f
+ Binrep.Generic.BLen: gblen :: (GBLen f, BLen w) => Cfg w -> f p -> BLenT
+ Binrep.Generic.BLen: gblensum :: (GBLenSum f, BLen w) => Cfg w -> f p -> BLenT
+ Binrep.Generic.BLen: instance (TypeError ...) => Binrep.Generic.BLen.GBLen GHC.Generics.V1
+ Binrep.Generic.BLen: instance Binrep.BLen.BLen c => Binrep.Generic.BLen.GBLen (GHC.Generics.K1 i c)
+ Binrep.Generic.BLen: instance Binrep.Generic.BLen.GBLen GHC.Generics.U1
+ Binrep.Generic.BLen: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). (Binrep.Generic.BLen.GBLen f, GHC.Generics.Constructor c) => Binrep.Generic.BLen.GBLenSum (GHC.Generics.C1 c f)
+ Binrep.Generic.BLen: instance forall k (f :: k -> *) i (d :: GHC.Generics.Meta). Binrep.Generic.BLen.GBLen f => Binrep.Generic.BLen.GBLen (GHC.Generics.M1 i d f)
+ Binrep.Generic.BLen: instance forall k (l :: k -> *) (r :: k -> *). (Binrep.Generic.BLen.GBLen l, Binrep.Generic.BLen.GBLen r) => Binrep.Generic.BLen.GBLen (l GHC.Generics.:*: r)
+ Binrep.Generic.BLen: instance forall k (l :: k -> *) (r :: k -> *). (Binrep.Generic.BLen.GBLenSum l, Binrep.Generic.BLen.GBLenSum r) => Binrep.Generic.BLen.GBLenSum (l GHC.Generics.:+: r)
+ Binrep.Generic.BLen: instance forall k (l :: k -> *) (r :: k -> *). Binrep.Generic.BLen.GBLenSum (l GHC.Generics.:+: r) => Binrep.Generic.BLen.GBLen (l GHC.Generics.:+: r)
+ Binrep.Generic.CBLen: data JustX a b
+ Binrep.Generic.CBLen: data NothingX
+ Binrep.Generic.CBLen: type CBLenGeneric w a = GCBLen w (Rep a)
+ Binrep.Generic.CBLen: type family GCBLenCaseMaybe a
+ Binrep.Generic.Get: class GGet f
+ Binrep.Generic.Get: class GGetSum f
+ Binrep.Generic.Get: getGeneric :: (Generic a, GGet (Rep a), Get w, Eq w, Show w) => Cfg w -> Parser String a
+ Binrep.Generic.Get: gget :: (GGet f, Get w, Eq w, Show w) => Cfg w -> Parser String (f a)
+ Binrep.Generic.Get: ggetsum :: (GGetSum f, Get w, Eq w, Show w) => Cfg w -> w -> Maybe (Parser String (f a))
+ Binrep.Generic.Get: instance (TypeError ...) => Binrep.Generic.Get.GGet GHC.Generics.V1
+ Binrep.Generic.Get: instance Binrep.Generic.Get.GGet GHC.Generics.U1
+ Binrep.Generic.Get: instance Binrep.Get.Get c => Binrep.Generic.Get.GGet (GHC.Generics.K1 i c)
+ Binrep.Generic.Get: instance forall k (f :: k -> *) i (d :: GHC.Generics.Meta). Binrep.Generic.Get.GGet f => Binrep.Generic.Get.GGet (GHC.Generics.M1 i d f)
+ Binrep.Generic.Get: instance forall k (l :: k -> *) (r :: k -> *). (Binrep.Generic.Get.GGet l, Binrep.Generic.Get.GGet r) => Binrep.Generic.Get.GGet (l GHC.Generics.:*: r)
+ Binrep.Generic.Get: instance forall k (l :: k -> *) (r :: k -> *). (Binrep.Generic.Get.GGetSum l, Binrep.Generic.Get.GGetSum r) => Binrep.Generic.Get.GGetSum (l GHC.Generics.:+: r)
+ Binrep.Generic.Get: instance forall k (l :: k -> *) (r :: k -> *). Binrep.Generic.Get.GGetSum (l GHC.Generics.:+: r) => Binrep.Generic.Get.GGet (l GHC.Generics.:+: r)
+ Binrep.Generic.Get: instance forall k (r :: k -> *) (c :: GHC.Generics.Meta). (Binrep.Generic.Get.GGet r, GHC.Generics.Constructor c) => Binrep.Generic.Get.GGetSum (GHC.Generics.C1 c r)
+ Binrep.Generic.Internal: Cfg :: (String -> a) -> Cfg a
+ Binrep.Generic.Internal: [cSumTag] :: Cfg a -> String -> a
+ Binrep.Generic.Internal: conName' :: forall c. Constructor c => String
+ Binrep.Generic.Internal: data Cfg a
+ Binrep.Generic.Internal: type GErrRefuseVoid = 'Text "Refusing to derive binary representation for void datatype"
+ Binrep.Generic.Put: class GPut f
+ Binrep.Generic.Put: class GPutSum f
+ Binrep.Generic.Put: class GetConName f
+ Binrep.Generic.Put: getConName :: GetConName f => f a -> String
+ Binrep.Generic.Put: gput :: (GPut f, Put w) => Cfg w -> f p -> Builder
+ Binrep.Generic.Put: gputsum :: (GPutSum f, Put w) => Cfg w -> f a -> Builder
+ Binrep.Generic.Put: instance (TypeError ...) => Binrep.Generic.Put.GPut GHC.Generics.V1
+ Binrep.Generic.Put: instance Binrep.Generic.Put.GPut GHC.Generics.U1
+ Binrep.Generic.Put: instance Binrep.Put.Put c => Binrep.Generic.Put.GPut (GHC.Generics.K1 i c)
+ Binrep.Generic.Put: instance forall k (a :: k -> *) (b :: k -> *). (Binrep.Generic.Put.GetConName a, Binrep.Generic.Put.GetConName b) => Binrep.Generic.Put.GetConName (a GHC.Generics.:+: b)
+ Binrep.Generic.Put: instance forall k (c :: GHC.Generics.Meta) (a :: k -> *). GHC.Generics.Constructor c => Binrep.Generic.Put.GetConName (GHC.Generics.C1 c a)
+ Binrep.Generic.Put: instance forall k (f :: k -> *) i (d :: GHC.Generics.Meta). Binrep.Generic.Put.GPut f => Binrep.Generic.Put.GPut (GHC.Generics.M1 i d f)
+ Binrep.Generic.Put: instance forall k (l :: k -> *) (r :: k -> *). (Binrep.Generic.Put.GPut l, Binrep.Generic.Put.GPut r) => Binrep.Generic.Put.GPut (l GHC.Generics.:*: r)
+ Binrep.Generic.Put: instance forall k (l :: k -> *) (r :: k -> *). (Binrep.Generic.Put.GPutSum (l GHC.Generics.:+: r), Binrep.Generic.Put.GetConName (l GHC.Generics.:+: r)) => Binrep.Generic.Put.GPut (l GHC.Generics.:+: r)
+ Binrep.Generic.Put: instance forall k (l :: k -> *) (r :: k -> *). (Binrep.Generic.Put.GPutSum l, Binrep.Generic.Put.GPutSum r) => Binrep.Generic.Put.GPutSum (l GHC.Generics.:+: r)
+ Binrep.Generic.Put: instance forall k (r :: k -> *) (c :: GHC.Generics.Meta). (Binrep.Generic.Put.GPut r, GHC.Generics.Constructor c) => Binrep.Generic.Put.GPutSum (GHC.Generics.C1 c r)
+ Binrep.Generic.Put: putGeneric :: (Generic a, GPut (Rep a), Put w) => Cfg w -> a -> Builder
+ Binrep.Get: class Get a
+ Binrep.Get: class GetWith (r :: TYPE rep) a | a -> r
+ Binrep.Get: get :: Get a => Getter a
+ Binrep.Get: getWith :: GetWith r a => r -> Getter a
+ Binrep.Get: instance (Binrep.Get.Get a, Binrep.Get.Get b) => Binrep.Get.Get (a, b)
+ Binrep.Get: instance Binrep.Get.Get Data.ByteString.Internal.ByteString
+ Binrep.Get: instance Binrep.Get.Get GHC.Int.Int8
+ Binrep.Get: instance Binrep.Get.Get GHC.Word.Word8
+ Binrep.Get: instance Binrep.Get.Get a => Binrep.Get.Get [a]
+ Binrep.Get: runGet :: Get a => ByteString -> Either String (a, ByteString)
+ Binrep.Get: runGetWith :: GetWith (r :: TYPE LiftedRep) a => r -> ByteString -> Either String (a, ByteString)
+ Binrep.Get: runGetter :: Getter a -> ByteString -> Either String (a, ByteString)
+ Binrep.Get: type Getter a = Parser String a
+ Binrep.Put: class Put a
+ Binrep.Put: class PutWith r a
+ Binrep.Put: instance (Binrep.Put.Put a, Binrep.Put.Put b) => Binrep.Put.Put (a, b)
+ Binrep.Put: instance Binrep.Put.Put Data.ByteString.Internal.ByteString
+ Binrep.Put: instance Binrep.Put.Put GHC.Int.Int8
+ Binrep.Put: instance Binrep.Put.Put GHC.Word.Word8
+ Binrep.Put: instance Binrep.Put.Put a => Binrep.Put.Put [a]
+ Binrep.Put: instance Binrep.Put.Put a => Binrep.Put.PutWith r [a]
+ Binrep.Put: put :: Put a => a -> Builder
+ Binrep.Put: putWith :: (PutWith r a, Put a) => r -> a -> Either String Builder
+ Binrep.Put: putWithout :: Put a => a -> Either String Builder
+ Binrep.Put: runBuilder :: Builder -> ByteString
+ Binrep.Put: runPut :: Put a => a -> ByteString
+ Binrep.Put: runPutWith :: PutWith r a => r -> a -> Either String ByteString
+ Binrep.Put: type Builder = BuilderFor StrictByteStringBackend
+ Binrep.Type.AsciiNat: AsciiNat :: Natural -> AsciiNat (base :: Natural)
+ Binrep.Type.AsciiNat: [getAsciiNat] :: AsciiNat (base :: Natural) -> Natural
+ Binrep.Type.AsciiNat: asciiBytesToNat :: (Word8 -> Maybe Word8) -> Natural -> ByteString -> Either Word8 Natural
+ Binrep.Type.AsciiNat: asciiNatCompare :: AsciiNat b1 -> AsciiNat b2 -> Ordering
+ Binrep.Type.AsciiNat: digits :: forall b a. (Integral a, Integral b) => a -> a -> NonEmpty b
+ Binrep.Type.AsciiNat: instance Binrep.Get.Get (Binrep.Type.AsciiNat.AsciiNat 8)
+ Binrep.Type.AsciiNat: instance Binrep.Put.Put (Binrep.Type.AsciiNat.AsciiNat 8)
+ Binrep.Type.AsciiNat: instance GHC.Classes.Eq (Binrep.Type.AsciiNat.AsciiNat base)
+ Binrep.Type.AsciiNat: instance GHC.Classes.Ord (Binrep.Type.AsciiNat.AsciiNat base)
+ Binrep.Type.AsciiNat: instance GHC.Generics.Generic (Binrep.Type.AsciiNat.AsciiNat base)
+ Binrep.Type.AsciiNat: instance GHC.Show.Show (Binrep.Type.AsciiNat.AsciiNat 10)
+ Binrep.Type.AsciiNat: instance GHC.Show.Show (Binrep.Type.AsciiNat.AsciiNat 16)
+ Binrep.Type.AsciiNat: instance GHC.Show.Show (Binrep.Type.AsciiNat.AsciiNat 2)
+ Binrep.Type.AsciiNat: instance GHC.Show.Show (Binrep.Type.AsciiNat.AsciiNat 8)
+ Binrep.Type.AsciiNat: instance GHC.TypeNats.KnownNat base => Binrep.BLen.BLen (Binrep.Type.AsciiNat.AsciiNat base)
+ Binrep.Type.AsciiNat: instance GHC.TypeNats.KnownNat base => Data.Data.Data (Binrep.Type.AsciiNat.AsciiNat base)
+ Binrep.Type.AsciiNat: natToAsciiBytes :: (Word8 -> Word8) -> Natural -> Natural -> Builder
+ Binrep.Type.AsciiNat: newtype AsciiNat (base :: Natural)
+ Binrep.Type.AsciiNat: octalFromAsciiDigit :: Word8 -> Maybe Word8
+ Binrep.Type.Byte: byteVal :: ByteVal n => Proxy# n -> Word8#
+ Binrep.Type.Byte: byteVals :: ByteVals ns => Builder
+ Binrep.Type.Byte: class ByteVal (n :: Natural)
+ Binrep.Type.Byte: class ByteVals (ns :: [Natural])
+ Binrep.Type.Byte: class WriteByteVals (ns :: [Natural])
+ Binrep.Type.Byte: instance (Binrep.Type.Byte.ByteVal n, Binrep.Type.Byte.WriteByteVals ns) => Binrep.Type.Byte.WriteByteVals (n : ns)
+ Binrep.Type.Byte: instance (n GHC.Types.~ Binrep.Type.Byte.Length ns, GHC.TypeNats.KnownNat n, Binrep.Type.Byte.WriteByteVals ns) => Binrep.Type.Byte.ByteVals ns
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 0
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 1
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 10
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 100
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 101
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 102
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 103
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 104
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 105
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 106
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 107
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 108
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 109
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 11
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 110
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 111
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 112
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 113
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 114
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 115
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 116
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 117
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 118
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 119
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 12
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 120
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 121
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 122
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 123
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 124
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 125
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 126
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 127
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 128
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 129
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 13
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 130
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 131
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 132
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 133
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 134
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 135
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 136
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 137
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 138
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 139
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 14
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 140
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 141
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 142
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 143
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 144
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 145
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 146
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 147
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 148
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 149
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 15
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 150
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 151
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 152
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 153
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 154
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 155
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 156
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 157
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 158
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 159
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 16
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 160
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 161
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 162
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 163
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 164
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 165
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 166
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 167
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 168
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 169
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 17
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 170
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 171
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 172
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 173
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 174
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 175
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 176
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 177
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 178
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 179
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 18
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 180
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 181
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 182
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 183
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 184
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 185
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 186
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 187
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 188
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 189
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 19
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 190
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 191
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 192
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 193
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 194
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 195
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 196
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 197
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 198
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 199
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 2
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 20
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 200
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 201
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 202
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 203
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 204
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 205
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 206
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 207
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 208
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 209
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 21
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 210
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 211
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 212
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 213
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 214
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 215
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 216
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 217
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 218
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 219
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 22
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 220
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 221
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 222
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 223
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 224
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 225
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 226
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 227
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 228
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 229
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 23
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 230
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 231
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 232
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 233
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 234
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 235
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 236
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 237
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 238
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 239
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 24
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 240
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 241
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 242
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 243
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 244
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 245
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 246
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 247
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 248
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 249
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 25
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 250
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 251
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 252
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 253
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 254
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 255
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 26
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 27
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 28
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 29
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 3
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 30
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 31
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 32
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 33
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 34
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 35
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 36
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 37
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 38
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 39
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 4
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 40
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 41
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 42
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 43
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 44
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 45
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 46
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 47
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 48
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 49
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 5
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 50
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 51
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 52
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 53
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 54
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 55
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 56
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 57
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 58
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 59
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 6
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 60
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 61
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 62
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 63
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 64
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 65
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 66
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 67
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 68
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 69
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 7
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 70
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 71
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 72
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 73
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 74
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 75
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 76
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 77
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 78
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 79
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 8
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 80
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 81
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 82
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 83
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 84
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 85
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 86
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 87
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 88
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 89
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 9
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 90
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 91
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 92
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 93
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 94
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 95
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 96
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 97
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 98
+ Binrep.Type.Byte: instance Binrep.Type.Byte.ByteVal 99
+ Binrep.Type.Byte: instance Binrep.Type.Byte.WriteByteVals '[]
+ Binrep.Type.Byte: type family Length (a :: [k]) :: Natural
+ Binrep.Type.Byte: writeByteVals :: WriteByteVals ns => Addr# -> IO ()
+ Binrep.Type.ByteString: C :: Rep
+ Binrep.Type.ByteString: Pascal :: ISize -> Endianness -> Rep
+ Binrep.Type.ByteString: data Rep
+ Binrep.Type.ByteString: getCString :: Parser String ByteString
+ Binrep.Type.ByteString: instance (irep GHC.Types.~ Binrep.Type.Int.IRep 'Binrep.Type.Int.U size, GHC.Enum.Bounded irep, GHC.Real.Integral irep, GHC.Show.Show irep, Data.Typeable.Internal.Typeable size, Data.Typeable.Internal.Typeable e) => Refined.Predicate ('Binrep.Type.ByteString.Pascal size e) Data.ByteString.Internal.ByteString
+ Binrep.Type.ByteString: instance (itype GHC.Types.~ Binrep.Type.Int.I 'Binrep.Type.Int.U size end, irep GHC.Types.~ Binrep.Type.Int.IRep 'Binrep.Type.Int.U size, Binrep.Put.Put itype, GHC.Num.Num irep) => Binrep.Put.Put (Binrep.Type.ByteString.AsByteString ('Binrep.Type.ByteString.Pascal size end))
+ Binrep.Type.ByteString: instance (itype GHC.Types.~ Binrep.Type.Int.I 'Binrep.Type.Int.U size end, irep GHC.Types.~ Binrep.Type.Int.IRep 'Binrep.Type.Int.U size, GHC.Real.Integral irep, Binrep.Get.Get itype) => Binrep.Get.Get (Binrep.Type.ByteString.AsByteString ('Binrep.Type.ByteString.Pascal size end))
+ Binrep.Type.ByteString: instance (itype GHC.Types.~ Binrep.Type.Int.I 'Binrep.Type.Int.U size end, irep GHC.Types.~ Binrep.Type.Int.IRep 'Binrep.Type.Int.U size, GHC.TypeNats.KnownNat (Binrep.CBLen.CBLen irep)) => Binrep.BLen.BLen (Binrep.Type.ByteString.AsByteString ('Binrep.Type.ByteString.Pascal size end))
+ Binrep.Type.ByteString: instance Binrep.BLen.BLen (Binrep.Type.ByteString.AsByteString 'Binrep.Type.ByteString.C)
+ Binrep.Type.ByteString: instance Binrep.Get.Get (Binrep.Type.ByteString.AsByteString 'Binrep.Type.ByteString.C)
+ Binrep.Type.ByteString: instance Binrep.Put.Put (Binrep.Type.ByteString.AsByteString 'Binrep.Type.ByteString.C)
+ Binrep.Type.ByteString: instance Data.Data.Data Binrep.Type.ByteString.Rep
+ Binrep.Type.ByteString: instance GHC.Classes.Eq Binrep.Type.ByteString.Rep
+ Binrep.Type.ByteString: instance GHC.Generics.Generic Binrep.Type.ByteString.Rep
+ Binrep.Type.ByteString: instance GHC.Show.Show Binrep.Type.ByteString.Rep
+ Binrep.Type.ByteString: instance Refined.Predicate 'Binrep.Type.ByteString.C Data.ByteString.Internal.ByteString
+ Binrep.Type.ByteString: putCString :: ByteString -> Builder
+ Binrep.Type.ByteString: type AsByteString (rep :: Rep) = Refined rep ByteString
+ Binrep.Type.Common: BE :: Endianness
+ Binrep.Type.Common: LE :: Endianness
+ Binrep.Type.Common: data Endianness
+ Binrep.Type.Common: instance Data.Data.Data Binrep.Type.Common.Endianness
+ Binrep.Type.Common: instance GHC.Classes.Eq Binrep.Type.Common.Endianness
+ Binrep.Type.Common: instance GHC.Generics.Generic Binrep.Type.Common.Endianness
+ Binrep.Type.Common: instance GHC.Show.Show Binrep.Type.Common.Endianness
+ Binrep.Type.Int: I :: IRep sign size -> I (sign :: ISign) (size :: ISize) (e :: Endianness)
+ Binrep.Type.Int: I1 :: ISize
+ Binrep.Type.Int: I2 :: ISize
+ Binrep.Type.Int: I4 :: ISize
+ Binrep.Type.Int: I8 :: ISize
+ Binrep.Type.Int: S :: ISign
+ Binrep.Type.Int: U :: ISign
+ Binrep.Type.Int: [getI] :: I (sign :: ISign) (size :: ISize) (e :: Endianness) -> IRep sign size
+ Binrep.Type.Int: data ISign
+ Binrep.Type.Int: data ISize
+ Binrep.Type.Int: instance (Data.Data.Data (Binrep.Type.Int.IRep sign size), Data.Typeable.Internal.Typeable sign, Data.Typeable.Internal.Typeable size, Data.Typeable.Internal.Typeable e) => Data.Data.Data (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance (irep GHC.Types.~ Binrep.Type.Int.IRep 'Binrep.Type.Int.S size, GHC.Real.Integral irep) => Strongweak.Weaken.Weaken (Binrep.Type.Int.I 'Binrep.Type.Int.S size end)
+ Binrep.Type.Int: instance (irep GHC.Types.~ Binrep.Type.Int.IRep 'Binrep.Type.Int.S size, GHC.Real.Integral irep, GHC.Enum.Bounded irep, GHC.Show.Show irep, Data.Typeable.Internal.Typeable size, Data.Typeable.Internal.Typeable end) => Strongweak.Strengthen.Strengthen (Binrep.Type.Int.I 'Binrep.Type.Int.S size end)
+ Binrep.Type.Int: instance (irep GHC.Types.~ Binrep.Type.Int.IRep 'Binrep.Type.Int.U size, GHC.Real.Integral irep) => Strongweak.Weaken.Weaken (Binrep.Type.Int.I 'Binrep.Type.Int.U size end)
+ Binrep.Type.Int: instance (irep GHC.Types.~ Binrep.Type.Int.IRep 'Binrep.Type.Int.U size, GHC.Real.Integral irep, GHC.Enum.Bounded irep, GHC.Show.Show irep, Data.Typeable.Internal.Typeable size, Data.Typeable.Internal.Typeable end) => Strongweak.Strengthen.Strengthen (Binrep.Type.Int.I 'Binrep.Type.Int.U size end)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I1 e)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I2 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I2 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I4 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I4 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I8 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I8 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I1 e)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I2 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I2 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I4 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I4 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I8 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Get.Get (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I8 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I1 e)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I2 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I2 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I4 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I4 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I8 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.S 'Binrep.Type.Int.I8 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I1 e)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I2 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I2 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I4 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I4 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I8 'Binrep.Type.Common.BE)
+ Binrep.Type.Int: instance Binrep.Put.Put (Binrep.Type.Int.I 'Binrep.Type.Int.U 'Binrep.Type.Int.I8 'Binrep.Type.Common.LE)
+ Binrep.Type.Int: instance Data.Aeson.Types.FromJSON.FromJSON (Binrep.Type.Int.IRep sign size) => Data.Aeson.Types.FromJSON.FromJSON (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance Data.Aeson.Types.ToJSON.ToJSON (Binrep.Type.Int.IRep sign size) => Data.Aeson.Types.ToJSON.ToJSON (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance Data.Data.Data Binrep.Type.Int.ISign
+ Binrep.Type.Int: instance Data.Data.Data Binrep.Type.Int.ISize
+ Binrep.Type.Int: instance GHC.Classes.Eq (Binrep.Type.Int.IRep sign size) => GHC.Classes.Eq (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance GHC.Classes.Eq Binrep.Type.Int.ISign
+ Binrep.Type.Int: instance GHC.Classes.Eq Binrep.Type.Int.ISize
+ Binrep.Type.Int: instance GHC.Classes.Ord (Binrep.Type.Int.IRep sign size) => GHC.Classes.Ord (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance GHC.Enum.Bounded (Binrep.Type.Int.IRep sign size) => GHC.Enum.Bounded (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance GHC.Enum.Enum (Binrep.Type.Int.IRep sign size) => GHC.Enum.Enum (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance GHC.Generics.Generic (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance GHC.Generics.Generic Binrep.Type.Int.ISign
+ Binrep.Type.Int: instance GHC.Generics.Generic Binrep.Type.Int.ISize
+ Binrep.Type.Int: instance GHC.Num.Num (Binrep.Type.Int.IRep sign size) => GHC.Num.Num (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance GHC.Real.Integral (Binrep.Type.Int.IRep sign size) => GHC.Real.Integral (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance GHC.Real.Real (Binrep.Type.Int.IRep sign size) => GHC.Real.Real (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance GHC.Show.Show (Binrep.Type.Int.IRep sign size) => GHC.Show.Show (Binrep.Type.Int.I sign size e)
+ Binrep.Type.Int: instance GHC.Show.Show Binrep.Type.Int.ISign
+ Binrep.Type.Int: instance GHC.Show.Show Binrep.Type.Int.ISize
+ Binrep.Type.Int: instance GHC.TypeNats.KnownNat (Binrep.CBLen.CBLen (Binrep.Type.Int.I sign size end)) => Binrep.BLen.BLen (Binrep.Type.Int.I sign size end)
+ Binrep.Type.Int: newtype I (sign :: ISign) (size :: ISize) (e :: Endianness)
+ Binrep.Type.Int: type family MaxBound w :: Natural
+ Binrep.Type.LenPfx: LenPfx :: Vector n a -> LenPfx (size :: ISize) (end :: Endianness) a
+ Binrep.Type.LenPfx: [unLenPfx] :: LenPfx (size :: ISize) (end :: Endianness) a -> Vector n a
+ Binrep.Type.LenPfx: asLenPfx :: forall size end n a irep. (irep ~ IRep 'U size, KnownNat n, KnownNat (MaxBound irep)) => Vector n a -> Maybe (LenPfx size end a)
+ Binrep.Type.LenPfx: data LenPfx (size :: ISize) (end :: Endianness) a
+ Binrep.Type.LenPfx: getLenPfx :: forall size end a itype irep. (itype ~ I 'U size end, irep ~ IRep 'U size, Get itype, Integral irep, KnownNat (MaxBound irep)) => Getter a -> Getter (LenPfx size end a)
+ Binrep.Type.LenPfx: instance (Binrep.BLen.BLen a, itype GHC.Types.~ Binrep.Type.Int.I 'Binrep.Type.Int.U size end, GHC.TypeNats.KnownNat (Binrep.CBLen.CBLen itype)) => Binrep.BLen.BLen (Binrep.Type.LenPfx.LenPfx size end a)
+ Binrep.Type.LenPfx: instance (GHC.TypeNats.KnownNat (Binrep.Type.Int.MaxBound (Binrep.Type.Int.IRep 'Binrep.Type.Int.U size)), GHC.Show.Show a, Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable size, Data.Typeable.Internal.Typeable end) => Strongweak.Strengthen.Strengthen (Binrep.Type.LenPfx.LenPfx size end a)
+ Binrep.Type.LenPfx: instance (itype GHC.Types.~ Binrep.Type.Int.I 'Binrep.Type.Int.U size end, irep GHC.Types.~ Binrep.Type.Int.IRep 'Binrep.Type.Int.U size, Binrep.Get.Get itype, GHC.Real.Integral irep, Binrep.Get.Get a, GHC.TypeNats.KnownNat (Binrep.Type.Int.MaxBound irep)) => Binrep.Get.Get (Binrep.Type.LenPfx.LenPfx size end a)
+ Binrep.Type.LenPfx: instance (itype GHC.Types.~ Binrep.Type.Int.I 'Binrep.Type.Int.U size end, irep GHC.Types.~ Binrep.Type.Int.IRep 'Binrep.Type.Int.U size, Binrep.Put.Put a, Binrep.Put.Put itype, GHC.Num.Num irep) => Binrep.Put.Put (Binrep.Type.LenPfx.LenPfx size end a)
+ Binrep.Type.LenPfx: instance GHC.Classes.Eq a => GHC.Classes.Eq (Binrep.Type.LenPfx.LenPfx size end a)
+ Binrep.Type.LenPfx: instance GHC.Generics.Generic (Binrep.Type.LenPfx.LenPfx size end a)
+ Binrep.Type.LenPfx: instance GHC.Show.Show a => GHC.Show.Show (Binrep.Type.LenPfx.LenPfx size end a)
+ Binrep.Type.LenPfx: instance Strongweak.Weaken.Weaken (Binrep.Type.LenPfx.LenPfx size end a)
+ Binrep.Type.LenPfx: lenPfxFromList :: forall size end a irep. (irep ~ IRep 'U size, KnownNat (MaxBound irep)) => [a] -> Maybe (LenPfx size end a)
+ Binrep.Type.LenPfx: lenPfxSize :: Num (IRep 'U size) => LenPfx size end a -> I 'U size end
+ Binrep.Type.LenPfx: vsEq :: forall a n m. (Eq a, KnownNat n, KnownNat m) => Vector n a -> Vector m a -> Bool
+ Binrep.Type.Magic: Magic :: Magic (a :: k)
+ Binrep.Type.Magic: data Magic (a :: k)
+ Binrep.Type.Magic: instance forall k (a :: k). (Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable k) => Data.Data.Data (Binrep.Type.Magic.Magic a)
+ Binrep.Type.Magic: instance forall k (a :: k). GHC.Classes.Eq (Binrep.Type.Magic.Magic a)
+ Binrep.Type.Magic: instance forall k (a :: k). GHC.Generics.Generic (Binrep.Type.Magic.Magic a)
+ Binrep.Type.Magic: instance forall k (a :: k). GHC.Show.Show (Binrep.Type.Magic.Magic a)
+ Binrep.Type.Magic: instance forall k (a :: k). GHC.TypeNats.KnownNat (Binrep.Type.Byte.Length (Binrep.Type.Magic.MagicVals a)) => Binrep.BLen.BLen (Binrep.Type.Magic.Magic a)
+ Binrep.Type.Magic: instance forall k (bs :: [GHC.Num.Natural.Natural]) (a :: k). (bs GHC.Types.~ Binrep.Type.Magic.MagicVals a, Binrep.Type.Byte.ByteVals bs) => Binrep.Get.Get (Binrep.Type.Magic.Magic a)
+ Binrep.Type.Magic: instance forall k (bs :: [GHC.Num.Natural.Natural]) (a :: k). (bs GHC.Types.~ Binrep.Type.Magic.MagicVals a, Binrep.Type.Byte.ByteVals bs) => Binrep.Put.Put (Binrep.Type.Magic.Magic a)
+ Binrep.Type.Magic: type family SymbolAsCharList' (a :: Maybe (Char, Symbol)) :: [Char]
+ Binrep.Type.Magic.UTF8: MagicUTF8 :: MagicUTF8 (str :: Symbol)
+ Binrep.Type.Magic.UTF8: data MagicUTF8 (str :: Symbol)
+ Binrep.Type.Magic.UTF8: encodeStringUtf8 :: String -> ByteString
+ Binrep.Type.Magic.UTF8: instance GHC.Show.Show (Binrep.Type.Magic.UTF8.MagicUTF8 str)
+ Binrep.Type.Magic.UTF8: instance GHC.TypeLits.KnownSymbol str => Binrep.BLen.BLen (Binrep.Type.Magic.UTF8.MagicUTF8 str)
+ Binrep.Type.Magic.UTF8: instance GHC.TypeLits.KnownSymbol str => Binrep.Get.Get (Binrep.Type.Magic.UTF8.MagicUTF8 str)
+ Binrep.Type.Magic.UTF8: instance GHC.TypeLits.KnownSymbol str => Binrep.Put.Put (Binrep.Type.Magic.UTF8.MagicUTF8 str)
+ Binrep.Type.Magic.UTF8: symVal :: forall str. KnownSymbol str => String
+ Binrep.Type.NullPadded: data NullPad (n :: Natural)
+ Binrep.Type.NullPadded: getNNulls :: BLenT -> Parser String ()
+ Binrep.Type.NullPadded: instance (Binrep.BLen.BLen a, GHC.TypeNats.KnownNat n) => Refined.Predicate (Binrep.Type.NullPadded.NullPad n) a
+ Binrep.Type.NullPadded: instance (Binrep.Get.Get a, Binrep.BLen.BLen a, GHC.TypeNats.KnownNat n) => Binrep.Get.Get (Binrep.Type.NullPadded.NullPadded n a)
+ Binrep.Type.NullPadded: instance (Binrep.Put.Put a, Binrep.BLen.BLen a, GHC.TypeNats.KnownNat n) => Binrep.Put.Put (Binrep.Type.NullPadded.NullPadded n a)
+ Binrep.Type.NullPadded: instance GHC.TypeNats.KnownNat n => Binrep.BLen.BLen (Binrep.Type.NullPadded.NullPadded n a)
+ Binrep.Type.NullPadded: type NullPadded n a = Refined (NullPad n) a
+ Binrep.Type.Sized: data Size (n :: Natural)
+ Binrep.Type.Sized: instance (Binrep.BLen.BLen a, GHC.TypeNats.KnownNat n) => Refined.Predicate (Binrep.Type.Sized.Size n) a
+ Binrep.Type.Sized: instance (Binrep.Get.Get a, GHC.TypeNats.KnownNat n) => Binrep.Get.Get (Binrep.Type.Sized.Sized n a)
+ Binrep.Type.Sized: instance Binrep.Put.Put a => Binrep.Put.Put (Binrep.Type.Sized.Sized n a)
+ Binrep.Type.Sized: instance GHC.TypeNats.KnownNat n => Binrep.BLen.BLen (Binrep.Type.Sized.Sized n a)
+ Binrep.Type.Sized: type Sized n a = Refined (Size n) a
+ Binrep.Type.Text: ASCII :: Encoding
+ Binrep.Type.Text: SJIS :: Encoding
+ Binrep.Type.Text: UTF16 :: Endianness -> Encoding
+ Binrep.Type.Text: UTF32 :: Endianness -> Encoding
+ Binrep.Type.Text: UTF8 :: Encoding
+ Binrep.Type.Text: class Decode (enc :: Encoding)
+ Binrep.Type.Text: class Encode (enc :: Encoding)
+ Binrep.Type.Text: data Encoding
+ Binrep.Type.Text: decode :: Decode enc => Bytes -> Either String (AsText enc)
+ Binrep.Type.Text: decodeViaTextICU :: String -> ByteString -> IO (Either String Text)
+ Binrep.Type.Text: encode :: forall enc. Encode enc => AsText enc -> Bytes
+ Binrep.Type.Text: encodeToRep :: forall (rep :: Rep) enc. (Encode enc, Predicate rep Bytes) => AsText enc -> Either RefineException (Refined rep Bytes)
+ Binrep.Type.Text: instance Binrep.Type.Text.Decode 'Binrep.Type.Text.SJIS
+ Binrep.Type.Text: instance Binrep.Type.Text.Decode 'Binrep.Type.Text.UTF8
+ Binrep.Type.Text: instance Binrep.Type.Text.Decode ('Binrep.Type.Text.UTF16 'Binrep.Type.Common.BE)
+ Binrep.Type.Text: instance Binrep.Type.Text.Decode ('Binrep.Type.Text.UTF16 'Binrep.Type.Common.LE)
+ Binrep.Type.Text: instance Binrep.Type.Text.Decode ('Binrep.Type.Text.UTF32 'Binrep.Type.Common.BE)
+ Binrep.Type.Text: instance Binrep.Type.Text.Decode ('Binrep.Type.Text.UTF32 'Binrep.Type.Common.LE)
+ Binrep.Type.Text: instance Binrep.Type.Text.Encode 'Binrep.Type.Text.ASCII
+ Binrep.Type.Text: instance Binrep.Type.Text.Encode 'Binrep.Type.Text.SJIS
+ Binrep.Type.Text: instance Binrep.Type.Text.Encode 'Binrep.Type.Text.UTF8
+ Binrep.Type.Text: instance Binrep.Type.Text.Encode ('Binrep.Type.Text.UTF16 'Binrep.Type.Common.BE)
+ Binrep.Type.Text: instance Binrep.Type.Text.Encode ('Binrep.Type.Text.UTF16 'Binrep.Type.Common.LE)
+ Binrep.Type.Text: instance Binrep.Type.Text.Encode ('Binrep.Type.Text.UTF32 'Binrep.Type.Common.BE)
+ Binrep.Type.Text: instance Binrep.Type.Text.Encode ('Binrep.Type.Text.UTF32 'Binrep.Type.Common.LE)
+ Binrep.Type.Text: instance Data.Data.Data Binrep.Type.Text.Encoding
+ Binrep.Type.Text: instance Data.Typeable.Internal.Typeable e => Refined.Predicate ('Binrep.Type.Text.UTF16 e) Data.Text.Internal.Text
+ Binrep.Type.Text: instance Data.Typeable.Internal.Typeable e => Refined.Predicate ('Binrep.Type.Text.UTF32 e) Data.Text.Internal.Text
+ Binrep.Type.Text: instance GHC.Classes.Eq Binrep.Type.Text.Encoding
+ Binrep.Type.Text: instance GHC.Generics.Generic Binrep.Type.Text.Encoding
+ Binrep.Type.Text: instance GHC.Show.Show Binrep.Type.Text.Encoding
+ Binrep.Type.Text: instance Refined.Predicate 'Binrep.Type.Text.ASCII Data.Text.Internal.Text
+ Binrep.Type.Text: instance Refined.Predicate 'Binrep.Type.Text.SJIS Data.Text.Internal.Text
+ Binrep.Type.Text: instance Refined.Predicate 'Binrep.Type.Text.UTF8 Data.Text.Internal.Text
+ Binrep.Type.Text: type AsText (enc :: Encoding) = Refined enc Text
+ Binrep.Type.Vector: getVector :: KnownNat n => Getter a -> Getter (Vector n a)
+ Binrep.Type.Vector: instance (Binrep.Get.Get a, GHC.TypeNats.KnownNat n) => Binrep.Get.Get (Data.Vector.Sized.Vector n a)
+ Binrep.Type.Vector: instance Binrep.BLen.BLen a => Binrep.BLen.BLen (Data.Vector.Sized.Vector n a)
+ Binrep.Type.Vector: instance Binrep.Put.Put a => Binrep.Put.Put (Data.Vector.Sized.Vector n a)
+ Binrep.Util: natVal'' :: forall a. KnownNat a => Natural
+ Binrep.Util: posIntToNat :: Int -> Natural
+ Data.Aeson.Extra.SizedVector: instance (Data.Aeson.Types.FromJSON.FromJSON (v a), GHC.TypeNats.KnownNat n, Data.Vector.Generic.Base.Vector v a) => Data.Aeson.Types.FromJSON.FromJSON (Data.Vector.Generic.Sized.Internal.Vector v n a)
+ Data.Aeson.Extra.SizedVector: instance Data.Aeson.Types.ToJSON.ToJSON (v a) => Data.Aeson.Types.ToJSON.ToJSON (Data.Vector.Generic.Sized.Internal.Vector v n a)
Files
- CHANGELOG.md +12/−0
- README.md +131/−10
- binrep.cabal +123/−24
- src/Binrep.hs +16/−0
- src/Binrep/BLen.hs +69/−0
- src/Binrep/BLen/Internal/AsBLen.hs +65/−0
- src/Binrep/ByteLen.hs +0/−34
- src/Binrep/CBLen.hs +21/−0
- src/Binrep/Codec.hs +0/−86
- src/Binrep/Example.hs +67/−0
- src/Binrep/Example/FileTable.hs +105/−0
- src/Binrep/Example/Tar.hs +67/−0
- src/Binrep/Example/Tiff.hs +62/−0
- src/Binrep/Example/Wav.hs +31/−0
- src/Binrep/Extra/HexByteString.hs +109/−0
- src/Binrep/Generic.hs +49/−0
- src/Binrep/Generic/BLen.hs +51/−0
- src/Binrep/Generic/CBLen.hs +72/−0
- src/Binrep/Generic/Get.hs +66/−0
- src/Binrep/Generic/Internal.hs +21/−0
- src/Binrep/Generic/Put.hs +66/−0
- src/Binrep/Get.hs +68/−0
- src/Binrep/Predicates/NullPadTo.hs +0/−69
- src/Binrep/Put.hs +63/−0
- src/Binrep/Type/AsciiNat.hs +112/−0
- src/Binrep/Type/Byte.hs +821/−0
- src/Binrep/Type/ByteString.hs +101/−0
- src/Binrep/Type/Common.hs +10/−0
- src/Binrep/Type/Int.hs +142/−0
- src/Binrep/Type/LenPfx.hs +110/−0
- src/Binrep/Type/Magic.hs +97/−0
- src/Binrep/Type/Magic/UTF8.hs +47/−0
- src/Binrep/Type/NullPadded.hs +70/−0
- src/Binrep/Type/Sized.hs +44/−0
- src/Binrep/Type/Text.hs +184/−0
- src/Binrep/Type/Vector.hs +26/−0
- src/Binrep/Types/Ints.hs +0/−89
- src/Binrep/Types/Strings.hs +0/−111
- src/Binrep/Util.hs +24/−0
- src/Data/Aeson/Extra/SizedVector.hs +19/−0
- test/ArbitraryOrphans.hs +10/−0
- test/Binrep/Extra/HexByteStringSpec.hs +39/−0
- test/Binrep/LawsSpec.hs +49/−0
- test/Spec.hs +1/−0
CHANGELOG.md view
@@ -1,3 +1,15 @@+## 0.2.0 (2022-07-07)+Multiple rewrites (unable to push to Hackage for a while due to dependencies).++ * BinaryCodec split into Get and Put+ * fast serializing via fumieval's mason+ * fast parsing via András Kovács' flatparse+ * integration with my strongweak library+ * generics+ * tests+ * CBLen for constant length types+ * plenty more+ ## 0.1.0 (2022-04-22) Initial release.
README.md view
@@ -1,14 +1,135 @@+[gh-strongweak]: https://github.com/raehik/strongweak+[gh-flatparse]: https://github.com/AndrasKovacs/flatparse+[gh-mason]: https://github.com/fumieval/mason+[gh-refined]: https://github.com/nikita-volkov/refined+ # binrep-Haskell data types with their binary representation explicitly built into the-types. Intended for simple binary file parsing.+binrep is a library for **precisely modelling binary schemas** and working with+them effectively and efficiently in Haskell. Here's why it's useful: -The binary and cereal libraries are for passing Haskell data between other-binary and cereal users. Thus, data representation is largely obscured. For-example, in `cereal`, all data is handled in big-endian format. If you use the-`Serialize` typeclass methods for parsing and serializing, you would never know.+ * **Explicit:** Binary representation primitives such as C-style bytestrings+ (null-terminated), sized explicit-endian machine integers, and null-padded+ data enable defining Haskell data types with the binary schema "baked in".+ * **Low boilerplate:** Generic parsers and serializers further reduce boilerplate for+ straightforward schemas. (See [Generic binary+ representation](#generic-binary-representation) for details.)+ * **Easy validation:** Goes hand in hand with my [strongweak][gh-strongweak]+ library to allow working with unwrapped data internally, and enforcing all+ the binary representation invariants before serializing - no extra+ definitions required.+ * **Performant:** Parsing and serialization is low-level and *extremely fast*,+ using [flatparse][gh-flatparse] and [mason][gh-mason] respectively. -binrep never makes decisions by itself. You can't parse/serialize a `Word64`-without either providing the endianness to use at runtime, or encoding the-endianness into the type.+## Philosophy+### Modelling, not serializing+binrep is good at modelling binary data formats. It is not a plain+"serialization" library, where the actual binary representation is hidden from+the user (intentionally, with good reason). The binary and cereal libraries are+great choices for that. They are interested in defining efficient binary codecs+for Haskell data. However, their codec typeclasses *hide representation+decisions* from the user. In cereal, -See the Hackage documentation for details.+ * machine integers are encoded with+ [big endian](https://hackage.haskell.org/package/cereal-0.5.8.2/docs/src/Data.Serialize.html#line-182)+ * bytestrings are written with an+ [8-byte length prefix](https://hackage.haskell.org/package/cereal-0.5.8.2/docs/src/Data.Serialize.html#line-498)++These are fine decisions. But they aren't accurate to the types. Endianness is+an implementation decision.++binrep refuses to work with a machine integer unless it knows the endianness.+Bytestrings are split into C-style (null-terminated) and Pascal-style+(length-prefixed). This enforces careful consideration for the binary data being+modelled.++### Validation without boilerplate+A C-style bytestring must not contain any `0x00` null bytes. A Pascal-style+bytestring must be short enough to be able to encode its length in the length+prefix machine integer. But checking such invariants is tedious work. Am I+really going to wrap everything in a bunch of newtypes and force users to call a+bunch of checker functions every time?++Yes and no. Yes, binrep uses newtypes extensively, though most are type synonyms+over the `Refined` newtype from Nikita Volkov's wonderful [refined][gh-refined]+library. No, binrep doesn't want you to wrangle with these day-to-day. One+solution is to define a simplified "weak" type, and convert between it and the+binary-safe "strong" type. My [strongweak][gh-strongweak] library provides+supporting definitions for this pattern, and generic derivers which will work+with binrep's binary representation primitives.++### Performant primitives+Parsing uses András Kovács' [flatparse][gh-flatparse] library. Serializing is+via Fumiaki Kinoshita's [mason][gh-mason] library. These are about as fast as+you can get in 2022.++We only define serializers for validated types, meaning we can potentially skip+safety checks, that other serializers would do. Except we still do them, but+validation is an explicitly required step before serialization.++*This might change if we start to support weirder binary representations,+specifically offset-based data.*++## Generic binary representation+binrep's generic deriving makes very few decisions:++ * Constructors are encoded by sequentially encoding every enclosed field.+ * Empty constructors thus serialize to 0 bytes.+ * Sum types are encoded via a tag obtained from the constructor names.+ * It's the same approach as aeson, with a bit more flexibility: see below.++Sum types (data types with multiple constructors) are handled by first encoding+a "tag field", the value of which then indicates which constructor to use. You+must provide a function to convert from a constructor name to a (unique) tag.+You could encode them as a null-terminated ASCII bytestring (this is the+default), or as a single byte. To ease this, you may consider putting the tag+value in constructor names:++```haskell+data BinarySumType = B1 | B2++getConstructorTag :: String -> Word8+getConstructorTag = read . drop 1++-- >>> getConstructorTag "B1"+-- 1++-- Or use our generic helper, which takes hex values:+--+-- >>> cSumTagHex @Word8 (drop . 1) "BFF"+-- 255+```++## Similar projects+### Kaitai Struct+[Kaitai Struct](https://kaitai.io/) is a wonderful declarative parser generator+project. They bolt an expression language and a whole lot of binary cleverness+on top of a nice YAML schema. It comes with an IDE, a visualizer, and you can+compile schemas down to parsers for various different languages (no Haskell...).++Design principles like their fancy absolute offset handling and language+neutrality have stunted serialization support. Though it's more like they have+such powerful parsing that they can parse formats that can't be edited and+re-serialized naively, like archives with file indexes. For proper handling, one+should store a file table, and serialization generates the index. So in reverse,+you would want to combine them. But it's a bit program-y. In binrep, you are in+a programming language, so it's less of a problem... but I'm not sure if we can+be very efficient at absolute offset stuff.++Realistically, Kaitai Struct is the best decision for fast iteration on+reversing unknown data. binrep is useful for loading data straight into Haskell+for further processing, especially converting between simpler formats.++### Wuffs+[Wuffs](https://github.com/google/wuffs) is a crazy exploration into safe+low-level code via strong typing. You have to annotate every possibly dangerous+statement with a proof of safety. It's a tedious, explicit, very safe and very+fast imperative language for defining parsers and serializers.++Wuffs is more a codec engineer's tool than a reverse engineer's one. binrep+isn't really interested in speed, and being a Haskell library we get to focus on+defining types and their composition in a declarative & functional manner. As+such, we get to define more useful things quicker using binrep. Though we share+many core ideas, such as refinement types.++Check out Wuffs if you need to write a bunch of codecs and they really, really+need to be both fast and safe. The trade-off is, of course, your time.
binrep.cabal view
@@ -5,10 +5,10 @@ -- see: https://github.com/sol/hpack name: binrep-version: 0.1.0-synopsis: Encode binary representations via types.+version: 0.2.0+synopsis: Encode precise binary representations directly in types description: Please see README.md.-category: Data+category: Data, Serialization homepage: https://github.com/raehik/binrep#readme bug-reports: https://github.com/raehik/binrep/issues author: Ben Orchard@@ -17,7 +17,7 @@ license-file: LICENSE build-type: Simple tested-with:- GHC ==8.10.7 || ==9.2.2+ GHC ==9.2.2 extra-source-files: README.md CHANGELOG.md@@ -28,25 +28,50 @@ library exposed-modules:- Binrep.ByteLen- Binrep.Codec- Binrep.Predicates.NullPadTo- Binrep.Types.Ints- Binrep.Types.Strings+ Binrep+ Binrep.BLen+ Binrep.BLen.Internal.AsBLen+ Binrep.CBLen+ Binrep.Example+ Binrep.Example.FileTable+ Binrep.Example.Tar+ Binrep.Example.Tiff+ Binrep.Example.Wav+ Binrep.Extra.HexByteString+ Binrep.Generic+ Binrep.Generic.BLen+ Binrep.Generic.CBLen+ Binrep.Generic.Get+ Binrep.Generic.Internal+ Binrep.Generic.Put+ Binrep.Get+ Binrep.Put+ Binrep.Type.AsciiNat+ Binrep.Type.Byte+ Binrep.Type.ByteString+ Binrep.Type.Common+ Binrep.Type.Int+ Binrep.Type.LenPfx+ Binrep.Type.Magic+ Binrep.Type.Magic.UTF8+ Binrep.Type.NullPadded+ Binrep.Type.Sized+ Binrep.Type.Text+ Binrep.Type.Vector Binrep.Util+ Data.Aeson.Extra.SizedVector other-modules: Paths_binrep hs-source-dirs: src default-extensions: EmptyCase- FlexibleContexts- FlexibleInstances- InstanceSigs- MultiParamTypeClasses- PolyKinds LambdaCase+ InstanceSigs+ BangPatterns+ ExplicitNamespaces DerivingStrategies+ DerivingVia StandaloneDeriving DeriveAnyClass DeriveGeneric@@ -55,27 +80,101 @@ DeriveFoldable DeriveTraversable DeriveLift- ImportQualifiedPost- StandaloneKindSignatures- DerivingVia+ FlexibleContexts+ FlexibleInstances+ MultiParamTypeClasses+ GADTs+ PolyKinds RoleAnnotations+ RankNTypes TypeApplications- DataKinds+ DefaultSignatures TypeFamilies+ DataKinds+ MagicHash+ ImportQualifiedPost+ StandaloneKindSignatures+ ScopedTypeVariables TypeOperators+ ghc-options: -Wall+ build-depends:+ aeson ==2.0.*+ , base >=4.14 && <5+ , bytestring ==0.11.*+ , either >=5.0.1.1 && <5.1+ , flatparse >=0.3.5.0 && <0.4+ , mason >=0.2.5 && <0.3+ , megaparsec >=9.2.0 && <9.3+ , refined ==0.7.*+ , strongweak >=0.3.1 && <0.4+ , text ==1.2.*+ , text-icu >=0.8.0.1 && <0.9+ , vector >=0.12.3.1 && <0.13+ , vector-sized >=1.5.0 && <1.6+ default-language: Haskell2010++test-suite spec+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ ArbitraryOrphans+ Binrep.Extra.HexByteStringSpec+ Binrep.LawsSpec+ Paths_binrep+ hs-source-dirs:+ test+ default-extensions:+ EmptyCase+ LambdaCase+ InstanceSigs BangPatterns+ ExplicitNamespaces+ DerivingStrategies+ DerivingVia+ StandaloneDeriving+ DeriveAnyClass+ DeriveGeneric+ DeriveDataTypeable+ DeriveFunctor+ DeriveFoldable+ DeriveTraversable+ DeriveLift+ FlexibleContexts+ FlexibleInstances+ MultiParamTypeClasses GADTs- DefaultSignatures+ PolyKinds+ RoleAnnotations RankNTypes- UndecidableInstances+ TypeApplications+ DefaultSignatures+ TypeFamilies+ DataKinds MagicHash+ ImportQualifiedPost+ StandaloneKindSignatures ScopedTypeVariables+ TypeOperators+ ghc-options: -Wall+ build-tool-depends:+ hspec-discover:hspec-discover >=2.7 && <2.10 build-depends:- aeson ==2.0.*+ QuickCheck >=2.14.2 && <2.15+ , aeson ==2.0.* , base >=4.14 && <5+ , binrep , bytestring ==0.11.*- , cereal >=0.5.8.1 && <0.6- , refined >=0.6.3 && <0.7- , refined-with >=0.1.0 && <0.2+ , either >=5.0.1.1 && <5.1+ , flatparse >=0.3.5.0 && <0.4+ , generic-random >=1.5.0.1 && <1.6+ , hspec >=2.7 && <2.10+ , mason >=0.2.5 && <0.3+ , megaparsec >=9.2.0 && <9.3+ , quickcheck-instances >=0.3.26 && <0.4+ , refined ==0.7.*+ , strongweak >=0.3.1 && <0.4 , text ==1.2.*+ , text-icu >=0.8.0.1 && <0.9+ , vector >=0.12.3.1 && <0.13+ , vector-sized >=1.5.0 && <1.6 default-language: Haskell2010
+ src/Binrep.hs view
@@ -0,0 +1,16 @@+{- | Helper module to bring most functionality into scope.++Generics are in a separate module (to prevent module import cycles).+-}++module Binrep+ ( module Binrep.BLen+ , module Binrep.CBLen+ , module Binrep.Put+ , module Binrep.Get+ ) where++import Binrep.BLen+import Binrep.CBLen+import Binrep.Put+import Binrep.Get
+ src/Binrep/BLen.hs view
@@ -0,0 +1,69 @@+{-# LANGUAGE AllowAmbiguousTypes #-}++module Binrep.BLen+ ( module Binrep.BLen+ , module Binrep.BLen.Internal.AsBLen+ ) where++import Binrep.BLen.Internal.AsBLen+import Binrep.CBLen+import Binrep.Util ( natVal'' )++import GHC.TypeNats+import Data.ByteString qualified as B+import Data.Word+import Data.Int++type BLenT = Int++-- | The length in bytes of a value of the given type can be known on the cheap+-- e.g. by reading a length field, or using compile time information.+--+-- Concepts such as null padding require the notion of length in bytes in order+-- to handle. In a hand-rolled parser, you may keep count of the current length+-- as you go. Here, the individual types keep track, and expose it via this+-- typeclass.+--+-- Obtaining the length of a value is usually an @O(1)@ operation like reading a+-- field or returning a constant. When it's not, it's often an indicator of a+-- problematic type e.g. plain Haskell lists.+--+-- We derive a default instance for constant-size types by throwing away the+-- value and reifying the type level natural.+--+-- Note that one can derive a free 'BLen' instance for any type with a 'Put'+-- instance via serializing it and checking the length. _Do not do this._ If you+-- find you can't write a decent 'BLen' instance for a type, it may be that you+-- need to rethink the representation.+class BLen a where+ blen :: a -> BLenT+ default blen :: KnownNat (CBLen a) => a -> BLenT+ blen _ = cblen @a++typeNatToBLen :: forall n. KnownNat n => BLenT+typeNatToBLen = natToBLen $ natVal'' @n+{-# INLINE typeNatToBLen #-}++-- | Reify a type's constant byte length to the term level.+cblen :: forall a n. (n ~ CBLen a, KnownNat n) => BLenT+cblen = typeNatToBLen @n+{-# INLINE cblen #-}++-- | @O(n)@+instance BLen a => BLen [a] where+ blen = sum . map blen++instance (BLen a, BLen b) => BLen (a, b) where+ blen (a, b) = blen a + blen b++instance BLen B.ByteString where+ blen = posIntToBLen . B.length++deriving anyclass instance BLen Word8+deriving anyclass instance BLen Int8+deriving anyclass instance BLen Word16+deriving anyclass instance BLen Int16+deriving anyclass instance BLen Word32+deriving anyclass instance BLen Int32+deriving anyclass instance BLen Word64+deriving anyclass instance BLen Int64
+ src/Binrep/BLen/Internal/AsBLen.hs view
@@ -0,0 +1,65 @@+module Binrep.BLen.Internal.AsBLen where++import GHC.Natural ( minusNaturalMaybe )+import GHC.Num.Natural+import GHC.Exts+import Binrep.Util ( posIntToNat )++-- | Helper definitions for using the given type to store byte lengths.+--+-- Byte lengths must be non-negative. Thus, the ideal representation is a+-- 'Natural'. However, most underlying types that we use ('B.ByteString', lists)+-- store their length in 'Int's. By similarly storing an 'Int' ourselves, we+-- could potentially improve performance.+--+-- I like both options, and don't want to give up either. So we provide helpers+-- via a typeclass so that the user doesn't ever have to think about the+-- underlying type.+--+-- For simplicity, documentation may consider 'a' to be an "unsigned" type. For+-- example, underflow refers to a negative 'a' result.+class AsBLen a where+ -- | Safe blen subtraction, returning 'Nothing' for negative results.+ --+ -- Regular subtraction should only be used when you have a guarantee that it+ -- won't underflow.+ safeBLenSub :: a -> a -> Maybe a++ -- | Convert some 'Int' @i@ where @i >= 0@ to a blen.+ --+ -- This is intended for wrapping the output of 'length' functions.+ posIntToBLen :: Int -> a++ -- | Convert some 'Word#' @w@ where @w <= maxBound @a@ to a blen.+ wordToBLen# :: Word# -> a++ -- | Convert some 'Natural' @n@ where @n <= maxBound @a@ to a blen.+ natToBLen :: Natural -> a++instance AsBLen Int where+ safeBLenSub x y = if z >= 0 then Just z else Nothing where z = x - y+ {-# INLINE safeBLenSub #-}++ posIntToBLen = id+ {-# INLINE posIntToBLen #-}++ natToBLen = \case+ NS w# -> wordToBLen# w#+ NB _ -> error "TODO natural too large"+ {-# INLINE natToBLen #-}++ wordToBLen# w# = I# (word2Int# w#)+ {-# INLINE wordToBLen# #-}++instance AsBLen Natural where+ safeBLenSub = minusNaturalMaybe+ {-# INLINE safeBLenSub #-}++ posIntToBLen = posIntToNat+ {-# INLINE posIntToBLen #-}++ wordToBLen# = NS+ {-# INLINE wordToBLen# #-}++ natToBLen = id+ {-# INLINE natToBLen #-}
− src/Binrep/ByteLen.hs
@@ -1,34 +0,0 @@-{- TODO-Potentially should be moved into BinaryCodec. We need this for padding-based-combinators. Each inside combinator must report the number of bytes they-serialized. It *should* be extremely cheap.--So far I haven't got another use for it, and I feel there should be some better-way to define it but the types don't fit well. So I'll leave it as is for now.--}--module Binrep.ByteLen where--import Numeric.Natural---- | The size in bytes of the type can be known, preferably on the cheap e.g.--- reading a length field.------ Aim to make this O(1). Except for where you can't like lists lol.------ Importantly goes hand in hand with BinaryCodec! Maybe we should make it a--- function there lol!------ This is useful for padding types generically, without having to track the--- read/write cursor. Yes, that feature *is* common and cheap for parsers (and--- to lesser extent, serializers), but you should really only be padding types--- that have a "static-ish" (= cheaply calculated) size. At least, I think so?--- I'm not quite sure.------ Some instances ignore the argument. It would be possible to pull those out--- into a statically-known bytelength typeclass, but it wouldn't improve clarity--- or performance, just get rid of a couple 'undefined's.-class ByteLen a where- blen :: a -> Natural--instance ByteLen a => ByteLen [a] where blen = sum . map blen
+ src/Binrep/CBLen.hs view
@@ -0,0 +1,21 @@+module Binrep.CBLen where++import Data.Word+import Data.Int+import GHC.TypeNats ( Natural )++-- | The length in bytes of any value of the given type is constant.+--+-- Many binary representation primitives are constant, or store their size in+-- their type. This is a stronger statement about their length than @BLen@.+type family CBLen a :: Natural++-- Explicitly-sized Haskell machine words are constant size.+type instance CBLen Word8 = 1+type instance CBLen Int8 = 1+type instance CBLen Word16 = 2+type instance CBLen Int16 = 2+type instance CBLen Word32 = 4+type instance CBLen Int32 = 4+type instance CBLen Word64 = 8+type instance CBLen Int64 = 8
− src/Binrep/Codec.hs
@@ -1,86 +0,0 @@-module Binrep.Codec where--import Data.ByteString qualified as BS-import Data.ByteString.Lazy qualified as BL-import Data.ByteString.Builder qualified as B-import Data.Serialize---- | Types that can be coded precisely between binary and a Haskell type.------ This class looks identical to cereal's 'Serialize', but we take a different--- approach to instances.------ 'Data.Serialize.Serialize' defines an internal binary codec for common--- Haskell types. It makes implicit decisions, such as big-endian for all--- integer types, and coding lists with a (big-endian) 'Word64' length prefix.--- It only works with other data serialized with the same library.------ This typeclass defines composable binary codec combinators. If you want to--- write a codec for a 'Word64', it needs to specify its endianness in the type.--- If you want to write a codec for a list with a 'Word8' length prefix, it must--- come with a proof that it's not oversized.------ The idea is to use this typeclass along with various annotated newtypes to--- allow defining a Haskell type's binary representation directly in the types.--- In cases where you're doing intermediate serialization and not much else, it--- may be convenient. You will need to do a bunch of (free at runtime) wrapping--- though.-class BinaryCodec a where- toBin :: Putter a -- ^ Encode to binary. Same as cereal's 'put'.- fromBin :: Get a -- ^ Decode from binary. Same as cereal's 'get'.---- | Run the encoder for a supporting type.-binEncode :: BinaryCodec a => a -> BS.ByteString-binEncode = runPut . toBin---- | Run the decoder a supporting type.-binDecode :: BinaryCodec a => BS.ByteString -> Either String a-binDecode = runGet fromBin---- | Serialize each element in order. No length indicator, so parse until either--- error or EOF. Usually not what you want, but sometimes used at the "top" of--- binary formats.-instance BinaryCodec a => BinaryCodec [a] where- toBin as = mapM_ toBin as- fromBin = go []- where- go as = do- a <- fromBin- isEmpty >>= \case- True -> return $ reverse $ a : as- False -> go $ a : as---- | Types that can be coded between binary and a Haskell type given some--- runtime information.------ We can't prove something related to a value and pass that proof along without--- dependent types, meaning we can't split validation from encoding like in--- 'BinaryCodec', so encoding can fail. However, by allowing an arbitrary--- environment, we can define many more convenient instances.------ For example, you can't write a 'BinaryCodec' instance for 'Word16' because it--- doesn't specify its endianness. But you can define 'BinaryCodecWith--- Endianness Word16'! This was, you can decide how much of the binary schema--- you want to place directly in the types, and how much to configure--- dynamically.------ This class defaults to the free implementation provided by 'BinaryCodec',--- which ignores the environment and wraps serializing with 'Right'.-class BinaryCodecWith r a where- -- | Encode to binary with the given environment.- toBinWith :: r -> a -> Either String B.Builder- default toBinWith :: BinaryCodec a => r -> a -> Either String B.Builder- toBinWith = const $ Right . execPut . toBin-- -- | Decode to binary with the given environment.- fromBinWith :: r -> Get a- default fromBinWith :: BinaryCodec a => r -> Get a- fromBinWith = const fromBin---- | Run the encoder for a supporting type using the given environment.-binEncodeWith :: BinaryCodecWith r a => r -> a -> Either String BS.ByteString-binEncodeWith r a = BL.toStrict . B.toLazyByteString <$> toBinWith r a---- | Run the decoder for a supporting type using the given environment.-binDecodeWith :: BinaryCodecWith r a => r -> BS.ByteString -> Either String a-binDecodeWith = runGet . fromBinWith
+ src/Binrep/Example.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE UndecidableInstances #-}++module Binrep.Example where++import Binrep+import Binrep.Generic+import Binrep.Generic qualified as BR+import Binrep.Type.Common ( Endianness(..) )+import Binrep.Type.Int++import GHC.Generics ( Generic )+import Data.Data ( Data )++brCfgNoSum :: BR.Cfg (I 'U 'I1 'LE)+brCfgNoSum = BR.Cfg { BR.cSumTag = undefined }++data DV+ deriving stock (Generic, Data)++-- Disallowed. No binrepping void datatypes.+{-+instance BLen DV where blen = blenGeneric brCfgNoSum+instance Put DV where put = putGeneric brCfgNoSum+instance Get DV where get = getGeneric brCfgNoSum+-}++data DU = DU+ deriving stock (Generic, Data, Show, Eq)++instance BLen DU where blen = blenGeneric brCfgNoSum+instance Put DU where put = putGeneric brCfgNoSum+instance Get DU where get = getGeneric brCfgNoSum++data DSS = DSS+ { dss1 :: I 'U 'I1 'LE+ , dss2 :: I 'U 'I2 'LE+ , dss3 :: I 'U 'I4 'LE+ , dss4 :: I 'U 'I8 'LE+ , dss5 :: I 'U 'I1 'LE+ } deriving stock (Generic, Data, Show, Eq)++instance BLen DSS where blen = blenGeneric brCfgNoSum+instance Put DSS where put = putGeneric brCfgNoSum+instance Get DSS where get = getGeneric brCfgNoSum++data DCS = DCS1 {- DSS -} | DCS2 | DCS3 | DCS4 | DCS5+ deriving stock (Generic, Data, Show, Eq)++brCfgDCS :: BR.Cfg (I 'U 'I1 'LE)+brCfgDCS = BR.Cfg { BR.cSumTag = BR.cSumTagHex $ drop 3 }++--instance BR.BLen DCS where blen = BR.blenGeneric brCfgDCS+deriving anyclass instance BLen DCS+instance Put DCS where put = putGeneric brCfgDCS+instance Get DCS where get = getGeneric brCfgDCS++data DX = DX DU+ deriving stock (Generic, Data, Show, Eq)++type instance CBLen DX = CBLenGeneric (I 'U 'I1 'LE) DX+type instance CBLen DU = CBLenGeneric (I 'U 'I1 'LE) DU+type instance CBLen DSS = CBLenGeneric (I 'U 'I1 'LE) DSS+type instance CBLen DCS = CBLenGeneric (I 'U 'I1 'LE) DCS+deriving anyclass instance BLen DX++-- TODO clean up that CBLen messing around, probably don't mention it outside+-- the module (it's weird and will probably break things)
+ src/Binrep/Example/FileTable.hs view
@@ -0,0 +1,105 @@+module Binrep.Example.FileTable where++import Binrep+import Refined hiding ( Weaken )+import Refined.Unsafe+import Binrep.Type.Common ( Endianness(..) )+import Binrep.Type.Int+import Binrep.Type.LenPfx+import FlatParse.Basic qualified as FP+import Data.ByteString qualified as B+import Strongweak+import Strongweak.Generic+--import Data.Map ( Map )+import GHC.Generics ( Generic )+import GHC.Exts+import Data.Vector.Sized qualified as V+import Data.Word++type BS = B.ByteString++-- We're unable to put one invariant in the types: an entry can't be placed past+-- the maximum offset. Validating that requires quite a lot of work: we have to+-- do much of the layouting work, which will be repeated for serializing. This+-- is a downside of phase separation, it crops up every now and then.+--+-- The BLen instance will similarly be a bit complex, but it could probably be+-- implemented with similar code to strengthening.+newtype Table s a = Table { unTable :: SW s (LenPfx 'I1 'LE (Entry s a)) }++instance (Put a, BLen a) => Put (Table 'Strong a) where put = putFileTable++putFileTable :: (Put a, BLen a) => Table 'Strong a -> Builder+putFileTable (Table a@(LenPfx es)) =+ let es' = V.map prepEntry es+ osBase = V.sum $ V.map (\(l, _, _) -> l) es'+ in case V.foldl go ((fromIntegral osBase) - 1, mempty, mempty) es' of+ (_, bh, bd) -> put (lenPfxSize a) <> bh <> bd+ where+ go :: (Word8, Builder, Builder) -> (BLenT, Word8 -> Builder, BS) -> (Word8, Builder, Builder)+ go (os, bh, bd) (_, eh, ed) = (os+fromIntegral (B.length ed), bh<>eh os, bd<>put ed)++prepEntry :: (Put a, BLen a) => Entry 'Strong a -> (BLenT, Word8 -> Builder, BS)+prepEntry (Entry nm bs) = (l, b, bs')+ where+ bs' = unrefine bs+ b os =+ put nm <> put os <> put (fromIntegral (B.length bs') :: Word8)+ l = blen nm + 1 + 1 + blen bs'++instance Get a => Get (Table 'Strong a) where get = getFileTable++getFileTable :: Get a => Getter (Table 'Strong a)+getFileTable = FP.withAddr# $ \addr# -> Table <$> getLenPfx (getWith addr#)++{-+This is certainly a weird type.++ * Can use regular strongweak generics+ * Has no 'Get' instance+ * Has a 'GetWith Addr#' instance+ * Has no 'Put' instance+ * Has no 'PutWith' instance++You can't serialize an 'Entry' by itself, because it serializes to two+artifacts, a header entry and the associated data. Now I see why Kaitai Struct+was having trouble with serializing this sort of type.+-}+data Entry s a = Entry+ { entryName :: a+ , entryData :: SW s (Refined (SizeLessThan (IMax 'U 'I1)) BS)+ } deriving stock (Generic)+deriving stock instance Show a => Show (Entry 'Weak a)+deriving stock instance Eq a => Eq (Entry 'Weak a)+deriving stock instance Show a => Show (Entry 'Strong a)+deriving stock instance Eq a => Eq (Entry 'Strong a)+instance Weaken (Entry 'Strong a) where+ type Weak (Entry 'Strong a) = Entry 'Weak a+ weaken = weakenGeneric+instance Strengthen (Entry 'Strong a) where+ strengthen = strengthenGeneric++instance Get a => GetWith Addr# (Entry 'Strong a) where getWith = getEntry++getEntry :: Get a => Addr# -> Getter (Entry 'Strong a)+getEntry addr# = do+ name <- get+ dat <- FP.withAnyWord8# $ \offset# -> FP.withAnyWord8# $ \len# ->+ FP.takeBsOffAddr# addr# (w8i# offset#) (w8i# len#)+ return $ Entry name (reallyUnsafeRefine dat)++w8i# :: Word8# -> Int#+w8i# w# = word2Int# (word8ToWord# w#)++exBs :: BS+exBs = B.pack+ [ 0x02+ , 0x30, 0x31, 0x32, 0x00+ , 12 -- <- offset!!+ , 0x01+ , 0x39, 0x38, 0x00+ , 13+ , 0x01+ , 0xFF+ , 0xF0+ ]
+ src/Binrep/Example/Tar.hs view
@@ -0,0 +1,67 @@+module Binrep.Example.Tar where++import Binrep+import Binrep.Generic+import Binrep.Generic qualified as BR+import Binrep.Type.Common ( Endianness(..) )+import Binrep.Type.Int+import Binrep.Type.NullPadded+import Binrep.Type.AsciiNat++import GHC.Generics ( Generic )++import Data.Word ( Word8 )++import GHC.TypeNats++import Data.ByteString qualified as B++import FlatParse.Basic qualified as FP++type BS = B.ByteString++brCfgNoSum :: BR.Cfg (I 'U 'I1 'LE)+brCfgNoSum = BR.Cfg { BR.cSumTag = undefined }++-- | The naturals in tars are sized octal ASCII digit strings that end with a+-- null byte (and may start with leading ASCII zeroes). The size includes the+-- terminating null, so you get @n-1@ digits. What a farce.+--+-- Don't use this constructor directly! The size must be checked to ensure it+-- fits.+newtype TarNat n = TarNat { getTarNat :: AsciiNat 8 }+ deriving stock (Generic, Show, Eq)++type instance CBLen (TarNat n) = n+instance KnownNat n => BLen (TarNat n)++-- | No need to check for underflow etc. as TarNat guarantees good sizing.+instance KnownNat n => Put (TarNat n) where+ put (TarNat an) = put pfxNulls <> put an <> put @Word8 0x00+ where+ pfxNulls = B.replicate (fromIntegral pfxNullCount) 0x30+ pfxNullCount = n - blen an - 1+ n = typeNatToBLen @n++instance KnownNat n => Get (TarNat n) where+ get = do+ an <- FP.isolate (fromIntegral (n - 1)) get+ get @Word8 >>= \case+ 0x00 -> return $ TarNat an+ w -> FP.err $ "TODO expected null byte, got " <> show w+ where+ n = typeNatToBLen @n++-- Partial header+data Tar = Tar+ { tarFileName :: NullPadded 100 BS+ , tarFileMode :: TarNat 8+ , tarFileUIDOwner :: TarNat 8+ , tarFileUIDGroup :: TarNat 8+ , tarFileFileSize :: TarNat 12+ , tarFileLastMod :: TarNat 12+ } deriving stock (Generic, Show, Eq)++instance BLen Tar where blen = blenGeneric brCfgNoSum+instance Put Tar where put = putGeneric brCfgNoSum+instance Get Tar where get = getGeneric brCfgNoSum
+ src/Binrep/Example/Tiff.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE UndecidableInstances #-}++module Binrep.Example.Tiff where++import Binrep+import Binrep.Generic+import Binrep.Generic qualified as BR+import Binrep.Type.Common ( Endianness(..) )+import Binrep.Type.Int+import Binrep.Type.Magic+import Binrep.Type.Byte+import FlatParse.Basic ( (<|>) )++import GHC.Generics ( Generic )+import Data.Data ( Data, Typeable )+import GHC.TypeLits++import Data.ByteString qualified as B++type W8 = I 'U 'I1 'LE++brCfgNoSum :: BR.Cfg W8+brCfgNoSum = BR.Cfg { BR.cSumTag = undefined }++data Tiff where+ Tiff :: (Put (I 'U 'I4 end), bs ~ MagicVals (TiffMagic end), ByteVals bs, KnownNat (Length bs)) => TiffBody end -> Tiff++instance Show Tiff where+ show (Tiff body) = "Tiff " <> show body++data TiffBody (end :: Endianness) = TiffBody+ { tiffBodyMagic :: Magic (TiffMagic end)+ , tiffBodyExInt :: I 'U 'I4 end+ } deriving stock (Generic, Show, Eq)+deriving stock instance (KnownSymbol (TiffMagic end), Typeable end) => Data (TiffBody end)++instance (bs ~ MagicVals (TiffMagic end), KnownNat (Length bs)) => BLen (TiffBody end) where+ blen = blenGeneric brCfgNoSum+instance (bs ~ MagicVals (TiffMagic end), ByteVals bs, irep ~ I 'U 'I4 end, Put irep) => Put (TiffBody end) where+ put = putGeneric brCfgNoSum+instance (bs ~ MagicVals (TiffMagic end), ByteVals bs, irep ~ I 'U 'I4 end, Get irep) => Get (TiffBody end) where+ get = getGeneric brCfgNoSum++instance BLen Tiff where+ blen (Tiff body) = blen body++instance Put Tiff where+ put (Tiff body) = put body++instance Get Tiff where+ get = fmap Tiff (get @(TiffBody 'LE)) <|> fmap Tiff (get @(TiffBody 'BE))++type family TiffMagic (end :: Endianness) :: Symbol where+ TiffMagic 'LE = "II"+ TiffMagic 'BE = "MM"++tiffLEbs :: B.ByteString+tiffLEbs = B.pack [0x49, 0x49, 0xFF, 0x00, 0x00, 0x00]++tiffBEbs :: B.ByteString+tiffBEbs = B.pack [0x4D, 0x4D, 0x00, 0x00, 0x00, 0xFF]
+ src/Binrep/Example/Wav.hs view
@@ -0,0 +1,31 @@+module Binrep.Example.Wav where++import Binrep+import Binrep.Generic+import Binrep.Generic qualified as BR+import Binrep.Type.Common ( Endianness(..) )+import Binrep.Type.Int+import Binrep.Type.Magic++import GHC.Generics ( Generic )+import Data.Data ( Data )++type E = 'LE+type W32 = I 'U 'I4 E+type W16 = I 'U 'I2 E++brCfgNoSum :: BR.Cfg (I 'U 'I1 'LE)+brCfgNoSum = BR.Cfg { BR.cSumTag = undefined }++data WavHeader = WavHeader+ { wavHeaderMagic :: Magic "RIFF"+ , wavHeaderChunkSize :: W32 -- file size - 8+ , wavHeaderFmt :: Magic "WAVE"+ , wavHeaderFmtChunkMarker :: Magic "fmt "+ , wavHeaderFmtType :: W16+ , wavHeaderChannels :: W16+ } deriving stock (Generic, Data, Show, Eq)++instance BLen WavHeader where blen = blenGeneric brCfgNoSum+instance Put WavHeader where put = putGeneric brCfgNoSum+instance Get WavHeader where get = getGeneric brCfgNoSum
+ src/Binrep/Extra/HexByteString.hs view
@@ -0,0 +1,109 @@+-- | Pretty bytestrings via printing each byte as two hex digits.+--+-- This is primarily for aeson and when we want better 'show'ing of non-textual+-- bytestrings. It's not really binrep-related, but it needs _somewhere_ to go+-- and my projects that need it usually also touch binrep, so here it is.+--+-- Sadly, we can't use it to make aeson print integers as hex literals. It only+-- deals in Scientifics, and if we tried printing them as strings, it would+-- quote them. I need a YAML-like with better literals...++module Binrep.Extra.HexByteString where++import GHC.Generics ( Generic )+import Data.Data ( Data )++import Data.ByteString qualified as B+import Data.ByteString.Short qualified as B.Short+import Data.Char qualified as Char+import Data.Word+import Data.Text qualified as Text+import Data.Text ( Text )+import Data.List as List++import Text.Megaparsec hiding ( parse )+import Text.Megaparsec.Char qualified as MC+import Data.Void++import Data.Aeson++-- TODO could add some integer instances to print them as hex too++-- No harm in being polymorphic over the byte representation.+newtype Hex a = Hex { unHex :: a }+ deriving stock (Generic, Data)+ deriving Eq via a++-- But most users will probably just want this.+type HexByteString = Hex B.ByteString++instance Show (Hex B.ByteString) where+ show = Text.unpack . prettyHexByteString B.unpack . unHex++instance FromJSON (Hex B.ByteString) where+ parseJSON = withText "hex bytestring" $ \t ->+ case parseMaybe @Void (parseHexByteString B.pack) t of+ Nothing -> fail "failed to parse hex bytestring (TODO)"+ Just t' -> pure (Hex t')++instance ToJSON (Hex B.ByteString) where+ toJSON = String . prettyHexByteString B.unpack . unHex++instance Show (Hex B.Short.ShortByteString) where+ show = Text.unpack . prettyHexByteString B.Short.unpack . unHex++instance FromJSON (Hex B.Short.ShortByteString) where+ parseJSON = withText "hex bytestring" $ \t ->+ case parseMaybe @Void (parseHexByteString B.Short.pack) t of+ Nothing -> fail "failed to parse hex bytestring (TODO)"+ Just t' -> pure (Hex t')++instance ToJSON (Hex B.Short.ShortByteString) where+ toJSON = String . prettyHexByteString B.Short.unpack . unHex++-- | A hex bytestring looks like this: @00 01 89 8a FEff@. You can mix and+-- match capitalization and spacing, but I prefer to space each byte, full caps.+parseHexByteString+ :: (MonadParsec e s m, Token s ~ Char)+ => ([Word8] -> a) -> m a+parseHexByteString pack = pack <$> parseHexByte `sepBy` MC.hspace++-- | Parse a byte formatted as two hex digits e.g. EF. You _must_ provide both+-- nibbles e.g. @0F@, not @F@. They cannot be spaced e.g. @E F@ is invalid.+--+-- Returns a value 0-255, so can fit in any Num type that can store that.+parseHexByte :: (MonadParsec e s m, Token s ~ Char, Num a) => m a+parseHexByte = do+ c1 <- MC.hexDigitChar+ c2 <- MC.hexDigitChar+ return $ 0x10 * fromIntegral (Char.digitToInt c1) + fromIntegral (Char.digitToInt c2)++-- | Pretty print to default format @00 12 AB FF@: space between each byte, all+-- caps.+--+-- This format I consider most human readable. I prefer caps to draw attention+-- to this being data instead of text (you don't see that many capital letters+-- packed together in prose).+prettyHexByteString :: (a -> [Word8]) -> a -> Text+prettyHexByteString unpack =+ Text.concat+ . List.intersperse (Text.singleton ' ')+ . fmap (f . prettyHexByte Char.toUpper)+ . unpack+ where+ f :: (Char, Char) -> Text+ f (c1, c2) = Text.cons c1 $ Text.singleton c2++prettyHexByte :: (Char -> Char) -> Word8 -> (Char, Char)+prettyHexByte f w = (prettyNibble h, prettyNibble l)+ where+ (h,l) = fromIntegral w `divMod` 0x10+ prettyNibble = f . Char.intToDigit -- Char.intToDigit returns lower case++-- | Pretty print to "compact" format @0012abff@ (often output by hashers).+prettyHexByteStringCompact :: (a -> [Word8]) -> a -> Text+prettyHexByteStringCompact unpack =+ Text.concat . fmap (f . prettyHexByte id) . unpack+ where+ f :: (Char, Char) -> Text+ f (c1, c2) = Text.cons c1 $ Text.singleton c2
+ src/Binrep/Generic.hs view
@@ -0,0 +1,49 @@+-- | Derive 'BLen', 'Put', 'Get' and 'CBLen' instances generically.++module Binrep.Generic+ ( Cfg(..)+ , cSumTagHex, cSumTagNullTerm, cDef+ , blenGeneric, putGeneric, getGeneric, CBLenGeneric+ ) where++import Binrep.Generic.Internal+import Binrep.Generic.BLen+import Binrep.Generic.Put+import Binrep.Generic.Get+import Binrep.Generic.CBLen++import Binrep.Type.ByteString ( AsByteString, Rep(..) )+import Refined.Unsafe ( reallyUnsafeRefine )+import Data.Text qualified as Text+import Data.Text.Encoding qualified as Text++import Numeric ( readHex )++-- TODO better error handling (see what aeson does)++-- | Obtain the tag for a sum type value by applying a function to the+-- constructor name, and reading the result as a hexadecimal number.+cSumTagHex :: forall a. Integral a => (String -> String) -> String -> a+cSumTagHex f = forceRead . readHex . f++-- | Successfully parse exactly one result, or runtime error.+forceRead :: [(a, String)] -> a+forceRead = \case [] -> error "no parse"+ [(x, "")] -> x+ [(_x, _)] -> error "incomplete parse"+ (_:_) -> error "too many parses (how??)"++-- | Obtain the tag for a sum type value using the constructor name directly+-- (with a null terminator).+--+-- This is probably not what you want in a binary representation, but it's safe+-- and may be useful for debugging.+--+-- The refine force is safe under the assumption that Haskell constructor names+-- are UTF-8 with no null bytes allowed. I haven't confirmed that, but I'm+-- fairly certain.+cSumTagNullTerm :: String -> AsByteString 'C+cSumTagNullTerm = reallyUnsafeRefine . Text.encodeUtf8 . Text.pack++cDef :: Cfg (AsByteString 'C)+cDef = Cfg { cSumTag = cSumTagNullTerm }
+ src/Binrep/Generic/BLen.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE UndecidableInstances #-} -- required for TypeError >:(++module Binrep.Generic.BLen where++import GHC.Generics+import GHC.TypeLits ( TypeError )++import Binrep.BLen+import Binrep.Generic.Internal++blenGeneric :: (Generic a, GBLen (Rep a), BLen w) => Cfg w -> a -> BLenT+blenGeneric cfg = gblen cfg . from++class GBLen f where+ gblen :: BLen w => Cfg w -> f p -> BLenT++-- | Empty constructor.+instance GBLen U1 where+ gblen _ U1 = 0++-- | Field.+instance BLen c => GBLen (K1 i c) where+ gblen _ (K1 c) = blen c++-- | Product type fields are consecutive.+instance (GBLen l, GBLen r) => GBLen (l :*: r) where+ gblen cfg (l :*: r) = gblen cfg l + gblen cfg r++-- | Constructor sums are differentiated by a prefix tag.+instance GBLenSum (l :+: r) => GBLen (l :+: r) where+ gblen = gblensum++-- | Refuse to derive instance for void datatype.+instance TypeError GErrRefuseVoid => GBLen V1 where+ gblen = undefined++-- | Any datatype, constructor or record.+instance GBLen f => GBLen (M1 i d f) where+ gblen cfg = gblen cfg . unM1++--------------------------------------------------------------------------------++class GBLenSum f where+ gblensum :: BLen w => Cfg w -> f p -> BLenT++instance (GBLenSum l, GBLenSum r) => GBLenSum (l :+: r) where+ gblensum cfg = \case L1 l -> gblensum cfg l+ R1 r -> gblensum cfg r++instance (GBLen f, Constructor c) => GBLenSum (C1 c f) where+ gblensum cfg x = blen ((cSumTag cfg) (conName' @c)) + gblen cfg (unM1 x)
+ src/Binrep/Generic/CBLen.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE UndecidableInstances #-}++{- | Generically derive 'CBLen' type family instances.++This is mostly playing around -- I've only just learned regular GHC generics,+and pulling everything up to the type level is even more confusing and weird.++A 'CBLen' instance usually indicates a type is either extremely simple or comes+with size information in the type. Be careful deriving or writing instances for+your own types - @BLen@ is usually correct/sufficient.++You can attempt to derive a 'CBLen' type family instance generically for a type+via++ type instance CBLen a = CBLenGeneric w a++As with deriving @BLen@, you must provide the type used to store the sum tag for+sum types.++Then try doing something with it e.g. have GHC derive a @BLen@ instance for you+via the default method (that reifies CBLen)++ deriving anyclass BLen a++Hopefully it either compiles, or you get a useful type error. If not, sorry.+-}++module Binrep.Generic.CBLen where++import Binrep.CBLen+import Binrep.Generic.Internal++import GHC.Generics+import GHC.TypeLits+import Data.Kind++import Data.Type.Equality+import Data.Type.Bool++type CBLenGeneric w a = GCBLen w (Rep a)++type family GCBLen w (f :: k -> Type) :: Natural where+ GCBLen _ U1 = 0+ GCBLen _ (K1 i c) = CBLen c+ GCBLen w (l :*: r) = GCBLen w l + GCBLen w r++ GCBLen w (l :+: r) = CBLen w + GCBLenCaseMaybe (GCBLenSum w (l :+: r))++ GCBLen _ V1 = TypeError GErrRefuseVoid+ GCBLen w (M1 _ _ f) = GCBLen w f++--type family GCBLenSum w (f :: k -> Type) :: Maybe Natural where+type family GCBLenSum w (f :: k -> Type) where+ GCBLenSum w (C1 ('MetaCons name _ _) f) = JustX (GCBLen w f) name+ GCBLenSum w (l :+: r) = MaybeEq (GCBLenSum w l) (GCBLenSum w r)++type family MaybeEq a b where+ MaybeEq (JustX n nName) (JustX m _) = If (n == m) (JustX n nName) NothingX+ MaybeEq _ _ = NothingX++-- | I don't know how to pattern match in types without writing type families.+type family GCBLenCaseMaybe a where+ GCBLenCaseMaybe (JustX n _) = n+ GCBLenCaseMaybe NothingX =+ TypeError+ ( 'Text "Two constructors didn't have equal constant size."+ ':$$: 'Text "Sry dunno how to thread errors thru LOL"+ )++-- TODO rewrite this stuff to thread error info through!+data JustX a b+data NothingX
+ src/Binrep/Generic/Get.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE UndecidableInstances #-} -- required for TypeError >:(++module Binrep.Generic.Get where++import GHC.Generics+import GHC.TypeLits ( TypeError )++import Binrep.Get+import Binrep.Generic.Internal++import FlatParse.Basic qualified as FP+import FlatParse.Basic ( Parser )+import Control.Applicative ( (<|>) )++getGeneric :: (Generic a, GGet (Rep a), Get w, Eq w, Show w) => Cfg w -> Parser String a+getGeneric cfg = to <$> gget cfg++class GGet f where+ gget :: (Get w, Eq w, Show w) => Cfg w -> Parser String (f a)++-- | Empty constructor.+instance GGet U1 where+ gget _ = return U1++-- | Field.+instance Get c => GGet (K1 i c) where+ gget _ = K1 <$> get++-- | Product type fields are consecutive.+instance (GGet l, GGet r) => GGet (l :*: r) where+ gget cfg = do l <- gget cfg+ r <- gget cfg+ return $ l :*: r++-- | Constructor sums are differentiated by a prefix tag.+instance GGetSum (l :+: r) => GGet (l :+: r) where+ gget cfg = do+ tag <- get+ case ggetsum cfg tag of+ Just parser -> parser+ Nothing -> FP.err $ "invalid sum type tag: "<>show tag++-- | Refuse to derive instance for void datatype.+instance TypeError GErrRefuseVoid => GGet V1 where+ gget = undefined++-- | Any datatype, constructor or record.+instance GGet f => GGet (M1 i d f) where+ gget cfg = M1 <$> gget cfg++--------------------------------------------------------------------------------++class GGetSum f where+ ggetsum :: (Get w, Eq w, Show w) => Cfg w -> w -> Maybe (Parser String (f a))++instance (GGetSum l, GGetSum r) => GGetSum (l :+: r) where+ ggetsum cfg tag = l <|> r+ where+ l = fmap L1 <$> ggetsum cfg tag+ r = fmap R1 <$> ggetsum cfg tag++-- | Bad. Need to wrap this like SumFromString in Aeson.+instance (GGet r, Constructor c) => GGetSum (C1 c r) where+ ggetsum cfg tag+ | tag == (cSumTag cfg) (conName' @c) = Just $ gget cfg+ | otherwise = Nothing
+ src/Binrep/Generic/Internal.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE AllowAmbiguousTypes #-}++module Binrep.Generic.Internal where++import GHC.TypeLits+import GHC.Generics++data Cfg a = Cfg+ { cSumTag :: String -> a+ -- ^ How to turn a constructor name into a byte tag.+ }++-- | Common type error string for when GHC attempts to derive an binrep instance+-- for a (the?) void datatype @V1@.+type GErrRefuseVoid =+ 'Text "Refusing to derive binary representation for void datatype"++-- | 'conName' without the value (only used as a proxy). Lets us push our+-- 'undefined's into one place.+conName' :: forall c. Constructor c => String+conName' = conName @c undefined
+ src/Binrep/Generic/Put.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE UndecidableInstances #-} -- required for TypeError >:(++module Binrep.Generic.Put where++import GHC.Generics+import GHC.TypeLits ( TypeError )++import Binrep.Put+import Binrep.Generic.Internal++putGeneric :: (Generic a, GPut (Rep a), Put w) => Cfg w -> a -> Builder+putGeneric cfg = gput cfg . from++class GPut f where+ gput :: Put w => Cfg w -> f p -> Builder++-- | Empty constructor.+instance GPut U1 where+ gput _ U1 = mempty++-- | Field.+instance Put c => GPut (K1 i c) where+ gput _ = put . unK1++-- | Product type fields are consecutive.+instance (GPut l, GPut r) => GPut (l :*: r) where+ gput cfg (l :*: r) = gput cfg l <> gput cfg r++-- | Constructor sums are differentiated by a prefix tag.+instance (GPutSum (l :+: r), GetConName (l :+: r)) => GPut (l :+: r) where+ gput = gputsum++-- | Refuse to derive instance for void datatype.+instance TypeError GErrRefuseVoid => GPut V1 where+ gput = undefined++-- | Any datatype, constructor or record.+instance GPut f => GPut (M1 i d f) where+ gput cfg = gput cfg . unM1++--------------------------------------------------------------------------------++class GPutSum f where+ gputsum :: Put w => Cfg w -> f a -> Builder++instance (GPutSum l, GPutSum r) => GPutSum (l :+: r) where+ gputsum cfg = \case L1 a -> gputsum cfg a+ R1 a -> gputsum cfg a++instance (GPut r, Constructor c) => GPutSum (C1 c r) where+ gputsum cfg x = putTag <> putConstructor+ where putTag = put $ (cSumTag cfg) (conName' @c)+ putConstructor = gput cfg $ unM1 x++---++-- | Get the name of the constructor of a sum datatype.+class GetConName f where+ getConName :: f a -> String++instance (GetConName a, GetConName b) => GetConName (a :+: b) where+ getConName (L1 x) = getConName x+ getConName (R1 x) = getConName x++instance Constructor c => GetConName (C1 c a) where+ getConName = conName
+ src/Binrep/Get.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE FunctionalDependencies #-}++module Binrep.Get+ ( Getter, Get(..), runGet, runGetter+ , GetWith(..), runGetWith+ ) where++import FlatParse.Basic qualified as FP+import FlatParse.Basic ( Parser )+import Data.ByteString qualified as B+import Data.Word+import Data.Int+import GHC.Exts++type Getter a = Parser String a++class Get a where+ -- | Parse from binary.+ get :: Getter a++runGet :: Get a => B.ByteString -> Either String (a, B.ByteString)+runGet = runGetter get++runGetter :: Getter a -> B.ByteString -> Either String (a, B.ByteString)+runGetter g bs = case FP.runParser g bs of+ FP.OK a bs' -> Right (a, bs')+ FP.Fail -> Left "TODO fail"+ FP.Err e -> Left e++-- | Parse heterogeneous lists in order. No length indicator, so either fails or+-- succeeds by reaching EOF. Probably not what you usually want, but sometimes+-- used at the "top" of binary formats.+instance Get a => Get [a] where+ get = do as <- FP.many get+ FP.eof+ return as++instance (Get a, Get b) => Get (a, b) where+ get = do+ a <- get+ b <- get+ return (a, b)++instance Get B.ByteString where+ get = FP.takeRestBs++instance Get Word8 where get = FP.anyWord8+instance Get Int8 where get = FP.anyInt8++-- | A type that can be parsed from binary given some environment.+--+-- Making this levity polymorphic makes things pretty strange, but is useful.+-- See @Binrep.Example.FileTable@.+class GetWith (r :: TYPE rep) a | a -> r where+ -- | Parse from binary with the given environment.+ getWith :: r -> Getter a+ -- can no longer provide default implementation due to levity polymorphism+ --default getWith :: Get a => r -> Getter a+ --getWith _ = get++--deriving anyclass instance Get a => GetWith r [a]++-- Note that @r@ is not levity polymorphic, GHC forces it to be lifted. You+-- can't bind (LHS) a levity polymorphic value.+runGetWith+ :: GetWith (r :: TYPE LiftedRep) a+ => r -> B.ByteString -> Either String (a, B.ByteString)+runGetWith r bs = runGetter (getWith r) bs
− src/Binrep/Predicates/NullPadTo.hs
@@ -1,69 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Binrep.Predicates.NullPadTo where--import Binrep.Codec-import Binrep.ByteLen-import Binrep.Util ( tshow )-import Refined-import Refined.WithRefine-import Data.Serialize-import GHC.TypeNats-import Numeric.Natural-import GHC.Natural ( minusNaturalMaybe )-import GHC.Exts ( proxy#, Proxy# )-import Data.Typeable-import Data.ByteString qualified as BS--data NullPadTo (n :: Nat)--instance KnownNat n => ByteLen (WithRefine 'Enforced (NullPadTo n) a) where- blen = const n- where n = natVal' (proxy# :: Proxy# n)--instance (ByteLen a, KnownNat n) => Predicate (NullPadTo n) a where- validate p a- | len > n- = throwRefineOtherException (typeRep p) $- "too long: " <> tshow len <> " > " <> tshow n- | otherwise = success- where- n = natVal' (proxy# :: Proxy# n)- len = blen a---- | predicate is inherently enforced due to checking length to calculate how--- many succeeding nulls to parse------ Note that the consumer probably doesn't care about the content of the--- padding, just that the data is chunked correctly. I figure we care about--- correctness here, so it'd be nice to know about the padding well-formedness--- (i.e. that it's all nulls).-instance (BinaryCodec a, ByteLen a, KnownNat n)- => BinaryCodec (WithRefine 'Enforced (NullPadTo n) a) where- fromBin = do- a <- fromBin- let len = blen a- case minusNaturalMaybe n len of- Nothing -> fail $ "too long: " <> show len <> " > " <> show n- Just nullstrLen -> do- getNNulls nullstrLen- return $ reallyUnsafeEnforce a- where- n = natVal' (proxy# :: Proxy# n)- toBin wrnpa = do- let npa = unWithRefine wrnpa- toBin npa- let paddingLength = n - blen npa- putByteString $ BS.replicate (fromIntegral paddingLength) 0x00- where- n = natVal' (proxy# :: Proxy# n)--getNNulls :: Natural -> Get ()-getNNulls = \case 0 -> return ()- n -> getWord8 >>= \case- 0x00 -> getNNulls $ n-1- nonNull -> do- offset <- bytesRead- fail $ "expected null, found: "<> show nonNull- <> " at offset " <> show offset- <> ", " <> show n <> " more nulls to go"
+ src/Binrep/Put.hs view
@@ -0,0 +1,63 @@+module Binrep.Put where++import Mason.Builder qualified as Mason++import Data.ByteString qualified as B+import Data.Word+import Data.Int++type Builder = Mason.BuilderFor Mason.StrictByteStringBackend++class Put a where+ -- | Serialize to binary.+ put :: a -> Builder++-- | Run the serializer.+runPut :: Put a => a -> B.ByteString+runPut = runBuilder . put++runBuilder :: Builder -> B.ByteString+runBuilder = Mason.toStrictByteString++-- | Serialize each element in order. No length indicator, so parse until either+-- error or EOF. Usually not what you want, but sometimes used at the "top" of+-- binary formats.+instance Put a => Put [a] where+ put = mconcat . map put++instance (Put a, Put b) => Put (a, b) where+ put (a, b) = put a <> put b++-- | Serialize the bytestring as-is.+--+-- Careful -- the only way you're going to be able to parse this is to read+-- until EOF.+instance Put B.ByteString where+ put = Mason.byteString+ {-# INLINE put #-}++-- need to give args for RankNTypes reasons I don't understand+instance Put Word8 where+ put w = Mason.word8 w+ {-# INLINE put #-}+instance Put Int8 where+ put w = Mason.int8 w+ {-# INLINE put #-}++-- | Put with inlined checks via an environment.+class PutWith r a where+ -- | Attempt to serialize to binary with the given environment.+ putWith :: r -> a -> Either String Builder+ default putWith :: Put a => r -> a -> Either String Builder+ putWith _ = putWithout++-- | Helper for wrapping a 'BinRep' into a 'BinRepWith' (for encoding).+putWithout :: Put a => a -> Either String Builder+putWithout = Right . put++instance Put a => PutWith r [a]++-- | Run the serializer with the given environment.+runPutWith :: PutWith r a => r -> a -> Either String B.ByteString+runPutWith r a = case putWith r a of Left e -> Left e+ Right x -> Right $ runBuilder x
+ src/Binrep/Type/AsciiNat.hs view
@@ -0,0 +1,112 @@+{-| Naturals represented via ASCII numerals.++A concept which sees occasional use in places where neither speed nor size+efficiency matter.++The tar file format uses it, apparently to sidestep making a decision on byte+ordering. Though digits are encoded "big-endian", so, uh. I don't get it.++I don't really see the usage of these. It seems silly and inefficient, aimed+solely at easing debugging.+-}++{-# LANGUAGE AllowAmbiguousTypes #-}++module Binrep.Type.AsciiNat where++import Binrep+import Binrep.Util ( natVal'' )++import Data.Word ( Word8 )+import Data.List.NonEmpty ( NonEmpty( (:|) ) )+import Mason.Builder qualified as Mason+import Data.ByteString qualified as B+import Data.Semigroup ( sconcat )++import GHC.TypeNats ( Natural, KnownNat )+import GHC.Num.Natural ( naturalSizeInBase#, naturalToWord# )++import GHC.Generics ( Generic )+import Data.Data ( Data )+import Numeric ( showOct, showHex, showBin, showInt )++import FlatParse.Basic qualified as FP++-- | A 'Natural' represented in binary as an ASCII string, where each character+-- a is a digit in the given base (> 1).+--+-- 'Show' instances display the stored number in the given base. If the base has+-- a common prefix (e.g. @0x@ for hex), it is used.+newtype AsciiNat (base :: Natural) = AsciiNat { getAsciiNat :: Natural }+ deriving stock (Generic, Data)+ deriving (Eq, Ord) via Natural++instance Show (AsciiNat 2) where showsPrec _ n = showString "0b" . showBin (getAsciiNat n)+instance Show (AsciiNat 8) where showsPrec _ n = showString "0o" . showOct (getAsciiNat n)+instance Show (AsciiNat 10) where showsPrec _ n = showInt (getAsciiNat n)+instance Show (AsciiNat 16) where showsPrec _ n = showString "0x" . showHex (getAsciiNat n)++-- | Compare two 'AsciiNat's with arbitrary bases.+asciiNatCompare :: AsciiNat b1 -> AsciiNat b2 -> Ordering+asciiNatCompare (AsciiNat n1) (AsciiNat n2) = compare n1 n2++-- | The bytelength of an 'AsciiNat' is the number of digits in the number in+-- the given base. We can calculate this generically with great efficiency+-- using GHC primitives.+instance KnownNat base => BLen (AsciiNat base) where+ blen (AsciiNat n) = wordToBLen# (naturalSizeInBase# (naturalToWord# base) n)+ where base = natVal'' @base++--------------------------------------------------------------------------------++instance Put (AsciiNat 8) where+ put = natToAsciiBytes (+ 0x30) 8 . getAsciiNat++instance Get (AsciiNat 8) where+ get = do+ bs <- get+ case asciiBytesToNat octalFromAsciiDigit 8 bs of+ Left bs' -> FP.err $ "TODO " <> show bs'+ Right n -> return $ AsciiNat n++octalFromAsciiDigit :: Word8 -> Maybe Word8+octalFromAsciiDigit = \case+ 0x30 -> Just 0+ 0x31 -> Just 1+ 0x32 -> Just 2+ 0x33 -> Just 3+ 0x34 -> Just 4+ 0x35 -> Just 5+ 0x36 -> Just 6+ 0x37 -> Just 7+ _ -> Nothing++--------------------------------------------------------------------------------++natToAsciiBytes :: (Word8 -> Word8) -> Natural -> Natural -> Builder+natToAsciiBytes f base =+ sconcat . fmap (\w -> Mason.word8 w) . fmap f . digits @Word8 base++asciiBytesToNat :: (Word8 -> Maybe Word8) -> Natural -> B.ByteString -> Either Word8 Natural+asciiBytesToNat f base bs =+ case B.foldr go (Right (0, 0)) bs of+ Left w -> Left w+ Right (n, _) -> Right n+ where+ go :: Word8 -> Either Word8 (Natural, Natural) -> Either Word8 (Natural, Natural)+ go _ (Left w) = Left w+ go w (Right (n, expo)) =+ case f w of+ Nothing -> Left w+ Just d -> Right (n + fromIntegral d * base^expo, expo+1)++digits :: forall b a. (Integral a, Integral b) => a -> a -> NonEmpty b+digits base = go []+ where+ go s x = loop (head' :| s) tail'+ where+ head' = fromIntegral (x `mod` base)+ tail' = x `div` base+ loop s@(r :| rs) = \case+ 0 -> s+ x -> go (r : rs) x
+ src/Binrep/Type/Byte.hs view
@@ -0,0 +1,821 @@+{- | Safe, if silly, byte representation for use at the type level.++'Word8' is a special type that GHC doesn't (and I think can't) promote to the+type level. We only have 'Natural's, which are unbounded. So we define a safe,+promotable representation, to allow us to prove well-sizedness at compile time.+Then we provide a bunch of type families and reifying typeclasses to enable+going between "similar" kinds ('Natural') and types ('Word8', 'B.ByteString')+respectively.++Type-level functionality is stored in 'Binrep.Type.Byte.TypeLevel' because the+definitions are even sillier than the ones here.++Do not use this on the term level. That would be _extremely_ silly.+-}++{-# LANGUAGE AllowAmbiguousTypes, UndecidableInstances #-}++module Binrep.Type.Byte where++import Mason.Builder qualified as Mason+import Data.ByteString.Builder.Prim.Internal qualified as BI+import Binrep.Util ( natVal'' )+import Binrep.Put ( Builder )+import GHC.TypeNats+import GHC.Exts++-- Needs to be a function type to work. Interesting. It's perhaps not an+-- improvement on regular boxed. But interesting idea, so sticking with it.+class ByteVal (n :: Natural) where byteVal :: Proxy# n -> Word8#++instance ByteVal 0x00 where+ byteVal _ = wordToWord8# 0x00##+ {-# INLINE byteVal #-}+instance ByteVal 0x01 where+ byteVal _ = wordToWord8# 0x01##+ {-# INLINE byteVal #-}+instance ByteVal 0x02 where+ byteVal _ = wordToWord8# 0x02##+ {-# INLINE byteVal #-}+instance ByteVal 0x03 where+ byteVal _ = wordToWord8# 0x03##+ {-# INLINE byteVal #-}+instance ByteVal 0x04 where+ byteVal _ = wordToWord8# 0x04##+ {-# INLINE byteVal #-}+instance ByteVal 0x05 where+ byteVal _ = wordToWord8# 0x05##+ {-# INLINE byteVal #-}+instance ByteVal 0x06 where+ byteVal _ = wordToWord8# 0x06##+ {-# INLINE byteVal #-}+instance ByteVal 0x07 where+ byteVal _ = wordToWord8# 0x07##+ {-# INLINE byteVal #-}+instance ByteVal 0x08 where+ byteVal _ = wordToWord8# 0x08##+ {-# INLINE byteVal #-}+instance ByteVal 0x09 where+ byteVal _ = wordToWord8# 0x09##+ {-# INLINE byteVal #-}+instance ByteVal 0x0a where+ byteVal _ = wordToWord8# 0x0a##+ {-# INLINE byteVal #-}+instance ByteVal 0x0b where+ byteVal _ = wordToWord8# 0x0b##+ {-# INLINE byteVal #-}+instance ByteVal 0x0c where+ byteVal _ = wordToWord8# 0x0c##+ {-# INLINE byteVal #-}+instance ByteVal 0x0d where+ byteVal _ = wordToWord8# 0x0d##+ {-# INLINE byteVal #-}+instance ByteVal 0x0e where+ byteVal _ = wordToWord8# 0x0e##+ {-# INLINE byteVal #-}+instance ByteVal 0x0f where+ byteVal _ = wordToWord8# 0x0f##+ {-# INLINE byteVal #-}+instance ByteVal 0x10 where+ byteVal _ = wordToWord8# 0x10##+ {-# INLINE byteVal #-}+instance ByteVal 0x11 where+ byteVal _ = wordToWord8# 0x11##+ {-# INLINE byteVal #-}+instance ByteVal 0x12 where+ byteVal _ = wordToWord8# 0x12##+ {-# INLINE byteVal #-}+instance ByteVal 0x13 where+ byteVal _ = wordToWord8# 0x13##+ {-# INLINE byteVal #-}+instance ByteVal 0x14 where+ byteVal _ = wordToWord8# 0x14##+ {-# INLINE byteVal #-}+instance ByteVal 0x15 where+ byteVal _ = wordToWord8# 0x15##+ {-# INLINE byteVal #-}+instance ByteVal 0x16 where+ byteVal _ = wordToWord8# 0x16##+ {-# INLINE byteVal #-}+instance ByteVal 0x17 where+ byteVal _ = wordToWord8# 0x17##+ {-# INLINE byteVal #-}+instance ByteVal 0x18 where+ byteVal _ = wordToWord8# 0x18##+ {-# INLINE byteVal #-}+instance ByteVal 0x19 where+ byteVal _ = wordToWord8# 0x19##+ {-# INLINE byteVal #-}+instance ByteVal 0x1a where+ byteVal _ = wordToWord8# 0x1a##+ {-# INLINE byteVal #-}+instance ByteVal 0x1b where+ byteVal _ = wordToWord8# 0x1b##+ {-# INLINE byteVal #-}+instance ByteVal 0x1c where+ byteVal _ = wordToWord8# 0x1c##+ {-# INLINE byteVal #-}+instance ByteVal 0x1d where+ byteVal _ = wordToWord8# 0x1d##+ {-# INLINE byteVal #-}+instance ByteVal 0x1e where+ byteVal _ = wordToWord8# 0x1e##+ {-# INLINE byteVal #-}+instance ByteVal 0x1f where+ byteVal _ = wordToWord8# 0x1f##+ {-# INLINE byteVal #-}+instance ByteVal 0x20 where+ byteVal _ = wordToWord8# 0x20##+ {-# INLINE byteVal #-}+instance ByteVal 0x21 where+ byteVal _ = wordToWord8# 0x21##+ {-# INLINE byteVal #-}+instance ByteVal 0x22 where+ byteVal _ = wordToWord8# 0x22##+ {-# INLINE byteVal #-}+instance ByteVal 0x23 where+ byteVal _ = wordToWord8# 0x23##+ {-# INLINE byteVal #-}+instance ByteVal 0x24 where+ byteVal _ = wordToWord8# 0x24##+ {-# INLINE byteVal #-}+instance ByteVal 0x25 where+ byteVal _ = wordToWord8# 0x25##+ {-# INLINE byteVal #-}+instance ByteVal 0x26 where+ byteVal _ = wordToWord8# 0x26##+ {-# INLINE byteVal #-}+instance ByteVal 0x27 where+ byteVal _ = wordToWord8# 0x27##+ {-# INLINE byteVal #-}+instance ByteVal 0x28 where+ byteVal _ = wordToWord8# 0x28##+ {-# INLINE byteVal #-}+instance ByteVal 0x29 where+ byteVal _ = wordToWord8# 0x29##+ {-# INLINE byteVal #-}+instance ByteVal 0x2a where+ byteVal _ = wordToWord8# 0x2a##+ {-# INLINE byteVal #-}+instance ByteVal 0x2b where+ byteVal _ = wordToWord8# 0x2b##+ {-# INLINE byteVal #-}+instance ByteVal 0x2c where+ byteVal _ = wordToWord8# 0x2c##+ {-# INLINE byteVal #-}+instance ByteVal 0x2d where+ byteVal _ = wordToWord8# 0x2d##+ {-# INLINE byteVal #-}+instance ByteVal 0x2e where+ byteVal _ = wordToWord8# 0x2e##+ {-# INLINE byteVal #-}+instance ByteVal 0x2f where+ byteVal _ = wordToWord8# 0x2f##+ {-# INLINE byteVal #-}+instance ByteVal 0x30 where+ byteVal _ = wordToWord8# 0x30##+ {-# INLINE byteVal #-}+instance ByteVal 0x31 where+ byteVal _ = wordToWord8# 0x31##+ {-# INLINE byteVal #-}+instance ByteVal 0x32 where+ byteVal _ = wordToWord8# 0x32##+ {-# INLINE byteVal #-}+instance ByteVal 0x33 where+ byteVal _ = wordToWord8# 0x33##+ {-# INLINE byteVal #-}+instance ByteVal 0x34 where+ byteVal _ = wordToWord8# 0x34##+ {-# INLINE byteVal #-}+instance ByteVal 0x35 where+ byteVal _ = wordToWord8# 0x35##+ {-# INLINE byteVal #-}+instance ByteVal 0x36 where+ byteVal _ = wordToWord8# 0x36##+ {-# INLINE byteVal #-}+instance ByteVal 0x37 where+ byteVal _ = wordToWord8# 0x37##+ {-# INLINE byteVal #-}+instance ByteVal 0x38 where+ byteVal _ = wordToWord8# 0x38##+ {-# INLINE byteVal #-}+instance ByteVal 0x39 where+ byteVal _ = wordToWord8# 0x39##+ {-# INLINE byteVal #-}+instance ByteVal 0x3a where+ byteVal _ = wordToWord8# 0x3a##+ {-# INLINE byteVal #-}+instance ByteVal 0x3b where+ byteVal _ = wordToWord8# 0x3b##+ {-# INLINE byteVal #-}+instance ByteVal 0x3c where+ byteVal _ = wordToWord8# 0x3c##+ {-# INLINE byteVal #-}+instance ByteVal 0x3d where+ byteVal _ = wordToWord8# 0x3d##+ {-# INLINE byteVal #-}+instance ByteVal 0x3e where+ byteVal _ = wordToWord8# 0x3e##+ {-# INLINE byteVal #-}+instance ByteVal 0x3f where+ byteVal _ = wordToWord8# 0x3f##+ {-# INLINE byteVal #-}+instance ByteVal 0x40 where+ byteVal _ = wordToWord8# 0x40##+ {-# INLINE byteVal #-}+instance ByteVal 0x41 where+ byteVal _ = wordToWord8# 0x41##+ {-# INLINE byteVal #-}+instance ByteVal 0x42 where+ byteVal _ = wordToWord8# 0x42##+ {-# INLINE byteVal #-}+instance ByteVal 0x43 where+ byteVal _ = wordToWord8# 0x43##+ {-# INLINE byteVal #-}+instance ByteVal 0x44 where+ byteVal _ = wordToWord8# 0x44##+ {-# INLINE byteVal #-}+instance ByteVal 0x45 where+ byteVal _ = wordToWord8# 0x45##+ {-# INLINE byteVal #-}+instance ByteVal 0x46 where+ byteVal _ = wordToWord8# 0x46##+ {-# INLINE byteVal #-}+instance ByteVal 0x47 where+ byteVal _ = wordToWord8# 0x47##+ {-# INLINE byteVal #-}+instance ByteVal 0x48 where+ byteVal _ = wordToWord8# 0x48##+ {-# INLINE byteVal #-}+instance ByteVal 0x49 where+ byteVal _ = wordToWord8# 0x49##+ {-# INLINE byteVal #-}+instance ByteVal 0x4a where+ byteVal _ = wordToWord8# 0x4a##+ {-# INLINE byteVal #-}+instance ByteVal 0x4b where+ byteVal _ = wordToWord8# 0x4b##+ {-# INLINE byteVal #-}+instance ByteVal 0x4c where+ byteVal _ = wordToWord8# 0x4c##+ {-# INLINE byteVal #-}+instance ByteVal 0x4d where+ byteVal _ = wordToWord8# 0x4d##+ {-# INLINE byteVal #-}+instance ByteVal 0x4e where+ byteVal _ = wordToWord8# 0x4e##+ {-# INLINE byteVal #-}+instance ByteVal 0x4f where+ byteVal _ = wordToWord8# 0x4f##+ {-# INLINE byteVal #-}+instance ByteVal 0x50 where+ byteVal _ = wordToWord8# 0x50##+ {-# INLINE byteVal #-}+instance ByteVal 0x51 where+ byteVal _ = wordToWord8# 0x51##+ {-# INLINE byteVal #-}+instance ByteVal 0x52 where+ byteVal _ = wordToWord8# 0x52##+ {-# INLINE byteVal #-}+instance ByteVal 0x53 where+ byteVal _ = wordToWord8# 0x53##+ {-# INLINE byteVal #-}+instance ByteVal 0x54 where+ byteVal _ = wordToWord8# 0x54##+ {-# INLINE byteVal #-}+instance ByteVal 0x55 where+ byteVal _ = wordToWord8# 0x55##+ {-# INLINE byteVal #-}+instance ByteVal 0x56 where+ byteVal _ = wordToWord8# 0x56##+ {-# INLINE byteVal #-}+instance ByteVal 0x57 where+ byteVal _ = wordToWord8# 0x57##+ {-# INLINE byteVal #-}+instance ByteVal 0x58 where+ byteVal _ = wordToWord8# 0x58##+ {-# INLINE byteVal #-}+instance ByteVal 0x59 where+ byteVal _ = wordToWord8# 0x59##+ {-# INLINE byteVal #-}+instance ByteVal 0x5a where+ byteVal _ = wordToWord8# 0x5a##+ {-# INLINE byteVal #-}+instance ByteVal 0x5b where+ byteVal _ = wordToWord8# 0x5b##+ {-# INLINE byteVal #-}+instance ByteVal 0x5c where+ byteVal _ = wordToWord8# 0x5c##+ {-# INLINE byteVal #-}+instance ByteVal 0x5d where+ byteVal _ = wordToWord8# 0x5d##+ {-# INLINE byteVal #-}+instance ByteVal 0x5e where+ byteVal _ = wordToWord8# 0x5e##+ {-# INLINE byteVal #-}+instance ByteVal 0x5f where+ byteVal _ = wordToWord8# 0x5f##+ {-# INLINE byteVal #-}+instance ByteVal 0x60 where+ byteVal _ = wordToWord8# 0x60##+ {-# INLINE byteVal #-}+instance ByteVal 0x61 where+ byteVal _ = wordToWord8# 0x61##+ {-# INLINE byteVal #-}+instance ByteVal 0x62 where+ byteVal _ = wordToWord8# 0x62##+ {-# INLINE byteVal #-}+instance ByteVal 0x63 where+ byteVal _ = wordToWord8# 0x63##+ {-# INLINE byteVal #-}+instance ByteVal 0x64 where+ byteVal _ = wordToWord8# 0x64##+ {-# INLINE byteVal #-}+instance ByteVal 0x65 where+ byteVal _ = wordToWord8# 0x65##+ {-# INLINE byteVal #-}+instance ByteVal 0x66 where+ byteVal _ = wordToWord8# 0x66##+ {-# INLINE byteVal #-}+instance ByteVal 0x67 where+ byteVal _ = wordToWord8# 0x67##+ {-# INLINE byteVal #-}+instance ByteVal 0x68 where+ byteVal _ = wordToWord8# 0x68##+ {-# INLINE byteVal #-}+instance ByteVal 0x69 where+ byteVal _ = wordToWord8# 0x69##+ {-# INLINE byteVal #-}+instance ByteVal 0x6a where+ byteVal _ = wordToWord8# 0x6a##+ {-# INLINE byteVal #-}+instance ByteVal 0x6b where+ byteVal _ = wordToWord8# 0x6b##+ {-# INLINE byteVal #-}+instance ByteVal 0x6c where+ byteVal _ = wordToWord8# 0x6c##+ {-# INLINE byteVal #-}+instance ByteVal 0x6d where+ byteVal _ = wordToWord8# 0x6d##+ {-# INLINE byteVal #-}+instance ByteVal 0x6e where+ byteVal _ = wordToWord8# 0x6e##+ {-# INLINE byteVal #-}+instance ByteVal 0x6f where+ byteVal _ = wordToWord8# 0x6f##+ {-# INLINE byteVal #-}+instance ByteVal 0x70 where+ byteVal _ = wordToWord8# 0x70##+ {-# INLINE byteVal #-}+instance ByteVal 0x71 where+ byteVal _ = wordToWord8# 0x71##+ {-# INLINE byteVal #-}+instance ByteVal 0x72 where+ byteVal _ = wordToWord8# 0x72##+ {-# INLINE byteVal #-}+instance ByteVal 0x73 where+ byteVal _ = wordToWord8# 0x73##+ {-# INLINE byteVal #-}+instance ByteVal 0x74 where+ byteVal _ = wordToWord8# 0x74##+ {-# INLINE byteVal #-}+instance ByteVal 0x75 where+ byteVal _ = wordToWord8# 0x75##+ {-# INLINE byteVal #-}+instance ByteVal 0x76 where+ byteVal _ = wordToWord8# 0x76##+ {-# INLINE byteVal #-}+instance ByteVal 0x77 where+ byteVal _ = wordToWord8# 0x77##+ {-# INLINE byteVal #-}+instance ByteVal 0x78 where+ byteVal _ = wordToWord8# 0x78##+ {-# INLINE byteVal #-}+instance ByteVal 0x79 where+ byteVal _ = wordToWord8# 0x79##+ {-# INLINE byteVal #-}+instance ByteVal 0x7a where+ byteVal _ = wordToWord8# 0x7a##+ {-# INLINE byteVal #-}+instance ByteVal 0x7b where+ byteVal _ = wordToWord8# 0x7b##+ {-# INLINE byteVal #-}+instance ByteVal 0x7c where+ byteVal _ = wordToWord8# 0x7c##+ {-# INLINE byteVal #-}+instance ByteVal 0x7d where+ byteVal _ = wordToWord8# 0x7d##+ {-# INLINE byteVal #-}+instance ByteVal 0x7e where+ byteVal _ = wordToWord8# 0x7e##+ {-# INLINE byteVal #-}+instance ByteVal 0x7f where+ byteVal _ = wordToWord8# 0x7f##+ {-# INLINE byteVal #-}+instance ByteVal 0x80 where+ byteVal _ = wordToWord8# 0x80##+ {-# INLINE byteVal #-}+instance ByteVal 0x81 where+ byteVal _ = wordToWord8# 0x81##+ {-# INLINE byteVal #-}+instance ByteVal 0x82 where+ byteVal _ = wordToWord8# 0x82##+ {-# INLINE byteVal #-}+instance ByteVal 0x83 where+ byteVal _ = wordToWord8# 0x83##+ {-# INLINE byteVal #-}+instance ByteVal 0x84 where+ byteVal _ = wordToWord8# 0x84##+ {-# INLINE byteVal #-}+instance ByteVal 0x85 where+ byteVal _ = wordToWord8# 0x85##+ {-# INLINE byteVal #-}+instance ByteVal 0x86 where+ byteVal _ = wordToWord8# 0x86##+ {-# INLINE byteVal #-}+instance ByteVal 0x87 where+ byteVal _ = wordToWord8# 0x87##+ {-# INLINE byteVal #-}+instance ByteVal 0x88 where+ byteVal _ = wordToWord8# 0x88##+ {-# INLINE byteVal #-}+instance ByteVal 0x89 where+ byteVal _ = wordToWord8# 0x89##+ {-# INLINE byteVal #-}+instance ByteVal 0x8a where+ byteVal _ = wordToWord8# 0x8a##+ {-# INLINE byteVal #-}+instance ByteVal 0x8b where+ byteVal _ = wordToWord8# 0x8b##+ {-# INLINE byteVal #-}+instance ByteVal 0x8c where+ byteVal _ = wordToWord8# 0x8c##+ {-# INLINE byteVal #-}+instance ByteVal 0x8d where+ byteVal _ = wordToWord8# 0x8d##+ {-# INLINE byteVal #-}+instance ByteVal 0x8e where+ byteVal _ = wordToWord8# 0x8e##+ {-# INLINE byteVal #-}+instance ByteVal 0x8f where+ byteVal _ = wordToWord8# 0x8f##+ {-# INLINE byteVal #-}+instance ByteVal 0x90 where+ byteVal _ = wordToWord8# 0x90##+ {-# INLINE byteVal #-}+instance ByteVal 0x91 where+ byteVal _ = wordToWord8# 0x91##+ {-# INLINE byteVal #-}+instance ByteVal 0x92 where+ byteVal _ = wordToWord8# 0x92##+ {-# INLINE byteVal #-}+instance ByteVal 0x93 where+ byteVal _ = wordToWord8# 0x93##+ {-# INLINE byteVal #-}+instance ByteVal 0x94 where+ byteVal _ = wordToWord8# 0x94##+ {-# INLINE byteVal #-}+instance ByteVal 0x95 where+ byteVal _ = wordToWord8# 0x95##+ {-# INLINE byteVal #-}+instance ByteVal 0x96 where+ byteVal _ = wordToWord8# 0x96##+ {-# INLINE byteVal #-}+instance ByteVal 0x97 where+ byteVal _ = wordToWord8# 0x97##+ {-# INLINE byteVal #-}+instance ByteVal 0x98 where+ byteVal _ = wordToWord8# 0x98##+ {-# INLINE byteVal #-}+instance ByteVal 0x99 where+ byteVal _ = wordToWord8# 0x99##+ {-# INLINE byteVal #-}+instance ByteVal 0x9a where+ byteVal _ = wordToWord8# 0x9a##+ {-# INLINE byteVal #-}+instance ByteVal 0x9b where+ byteVal _ = wordToWord8# 0x9b##+ {-# INLINE byteVal #-}+instance ByteVal 0x9c where+ byteVal _ = wordToWord8# 0x9c##+ {-# INLINE byteVal #-}+instance ByteVal 0x9d where+ byteVal _ = wordToWord8# 0x9d##+ {-# INLINE byteVal #-}+instance ByteVal 0x9e where+ byteVal _ = wordToWord8# 0x9e##+ {-# INLINE byteVal #-}+instance ByteVal 0x9f where+ byteVal _ = wordToWord8# 0x9f##+ {-# INLINE byteVal #-}+instance ByteVal 0xa0 where+ byteVal _ = wordToWord8# 0xa0##+ {-# INLINE byteVal #-}+instance ByteVal 0xa1 where+ byteVal _ = wordToWord8# 0xa1##+ {-# INLINE byteVal #-}+instance ByteVal 0xa2 where+ byteVal _ = wordToWord8# 0xa2##+ {-# INLINE byteVal #-}+instance ByteVal 0xa3 where+ byteVal _ = wordToWord8# 0xa3##+ {-# INLINE byteVal #-}+instance ByteVal 0xa4 where+ byteVal _ = wordToWord8# 0xa4##+ {-# INLINE byteVal #-}+instance ByteVal 0xa5 where+ byteVal _ = wordToWord8# 0xa5##+ {-# INLINE byteVal #-}+instance ByteVal 0xa6 where+ byteVal _ = wordToWord8# 0xa6##+ {-# INLINE byteVal #-}+instance ByteVal 0xa7 where+ byteVal _ = wordToWord8# 0xa7##+ {-# INLINE byteVal #-}+instance ByteVal 0xa8 where+ byteVal _ = wordToWord8# 0xa8##+ {-# INLINE byteVal #-}+instance ByteVal 0xa9 where+ byteVal _ = wordToWord8# 0xa9##+ {-# INLINE byteVal #-}+instance ByteVal 0xaa where+ byteVal _ = wordToWord8# 0xaa##+ {-# INLINE byteVal #-}+instance ByteVal 0xab where+ byteVal _ = wordToWord8# 0xab##+ {-# INLINE byteVal #-}+instance ByteVal 0xac where+ byteVal _ = wordToWord8# 0xac##+ {-# INLINE byteVal #-}+instance ByteVal 0xad where+ byteVal _ = wordToWord8# 0xad##+ {-# INLINE byteVal #-}+instance ByteVal 0xae where+ byteVal _ = wordToWord8# 0xae##+ {-# INLINE byteVal #-}+instance ByteVal 0xaf where+ byteVal _ = wordToWord8# 0xaf##+ {-# INLINE byteVal #-}+instance ByteVal 0xb0 where+ byteVal _ = wordToWord8# 0xb0##+ {-# INLINE byteVal #-}+instance ByteVal 0xb1 where+ byteVal _ = wordToWord8# 0xb1##+ {-# INLINE byteVal #-}+instance ByteVal 0xb2 where+ byteVal _ = wordToWord8# 0xb2##+ {-# INLINE byteVal #-}+instance ByteVal 0xb3 where+ byteVal _ = wordToWord8# 0xb3##+ {-# INLINE byteVal #-}+instance ByteVal 0xb4 where+ byteVal _ = wordToWord8# 0xb4##+ {-# INLINE byteVal #-}+instance ByteVal 0xb5 where+ byteVal _ = wordToWord8# 0xb5##+ {-# INLINE byteVal #-}+instance ByteVal 0xb6 where+ byteVal _ = wordToWord8# 0xb6##+ {-# INLINE byteVal #-}+instance ByteVal 0xb7 where+ byteVal _ = wordToWord8# 0xb7##+ {-# INLINE byteVal #-}+instance ByteVal 0xb8 where+ byteVal _ = wordToWord8# 0xb8##+ {-# INLINE byteVal #-}+instance ByteVal 0xb9 where+ byteVal _ = wordToWord8# 0xb9##+ {-# INLINE byteVal #-}+instance ByteVal 0xba where+ byteVal _ = wordToWord8# 0xba##+ {-# INLINE byteVal #-}+instance ByteVal 0xbb where+ byteVal _ = wordToWord8# 0xbb##+ {-# INLINE byteVal #-}+instance ByteVal 0xbc where+ byteVal _ = wordToWord8# 0xbc##+ {-# INLINE byteVal #-}+instance ByteVal 0xbd where+ byteVal _ = wordToWord8# 0xbd##+ {-# INLINE byteVal #-}+instance ByteVal 0xbe where+ byteVal _ = wordToWord8# 0xbe##+ {-# INLINE byteVal #-}+instance ByteVal 0xbf where+ byteVal _ = wordToWord8# 0xbf##+ {-# INLINE byteVal #-}+instance ByteVal 0xc0 where+ byteVal _ = wordToWord8# 0xc0##+ {-# INLINE byteVal #-}+instance ByteVal 0xc1 where+ byteVal _ = wordToWord8# 0xc1##+ {-# INLINE byteVal #-}+instance ByteVal 0xc2 where+ byteVal _ = wordToWord8# 0xc2##+ {-# INLINE byteVal #-}+instance ByteVal 0xc3 where+ byteVal _ = wordToWord8# 0xc3##+ {-# INLINE byteVal #-}+instance ByteVal 0xc4 where+ byteVal _ = wordToWord8# 0xc4##+ {-# INLINE byteVal #-}+instance ByteVal 0xc5 where+ byteVal _ = wordToWord8# 0xc5##+ {-# INLINE byteVal #-}+instance ByteVal 0xc6 where+ byteVal _ = wordToWord8# 0xc6##+ {-# INLINE byteVal #-}+instance ByteVal 0xc7 where+ byteVal _ = wordToWord8# 0xc7##+ {-# INLINE byteVal #-}+instance ByteVal 0xc8 where+ byteVal _ = wordToWord8# 0xc8##+ {-# INLINE byteVal #-}+instance ByteVal 0xc9 where+ byteVal _ = wordToWord8# 0xc9##+ {-# INLINE byteVal #-}+instance ByteVal 0xca where+ byteVal _ = wordToWord8# 0xca##+ {-# INLINE byteVal #-}+instance ByteVal 0xcb where+ byteVal _ = wordToWord8# 0xcb##+ {-# INLINE byteVal #-}+instance ByteVal 0xcc where+ byteVal _ = wordToWord8# 0xcc##+ {-# INLINE byteVal #-}+instance ByteVal 0xcd where+ byteVal _ = wordToWord8# 0xcd##+ {-# INLINE byteVal #-}+instance ByteVal 0xce where+ byteVal _ = wordToWord8# 0xce##+ {-# INLINE byteVal #-}+instance ByteVal 0xcf where+ byteVal _ = wordToWord8# 0xcf##+ {-# INLINE byteVal #-}+instance ByteVal 0xd0 where+ byteVal _ = wordToWord8# 0xd0##+ {-# INLINE byteVal #-}+instance ByteVal 0xd1 where+ byteVal _ = wordToWord8# 0xd1##+ {-# INLINE byteVal #-}+instance ByteVal 0xd2 where+ byteVal _ = wordToWord8# 0xd2##+ {-# INLINE byteVal #-}+instance ByteVal 0xd3 where+ byteVal _ = wordToWord8# 0xd3##+ {-# INLINE byteVal #-}+instance ByteVal 0xd4 where+ byteVal _ = wordToWord8# 0xd4##+ {-# INLINE byteVal #-}+instance ByteVal 0xd5 where+ byteVal _ = wordToWord8# 0xd5##+ {-# INLINE byteVal #-}+instance ByteVal 0xd6 where+ byteVal _ = wordToWord8# 0xd6##+ {-# INLINE byteVal #-}+instance ByteVal 0xd7 where+ byteVal _ = wordToWord8# 0xd7##+ {-# INLINE byteVal #-}+instance ByteVal 0xd8 where+ byteVal _ = wordToWord8# 0xd8##+ {-# INLINE byteVal #-}+instance ByteVal 0xd9 where+ byteVal _ = wordToWord8# 0xd9##+ {-# INLINE byteVal #-}+instance ByteVal 0xda where+ byteVal _ = wordToWord8# 0xda##+ {-# INLINE byteVal #-}+instance ByteVal 0xdb where+ byteVal _ = wordToWord8# 0xdb##+ {-# INLINE byteVal #-}+instance ByteVal 0xdc where+ byteVal _ = wordToWord8# 0xdc##+ {-# INLINE byteVal #-}+instance ByteVal 0xdd where+ byteVal _ = wordToWord8# 0xdd##+ {-# INLINE byteVal #-}+instance ByteVal 0xde where+ byteVal _ = wordToWord8# 0xde##+ {-# INLINE byteVal #-}+instance ByteVal 0xdf where+ byteVal _ = wordToWord8# 0xdf##+ {-# INLINE byteVal #-}+instance ByteVal 0xe0 where+ byteVal _ = wordToWord8# 0xe0##+ {-# INLINE byteVal #-}+instance ByteVal 0xe1 where+ byteVal _ = wordToWord8# 0xe1##+ {-# INLINE byteVal #-}+instance ByteVal 0xe2 where+ byteVal _ = wordToWord8# 0xe2##+ {-# INLINE byteVal #-}+instance ByteVal 0xe3 where+ byteVal _ = wordToWord8# 0xe3##+ {-# INLINE byteVal #-}+instance ByteVal 0xe4 where+ byteVal _ = wordToWord8# 0xe4##+ {-# INLINE byteVal #-}+instance ByteVal 0xe5 where+ byteVal _ = wordToWord8# 0xe5##+ {-# INLINE byteVal #-}+instance ByteVal 0xe6 where+ byteVal _ = wordToWord8# 0xe6##+ {-# INLINE byteVal #-}+instance ByteVal 0xe7 where+ byteVal _ = wordToWord8# 0xe7##+ {-# INLINE byteVal #-}+instance ByteVal 0xe8 where+ byteVal _ = wordToWord8# 0xe8##+ {-# INLINE byteVal #-}+instance ByteVal 0xe9 where+ byteVal _ = wordToWord8# 0xe9##+ {-# INLINE byteVal #-}+instance ByteVal 0xea where+ byteVal _ = wordToWord8# 0xea##+ {-# INLINE byteVal #-}+instance ByteVal 0xeb where+ byteVal _ = wordToWord8# 0xeb##+ {-# INLINE byteVal #-}+instance ByteVal 0xec where+ byteVal _ = wordToWord8# 0xec##+ {-# INLINE byteVal #-}+instance ByteVal 0xed where+ byteVal _ = wordToWord8# 0xed##+ {-# INLINE byteVal #-}+instance ByteVal 0xee where+ byteVal _ = wordToWord8# 0xee##+ {-# INLINE byteVal #-}+instance ByteVal 0xef where+ byteVal _ = wordToWord8# 0xef##+ {-# INLINE byteVal #-}+instance ByteVal 0xf0 where+ byteVal _ = wordToWord8# 0xf0##+ {-# INLINE byteVal #-}+instance ByteVal 0xf1 where+ byteVal _ = wordToWord8# 0xf1##+ {-# INLINE byteVal #-}+instance ByteVal 0xf2 where+ byteVal _ = wordToWord8# 0xf2##+ {-# INLINE byteVal #-}+instance ByteVal 0xf3 where+ byteVal _ = wordToWord8# 0xf3##+ {-# INLINE byteVal #-}+instance ByteVal 0xf4 where+ byteVal _ = wordToWord8# 0xf4##+ {-# INLINE byteVal #-}+instance ByteVal 0xf5 where+ byteVal _ = wordToWord8# 0xf5##+ {-# INLINE byteVal #-}+instance ByteVal 0xf6 where+ byteVal _ = wordToWord8# 0xf6##+ {-# INLINE byteVal #-}+instance ByteVal 0xf7 where+ byteVal _ = wordToWord8# 0xf7##+ {-# INLINE byteVal #-}+instance ByteVal 0xf8 where+ byteVal _ = wordToWord8# 0xf8##+ {-# INLINE byteVal #-}+instance ByteVal 0xf9 where+ byteVal _ = wordToWord8# 0xf9##+ {-# INLINE byteVal #-}+instance ByteVal 0xfa where+ byteVal _ = wordToWord8# 0xfa##+ {-# INLINE byteVal #-}+instance ByteVal 0xfb where+ byteVal _ = wordToWord8# 0xfb##+ {-# INLINE byteVal #-}+instance ByteVal 0xfc where+ byteVal _ = wordToWord8# 0xfc##+ {-# INLINE byteVal #-}+instance ByteVal 0xfd where+ byteVal _ = wordToWord8# 0xfd##+ {-# INLINE byteVal #-}+instance ByteVal 0xfe where+ byteVal _ = wordToWord8# 0xfe##+ {-# INLINE byteVal #-}+instance ByteVal 0xff where+ byteVal _ = wordToWord8# 0xff##+ {-# INLINE byteVal #-}++type family Length (a :: [k]) :: Natural where+ Length '[] = 0+ Length (a ': as) = 1 + Length as++-- | Efficiently reify a list of type-level 'Byte's to a bytestring builder.+--+-- This is about as far as one should go for pointless performance here, I+-- should think.+class ByteVals (ns :: [Natural]) where byteVals :: Builder+instance (n ~ Length ns, KnownNat n, WriteByteVals ns) => ByteVals ns where+ byteVals = Mason.primFixed (BI.fixedPrim (fromIntegral n) go) ()+ where+ n = natVal'' @n+ go = \() (Ptr p#) -> writeByteVals @ns p#++class WriteByteVals (ns :: [Natural]) where writeByteVals :: Addr# -> IO ()+instance WriteByteVals '[] where writeByteVals _ = pure ()+instance (ByteVal n, WriteByteVals ns) => WriteByteVals (n ': ns) where+ writeByteVals p# =+ case runRW# (writeWord8OffAddr# p# 0# w#) of+ _ -> writeByteVals @ns (plusAddr# p# 1#)+ where w# = byteVal @n proxy#
+ src/Binrep/Type/ByteString.hs view
@@ -0,0 +1,101 @@+{- | Machine bytestrings.++I mix string and bytestring terminology here due to bad C influences, but this+module is specifically interested in bytestrings and their encoding. String/text+encoding is handled in another module.++Note that the length prefix predicate is also defined here... because that's+just Pascal-style bytestrings, extended to other types. I can't easily put it in+an orphan module, because we define byte length for *all length-prefixed types*+in one fell swoop.+-}++-- TODO redocument. pretty all over the place++{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE OverloadedStrings #-}++module Binrep.Type.ByteString where++import Binrep+import Binrep.Type.Common ( Endianness )+import Binrep.Type.Int+import Binrep.Util++import Refined+import Refined.Unsafe++import Data.ByteString qualified as B+import FlatParse.Basic qualified as FP+import FlatParse.Basic ( Parser )+import Data.Word ( Word8 )+import GHC.TypeNats ( KnownNat )++import GHC.Generics ( Generic )+import Data.Data ( Data )++import Data.Typeable ( Typeable, typeRep )++-- | Bytestring representation.+data Rep+ = C+ -- ^ C-style bytestring. Arbitrary length, terminated with a null byte.+ -- Permits no null bytes inside the bytestring.++ | Pascal ISize Endianness+ -- ^ Pascal-style bytestring. Length defined in a prefixing integer of given+ -- size and endianness.+ deriving stock (Generic, Data, Show, Eq)++-- | A bytestring using the given representation, stored in the 'Text' type.+type AsByteString (rep :: Rep) = Refined rep B.ByteString++getCString :: Parser String B.ByteString+getCString = FP.anyCString++instance BLen (AsByteString 'C) where+ blen cbs = posIntToBLen $ B.length (unrefine cbs) + 1++instance Put (AsByteString 'C) where+ put = putCString . unrefine++putCString :: B.ByteString -> Builder+putCString bs = put bs <> put @Word8 0x00++instance Get (AsByteString 'C) where+ get = reallyUnsafeRefine <$> getCString++instance (itype ~ I 'U size end, irep ~ IRep 'U size, KnownNat (CBLen irep)) => BLen (AsByteString ('Pascal size end)) where+ blen pbs = cblen @itype + blen (unrefine pbs)++instance (itype ~ I 'U size end, irep ~ IRep 'U size, Put itype, Num irep) => Put (AsByteString ('Pascal size end)) where+ put pbs = put @itype (fromIntegral (B.length bs)) <> put bs+ where bs = unrefine pbs++instance (itype ~ I 'U size end, irep ~ IRep 'U size, Integral irep, Get itype) => Get (AsByteString ('Pascal size end)) where+ get = do+ len <- get @itype+ bs <- FP.takeBs $ fromIntegral len+ return $ reallyUnsafeRefine bs++-- | A C-style bytestring must not contain any null bytes.+instance Predicate 'C B.ByteString where+ validate p bs+ | B.any (== 0x00) bs = throwRefineOtherException (typeRep p) $+ "null byte not permitted in in C-style bytestring"+ | otherwise = success++instance+ ( irep ~ IRep 'U size+ , Bounded irep, Integral irep+ , Show irep, Typeable size, Typeable e+ ) => Predicate ('Pascal size e) B.ByteString where+ validate p bs+ | len > fromIntegral max'+ = throwRefineOtherException (typeRep p) $+ "bytestring too long for given length prefix type: "+ <>tshow len<>" > "<>tshow max'+ | otherwise = success+ where+ len = B.length bs+ max' = maxBound @irep
+ src/Binrep/Type/Common.hs view
@@ -0,0 +1,10 @@+module Binrep.Type.Common where++import GHC.Generics ( Generic )+import Data.Data ( Data )++-- | Byte order.+data Endianness+ = BE -- ^ big endian, MSB first. e.g. most network protocols+ | LE -- ^ little endian, MSB last. e.g. most processor architectures+ deriving stock (Generic, Data, Show, Eq)
+ src/Binrep/Type/Int.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE UndecidableInstances #-}++{- TODO can I replace this with a closed newtype family?? idk if I even want to+ it's just this is clumsy to use sometimes+-}++module Binrep.Type.Int where++import Binrep+import Binrep.Type.Common ( Endianness(..) )+import Strongweak++import Data.Word+import Data.Int+import Data.Aeson+import FlatParse.Basic qualified as FP+import Mason.Builder qualified as Mason++import GHC.Generics ( Generic )+import Data.Data ( Typeable, Data )+import GHC.TypeNats++-- | Wrapper type grouping machine integers (sign, size) along with an explicit+-- endianness.+--+-- The internal representation is selected via a type family to correspond to+-- the relevant Haskell data type, so common overflow behaviour should match.+-- We derive lots of handy instances, so you may perform regular arithmetic on+-- pairs of these types. For example:+--+-- >>> 255 + 1 :: I 'U 'I1 e+-- 0+--+-- >>> 255 + 1 :: I 'U 'I2 e+-- 256+newtype I (sign :: ISign) (size :: ISize) (e :: Endianness)+ = I { getI :: IRep sign size }+ deriving stock (Generic)++deriving instance (Data (IRep sign size), Typeable sign, Typeable size, Typeable e) => Data (I sign size e)+deriving via (IRep sign size) instance Show (IRep sign size) => Show (I sign size e)++-- Steal various numeric instances from the representation types.+deriving via (IRep sign size) instance Eq (IRep sign size) => Eq (I sign size e)+deriving via (IRep sign size) instance Ord (IRep sign size) => Ord (I sign size e)+deriving via (IRep sign size) instance Bounded (IRep sign size) => Bounded (I sign size e)+deriving via (IRep sign size) instance Num (IRep sign size) => Num (I sign size e)+deriving via (IRep sign size) instance Real (IRep sign size) => Real (I sign size e)+deriving via (IRep sign size) instance Enum (IRep sign size) => Enum (I sign size e)+deriving via (IRep sign size) instance Integral (IRep sign size) => Integral (I sign size e)++-- | Unsigned machine integers can be idealized as naturals.+instance (irep ~ IRep 'U size, Integral irep) => Weaken (I 'U size end) where+ type Weak (I 'U size end) = Natural+ weaken = fromIntegral+instance (irep ~ IRep 'U size, Integral irep, Bounded irep, Show irep, Typeable size, Typeable end)+ => Strengthen (I 'U size end) where+ strengthen = strengthenBounded++-- | Signed machine integers can be idealized as integers.+instance (irep ~ IRep 'S size, Integral irep) => Weaken (I 'S size end) where+ type Weak (I 'S size end) = Integer+ weaken = fromIntegral+instance (irep ~ IRep 'S size, Integral irep, Bounded irep, Show irep, Typeable size, Typeable end)+ => Strengthen (I 'S size end) where+ strengthen = strengthenBounded++-- | Machine integer sign.+data ISign+ = S -- ^ signed+ | U -- ^ unsigned+ deriving stock (Generic, Data, Show, Eq)++-- | Machine integer size in number of bytes.+data ISize = I1 | I2 | I4 | I8+ deriving stock (Generic, Data, Show, Eq)++-- | Grouping for matching a signedness and size to a Haskell integer data type.+type family IRep (sign :: ISign) (size :: ISize) where+ IRep 'U 'I1 = Word8+ IRep 'S 'I1 = Int8+ IRep 'U 'I2 = Word16+ IRep 'S 'I2 = Int16+ IRep 'U 'I4 = Word32+ IRep 'S 'I4 = Int32+ IRep 'U 'I8 = Word64+ IRep 'S 'I8 = Int64++-- Also steal Aeson instances. The parser applies bounding checks appropriately.+deriving via (IRep sign size) instance ToJSON (IRep sign size) => ToJSON (I sign size e)+deriving via (IRep sign size) instance FromJSON (IRep sign size) => FromJSON (I sign size e)++type instance CBLen (I sign size end) = CBLen (IRep sign size)++deriving anyclass instance KnownNat (CBLen (I sign size end)) => BLen (I sign size end)++instance Put (I 'U 'I1 e) where put = put . getI+instance Get (I 'U 'I1 e) where get = I <$> get+instance Put (I 'S 'I1 e) where put = put . getI+instance Get (I 'S 'I1 e) where get = I <$> get++instance Put (I 'U 'I2 'BE) where put (I i) = Mason.word16BE i+instance Get (I 'U 'I2 'BE) where get = I <$> FP.anyWord16be+instance Put (I 'U 'I2 'LE) where put (I i) = Mason.word16LE i+instance Get (I 'U 'I2 'LE) where get = I <$> FP.anyWord16le+instance Put (I 'S 'I2 'BE) where put (I i) = Mason.int16BE i+instance Get (I 'S 'I2 'BE) where get = I <$> FP.anyInt16be+instance Put (I 'S 'I2 'LE) where put (I i) = Mason.int16LE i+instance Get (I 'S 'I2 'LE) where get = I <$> FP.anyInt16le++instance Put (I 'U 'I4 'BE) where put (I i) = Mason.word32BE i+instance Get (I 'U 'I4 'BE) where get = I <$> FP.anyWord32be+instance Put (I 'U 'I4 'LE) where put (I i) = Mason.word32LE i+instance Get (I 'U 'I4 'LE) where get = I <$> FP.anyWord32le+instance Put (I 'S 'I4 'BE) where put (I i) = Mason.int32BE i+instance Get (I 'S 'I4 'BE) where get = I <$> FP.anyInt32be+instance Put (I 'S 'I4 'LE) where put (I i) = Mason.int32LE i+instance Get (I 'S 'I4 'LE) where get = I <$> FP.anyInt32le++instance Put (I 'U 'I8 'BE) where put (I i) = Mason.word64BE i+instance Get (I 'U 'I8 'BE) where get = I <$> FP.anyWord64be+instance Put (I 'U 'I8 'LE) where put (I i) = Mason.word64LE i+instance Get (I 'U 'I8 'LE) where get = I <$> FP.anyWord64le+instance Put (I 'S 'I8 'BE) where put (I i) = Mason.int64BE i+instance Get (I 'S 'I8 'BE) where get = I <$> FP.anyInt64be+instance Put (I 'S 'I8 'LE) where put (I i) = Mason.int64LE i+instance Get (I 'S 'I8 'LE) where get = I <$> FP.anyInt64le++-- | Shortcut.+type family IMax (sign :: ISign) (size :: ISize) :: Natural where+ IMax sign size = MaxBound (IRep sign size)++-- | Restricted reflected version of @maxBound@.+type family MaxBound w :: Natural where+ MaxBound Word8 = 255+ MaxBound Int8 = 127+ MaxBound Word16 = 65535+ MaxBound Int16 = 32767+ MaxBound Word32 = 4294967295+ MaxBound Int32 = 2147483647+ MaxBound Word64 = 18446744073709551615+ MaxBound Int64 = 9223372036854775807
+ src/Binrep/Type/LenPfx.hs view
@@ -0,0 +1,110 @@+-- TODO cleanup proxy usage (can we be faster via unboxed @Proxy#@ s ?)++{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE UndecidableInstances #-}++module Binrep.Type.LenPfx where++import Binrep+import Strongweak+import Data.Either.Validation+import Binrep.Type.Vector ( getVector )+import Binrep.Type.Common ( Endianness )+import Binrep.Type.Int+import Binrep.Util ( natVal'' )+import Data.Vector.Sized ( Vector )+import Data.Vector.Sized qualified as V+import GHC.TypeNats+import GHC.TypeLits ( OrderingI(..) )+import Data.Proxy ( Proxy(..) )++import GHC.Generics+import Data.Typeable ( Typeable )++-- | Holy shit - no need to do a smart constructor, it's simply impossible to+-- instantiate invalid values of this type!+data LenPfx (size :: ISize) (end :: Endianness) a =+ forall n. (KnownNat n, n <= IMax 'U size) => LenPfx { unLenPfx :: Vector n a }++-- uhhhhhhhhhh i dunno. TODO+instance Generic (LenPfx size end a) where+ type Rep (LenPfx size end a) = Rec0 (LenPfx size end a)+ from = K1+ to = unK1++instance Eq a => Eq (LenPfx size end a) where+ (LenPfx a) == (LenPfx b) = vsEq a b++-- TODO+instance Show a => Show (LenPfx size end a) where+ show (LenPfx a) = "LenPfx ("<>show a<>")"++vsEq :: forall a n m. (Eq a, KnownNat n, KnownNat m) => Vector n a -> Vector m a -> Bool+vsEq vn vm =+ if natVal'' @n == natVal'' @m+ then V.toList vn == V.toList vm+ else False++instance Weaken (LenPfx size end a) where+ type Weak (LenPfx size end a) = [a]+ weaken (LenPfx v) = V.toList v++instance (KnownNat (MaxBound (IRep 'U size)), Show a, Typeable a, Typeable size, Typeable end)+ => Strengthen (LenPfx size end a) where+ strengthen l = case lenPfxFromList l of+ Nothing -> strengthenFailBase l "TODO doesn't fit"+ Just v -> Success v++asLenPfx+ :: forall size end n a irep+ . (irep ~ IRep 'U size, KnownNat n, KnownNat (MaxBound irep))+ => Vector n a -> Maybe (LenPfx size end a)+asLenPfx v =+ case cmpNat (Proxy :: Proxy n) (Proxy :: Proxy (MaxBound (IRep 'U size))) of+ LTI -> Just $ LenPfx v+ EQI -> Just $ LenPfx v+ GTI -> Nothing++lenPfxFromList+ :: forall size end a irep+ . (irep ~ IRep 'U size, KnownNat (MaxBound irep))+ => [a] -> Maybe (LenPfx size end a)+lenPfxFromList l = V.withSizedList l asLenPfx++instance (BLen a, itype ~ I 'U size end, KnownNat (CBLen itype))+ => BLen (LenPfx size end a) where+ blen (LenPfx v) = cblen @itype + blen v++instance (itype ~ I 'U size end, irep ~ IRep 'U size, Put a, Put itype, Num irep)+ => Put (LenPfx size end a) where+ put (LenPfx v) = put @itype (fromIntegral (vnatVal v)) <> put v+ where+ vnatVal :: forall n x. KnownNat n => Vector n x -> Natural+ vnatVal _ = natVal'' @n++lenPfxSize :: Num (IRep 'U size) => LenPfx size end a -> I 'U size end+lenPfxSize (LenPfx v) = fromIntegral (vnatVal v)+ where+ vnatVal :: forall n x. KnownNat n => Vector n x -> Natural+ vnatVal _ = natVal'' @n++instance (itype ~ I 'U size end, irep ~ IRep 'U size, Get itype, Integral irep, Get a, KnownNat (MaxBound irep))+ => Get (LenPfx size end a) where+ get = getLenPfx get++getLenPfx+ :: forall size end a itype irep+ . (itype ~ I 'U size end, irep ~ IRep 'U size, Get itype, Integral irep, KnownNat (MaxBound irep))+ => Getter a -> Getter (LenPfx size end a)+getLenPfx g = do+ len <- get @itype+ case someNatVal (fromIntegral len) of+ SomeNat (Proxy :: Proxy n) -> do+ x <- getVector @n g+ -- TODO we actually know that @n <= MaxBound irep@ before doing this+ -- because @len <= maxBound (_ :: irep)@ but that's hard to prove to+ -- GHC without lots of refactoring. This is good enough.+ case cmpNat (Proxy :: Proxy n) (Proxy :: Proxy (MaxBound irep)) of+ GTI -> error "impossible"+ LTI -> return $ LenPfx x+ EQI -> return $ LenPfx x
+ src/Binrep/Type/Magic.hs view
@@ -0,0 +1,97 @@+{-# LANGUAGE UndecidableInstances #-}++{- | Magic numbers (also just magic): short constant bytestrings usually+ found at the top of a file, included as a safety check for parsing.++TODO rename: MagicBytes -> MagicVals, and have ByteVal be a "consumer" of+MagicVals where each value must be a byte. (It's conceivable that we have+another consumer which makes each value into a non-empty list of bytes, LE/BE.)++TODO unassociated type fams bad (maybe). turn into class -- and turn the reifier+into a default method! (TODO think about this)++There are two main flavors of magics:++ * "random" bytes e.g. Zstandard: @28 B5 2F FD@+ * printable ASCII bytes e.g. Ogg: @4F 67 67 53@ -> OggS++For bytewise magics, use type-level 'Natural' lists.+For ASCII magics, use 'Symbol's (type-level strings).++Previously, I squashed these into a representationally-safe type. Now the check+only occurs during reification. So you are able to define invalid magics now+(bytes over 255, non-ASCII characters), and potentially use them, but you'll get+a clear type error like "no instance for ByteVal 256" when attempting to reify.++String magics are restricted to ASCII, and will type error during reification+otherwise. If you really want UTF-8, please read 'Binrep.Type.Magic.UTF8'.+-}++module Binrep.Type.Magic where++import Binrep+import Binrep.Type.Byte++import GHC.TypeLits+import Data.ByteString qualified as B+import FlatParse.Basic qualified as FP++import GHC.Generics ( Generic )+import Data.Data ( Data )++import Mason.Builder qualified as Mason++data Magic (a :: k) = Magic+ deriving stock (Generic, Data, Show, Eq)++-- | Assumes magic values are individual bytes.+type instance CBLen (Magic a) = Length (MagicVals a)++-- | Assumes magic values are individual bytes.+deriving anyclass instance KnownNat (Length (MagicVals a)) => BLen (Magic a)++-- | Forces magic values to be individual bytes.+instance (bs ~ MagicVals a, ByteVals bs) => Put (Magic a) where+ put Magic = byteVals @bs++-- | Forces magic values to be individual bytes.+--+-- TODO improve show - maybe hexbytestring goes here? lol+instance (bs ~ MagicVals a, ByteVals bs) => Get (Magic a) where+ get = do+ let expected = Mason.toStrictByteString $ byteVals @bs+ actual <- FP.takeBs $ B.length expected+ if actual == expected+ then return Magic+ else FP.err $ "bad magic: expected "<>show expected<>", got "<>show actual++{-+I do lots of functions on lists, because they're structurally simple. But you+can't pass type-level functions as arguments between type families. singletons+solves a related (?) problem using defunctionalization, where you manually write+out the function applications or something. Essentially, you can't do this:++ type family Map (f :: x -> y) (a :: [x]) :: [y] where+ Map _ '[] = '[]+ Map f (a ': as) = f a ': Map f as++So you have to write that out for every concrete function over lists.+-}++type family MagicVals (a :: k) :: [Natural]+type instance MagicVals (a :: Symbol) = SymbolUnicodeCodepoints a+type instance MagicVals (a :: [Natural]) = a++type family SymbolUnicodeCodepoints (a :: Symbol) :: [Natural] where+ SymbolUnicodeCodepoints a = CharListUnicodeCodepoints (SymbolAsCharList a)++type family CharListUnicodeCodepoints (a :: [Char]) :: [Natural] where+ CharListUnicodeCodepoints '[] = '[]+ CharListUnicodeCodepoints (c ': cs) = CharToNat c ': CharListUnicodeCodepoints cs++type family SymbolAsCharList (a :: Symbol) :: [Char] where+ SymbolAsCharList a = SymbolAsCharList' (UnconsSymbol a)++type family SymbolAsCharList' (a :: Maybe (Char, Symbol)) :: [Char] where+ SymbolAsCharList' 'Nothing = '[]+ SymbolAsCharList' ('Just '(c, s)) = c ': SymbolAsCharList' (UnconsSymbol s)
+ src/Binrep/Type/Magic/UTF8.hs view
@@ -0,0 +1,47 @@+{- | Inefficient attempt at UTF-8 magics.++To encode UTF-8 strings to bytestrings at compile time, we really need more+support from the compiler. We can go @Char -> Natural@, but we can't go @Natural+-> [Natural]@ where each value is @<= 255@. Doing so is hard without bit+twiddling.++The best we can do is get reify the 'Symbol' directly, then encode as UTF-8 at+runtime. It's a bit of a farce, and we can't derive a 'CBLen' instance, but+works just fine. Actually, I dunno, it might be faster than the bytewise magic+handling, depending on how GHC optimizes its instances.+-}++{-# LANGUAGE AllowAmbiguousTypes #-}++module Binrep.Type.Magic.UTF8 where++import Binrep++import GHC.TypeLits+import GHC.Exts ( proxy#, Proxy# )+import Data.Text qualified as Text+import Data.Text.Encoding qualified as Text+import Data.ByteString qualified as B+import FlatParse.Basic qualified as FP++data MagicUTF8 (str :: Symbol) = MagicUTF8 deriving Show++symVal :: forall str. KnownSymbol str => String+symVal = symbolVal' (proxy# :: Proxy# str)++instance KnownSymbol str => BLen (MagicUTF8 str) where+ blen MagicUTF8 = posIntToBLen $ B.length $ encodeStringUtf8 $ symVal @str++instance KnownSymbol str => Put (MagicUTF8 str) where+ put MagicUTF8 = put $ encodeStringUtf8 $ symVal @str++instance KnownSymbol str => Get (MagicUTF8 str) where+ get = do+ let expected = encodeStringUtf8 $ symVal @str+ actual <- FP.takeBs $ B.length expected+ if actual == expected+ then return MagicUTF8+ else FP.err $ "bad magic: expected "<>show expected<>", got "<>show actual++encodeStringUtf8 :: String -> B.ByteString+encodeStringUtf8 = Text.encodeUtf8 . Text.pack
+ src/Binrep/Type/NullPadded.hs view
@@ -0,0 +1,70 @@+{-# LANGUAGE OverloadedStrings #-}++module Binrep.Type.NullPadded where++import Binrep+import Binrep.Util ( tshow )++import Refined+import Refined.Unsafe++import GHC.TypeNats+import Data.Typeable ( typeRep )+import FlatParse.Basic qualified as FP+import FlatParse.Basic ( Parser )+import Mason.Builder qualified as Mason+import Data.ByteString qualified as BS++data NullPad (n :: Natural)++type NullPadded n a = Refined (NullPad n) a++-- | The size of some null-padded data is known - at compile time!+type instance CBLen (NullPadded n a) = n++deriving anyclass instance KnownNat n => BLen (NullPadded n a)++instance (BLen a, KnownNat n) => Predicate (NullPad n) a where+ validate p a+ | len > n+ = throwRefineOtherException (typeRep p) $+ "too long: " <> tshow len <> " > " <> tshow n+ | otherwise = success+ where+ n = typeNatToBLen @n+ len = blen a++-- TODO cleanup+instance (Put a, BLen a, KnownNat n) => Put (NullPadded n a) where+ put wrnpa =+ let npa = unrefine wrnpa+ paddingLength = n - blen npa+ in put npa <> Mason.byteString (BS.replicate (fromIntegral paddingLength) 0x00)+ where+ n = typeNatToBLen @n++-- | Safety: we assert actual length is within expected length (in order to+-- calculate how much padding to parse).+--+-- Note that the consumer probably doesn't care about the content of the+-- padding, just that the data is chunked correctly. I figure we care about+-- correctness here, so it'd be nice to know about the padding well-formedness+-- (i.e. that it's all nulls).+--+-- TODO maybe better definition via isolate+instance (Get a, BLen a, KnownNat n) => Get (NullPadded n a) where+ get = do+ a <- get+ let len = blen a+ nullStrLen = n - len+ if nullStrLen < 0+ then FP.err $ "too long: " <> show len <> " > " <> show n+ else getNNulls nullStrLen >> return (reallyUnsafeRefine a)+ where+ n = typeNatToBLen @n++getNNulls :: BLenT -> Parser String ()+getNNulls = \case 0 -> return ()+ n -> FP.anyWord8 >>= \case+ 0x00 -> getNNulls $ n-1+ nonNull -> FP.err "TODO expected null, wasn't"
+ src/Binrep/Type/Sized.hs view
@@ -0,0 +1,44 @@+-- | Constant-size data.++{-# LANGUAGE OverloadedStrings #-}++module Binrep.Type.Sized where++import Binrep+import Binrep.Util ( tshow )++import Refined+import Refined.Unsafe++import GHC.TypeNats+import Data.Typeable ( typeRep )+import FlatParse.Basic qualified as FP++data Size (n :: Natural)++type Sized n a = Refined (Size n) a++type instance CBLen (Sized n a) = n++deriving anyclass instance KnownNat n => BLen (Sized n a)++instance (BLen a, KnownNat n) => Predicate (Size n) a where+ validate p a+ | len > n+ = throwRefineOtherException (typeRep p) $+ "not correctly sized: "<>tshow len<>" /= "<>tshow n+ | otherwise = success+ where+ n = typeNatToBLen @n+ len = blen a++instance Put a => Put (Sized n a) where+ put = put . unrefine++-- TODO safety: isolate consumes all bytes if succeeds+instance (Get a, KnownNat n) => Get (Sized n a) where+ get = do+ a <- FP.isolate (fromIntegral n) get+ return $ reallyUnsafeRefine a+ where+ n = typeNatToBLen @n
+ src/Binrep/Type/Text.hs view
@@ -0,0 +1,184 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE CPP #-}++module Binrep.Type.Text+ ( Encoding(..)+ , AsText+ , Encode, encode+ , Decode(..)+ , encodeToRep+ , decodeViaTextICU+ ) where++import Binrep.Type.Common ( Endianness(..) )+import Binrep.Type.ByteString ( Rep )++import Refined+import Refined.Unsafe++import Data.ByteString qualified as B+import Data.Text qualified as Text+import Data.Text ( Text )+import Data.Char qualified as Char+import Data.Text.Encoding qualified as Text+import Data.Either.Combinators qualified as Either++import GHC.Generics ( Generic )+import Data.Data ( Data )++import Data.Typeable ( Typeable, typeRep )++import System.IO.Unsafe qualified+import Control.Exception qualified+import Data.Text.Encoding.Error qualified++import Data.Text.ICU.Convert qualified as ICU++type Bytes = B.ByteString++-- | Character encoding.+--+-- Byte-oriented encodings like ASCII and UTF-8 don't need to worry about+-- endianness. For UTF-16 and UTF-32, the designers decided to allow different+-- endiannesses, rather than saying "codepoints must be X-endian".+data Encoding+ = UTF8+ | UTF16 Endianness+ | UTF32 Endianness+ | ASCII -- ^ 7-bit+ | SJIS+ deriving stock (Generic, Data, Show, Eq)++-- | A string of a given encoding, stored in the 'Text' type.+type AsText (enc :: Encoding) = Refined enc Text++-- | Bytestring encoders for text validated for a given encoding.+class Encode (enc :: Encoding) where+ -- | Encode text to bytes. Internal function, use 'encode'.+ encode' :: Text -> Bytes++instance Encode 'UTF8 where encode' = Text.encodeUtf8++-- | ASCII is a subset of UTF-8, so valid ASCII is valid UTF-8, so this is safe.+instance Encode 'ASCII where encode' = encode' @'UTF8++instance Encode ('UTF16 'BE) where encode' = Text.encodeUtf16BE+instance Encode ('UTF16 'LE) where encode' = Text.encodeUtf16LE+instance Encode ('UTF32 'BE) where encode' = Text.encodeUtf32BE+instance Encode ('UTF32 'LE) where encode' = Text.encodeUtf32LE++instance Encode 'SJIS where encode' = encodeViaTextICU' "Shift-JIS"++-- | Encode some validated text.+encode :: forall enc. Encode enc => AsText enc -> Bytes+encode = encode' @enc . unrefine++-- | Any 'Text' value is always valid UTF-8.+instance Predicate 'UTF8 Text where validate _ _ = success++-- | Any 'Text' value is always valid UTF-16.+instance Typeable e => Predicate ('UTF16 e) Text where validate _ _ = success++-- | Any 'Text' value is always valid UTF-32.+instance Typeable e => Predicate ('UTF32 e) Text where validate _ _ = success++-- | 'Text' must be validated if you want to permit 7-bit ASCII only.+instance Predicate 'ASCII Text where+ validate p t = if Text.all Char.isAscii t+ then success+ else throwRefineOtherException (typeRep p) "not valid 7-bit ASCII"++-- | TODO Unsafely assume all 'Text's are valid Shift-JIS.+instance Predicate 'SJIS Text where validate _ _ = success++class Decode (enc :: Encoding) where+ -- | Decode a 'ByteString' to 'Text' with an explicit encoding.+ --+ -- This is intended to be used with visible type applications.+ decode :: Bytes -> Either String (AsText enc)++instance Decode 'UTF8 where decode = decodeText show Text.decodeUtf8'+instance Decode ('UTF16 'BE) where decode = decodeText show $ wrapUnsafeDecoder Text.decodeUtf16BE+instance Decode ('UTF16 'LE) where decode = decodeText show $ wrapUnsafeDecoder Text.decodeUtf16LE+instance Decode ('UTF32 'BE) where decode = decodeText show $ wrapUnsafeDecoder Text.decodeUtf32BE+instance Decode ('UTF32 'LE) where decode = decodeText show $ wrapUnsafeDecoder Text.decodeUtf32LE++-- Pre-@text-2.0@, @decodeASCII@ generated a warning and ran @decodeUtf8@.+#if MIN_VERSION_text(2,0,0)+instance Decode 'ASCII where decode = decodeText $ wrapUnsafeDecoder Text.decodeASCII+#endif++instance Decode 'SJIS where decode = decodeText id $ decodeViaTextICU' "Shift-JIS"++--------------------------------------------------------------------------------+-- Helpers++-- | Encode some text to a bytestring, asserting that the resulting value is+-- valid for the requested bytestring representation.+--+-- This is intended to be used with visible type applications:+--+-- >>> let Right t = refine @'UTF8 (Text.pack "hi")+-- >>> :t t+-- t :: AsText 'UTF8+-- >>> let Right bs = encodeToRep @'C t+-- >>> :t bs+-- bs :: Refined 'C Bytes+encodeToRep+ :: forall (rep :: Rep) enc+ . (Encode enc, Predicate rep Bytes)+ => AsText enc+ -> Either RefineException (Refined rep Bytes)+encodeToRep = refine . encode++--------------------------------------------------------------------------------+-- Internal helpers++-- | Helper for decoding a 'Bytes' to a 'Text' tagged with its encoding.+decodeText+ :: forall enc e+ . (e -> String) -> (Bytes -> Either e Text) -> Bytes+ -> Either String (AsText enc)+decodeText g f = Either.mapBoth g reallyUnsafeRefine . f++-- | Run an unsafe decoder safely.+--+-- Copied from @Data.Text.Encoding.decodeUtf8'@, so should be bulletproof?+wrapUnsafeDecoder+ :: (Bytes -> Text)+ -> Bytes -> Either Data.Text.Encoding.Error.UnicodeException Text+wrapUnsafeDecoder f =+ System.IO.Unsafe.unsafeDupablePerformIO+ . Control.Exception.try+ . Control.Exception.evaluate+ . f++-- | Encode some 'Text' to the given character set using text-icu.+--+-- No guarantees about correctness. Encodings are weird. e.g. Shift JIS's+-- yen/backslash problem is apparently to do with OSs treating it differently.+--+-- Expects a 'Text' that is confirmed valid for converting to the character set.+--+-- The charset must be valid, or it's exception time. See text-icu.+encodeViaTextICU :: String -> Text -> IO B.ByteString+encodeViaTextICU charset t = do+ conv <- ICU.open charset Nothing+ return $ ICU.fromUnicode conv t++encodeViaTextICU' :: String -> Text -> B.ByteString+encodeViaTextICU' charset t =+ System.IO.Unsafe.unsafeDupablePerformIO $ encodeViaTextICU charset t++-- TODO Shitty library doesn't let us say how to handle errors. Apparently, the+-- only solution is to scan through the resulting 'Text' to look for @\SUB@+-- characters, or lie about correctness. Sigh.+decodeViaTextICU :: String -> B.ByteString -> IO (Either String Text)+decodeViaTextICU charset t = do+ conv <- ICU.open charset Nothing+ return $ Right $ ICU.toUnicode conv t++decodeViaTextICU' :: String -> B.ByteString -> Either String Text+decodeViaTextICU' charset t = do+ System.IO.Unsafe.unsafeDupablePerformIO $ decodeViaTextICU charset t
+ src/Binrep/Type/Vector.hs view
@@ -0,0 +1,26 @@+-- | Sized vectors.++{-# LANGUAGE NoStarIsType #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Binrep.Type.Vector where++import Binrep+import Data.Vector.Sized qualified as V+import Data.Vector.Sized ( Vector )+import GHC.TypeNats++type instance CBLen (Vector n a) = CBLen a * n++instance BLen a => BLen (Vector n a) where+ blen = V.sum . V.map blen++instance Put a => Put (Vector n a) where+ put = mconcat . V.toList . V.map put++instance (Get a, KnownNat n) => Get (Vector n a) where+ get = getVector get++getVector :: KnownNat n => Getter a -> Getter (Vector n a)+getVector g = V.replicateM g
− src/Binrep/Types/Ints.hs
@@ -1,89 +0,0 @@-module Binrep.Types.Ints where--import Binrep.Codec-import Binrep.ByteLen-import GHC.Generics ( Generic )-import Data.Typeable-import Data.Word-import Data.Int-import Data.Aeson-import Data.Serialize---- | Wrapper type grouping machine integers (sign, size) along with an explicit--- endianness.-newtype I (sign :: ISign) (size :: ISize) (e :: Endianness)- = I { getI :: IRep sign size }- deriving stock (Generic, Typeable)---- | Lots of deriving boilerplate due to the type family usage.-deriving stock instance Show (IRep sign size) => Show (I sign size e)-deriving via (IRep sign size) instance Eq (IRep sign size) => Eq (I sign size e)-deriving via (IRep sign size) instance Ord (IRep sign size) => Ord (I sign size e)-deriving via (IRep sign size) instance Bounded (IRep sign size) => Bounded (I sign size e)-deriving via (IRep sign size) instance Num (IRep sign size) => Num (I sign size e)-deriving via (IRep sign size) instance Real (IRep sign size) => Real (I sign size e)-deriving via (IRep sign size) instance Enum (IRep sign size) => Enum (I sign size e)-deriving via (IRep sign size) instance Integral (IRep sign size) => Integral (I sign size e)-deriving via (IRep sign size) instance ToJSON (IRep sign size) => ToJSON (I sign size e)-deriving via (IRep sign size) instance FromJSON (IRep sign size) => FromJSON (I sign size e)--instance ByteLen (I s 'I1 e) where blen = const 1-instance ByteLen (I s 'I2 e) where blen = const 2-instance ByteLen (I s 'I4 e) where blen = const 4-instance ByteLen (I s 'I8 e) where blen = const 8---- | Endianness doesn't apply for single-byte machine integers.-instance BinaryCodec (I 'U 'I1 e) where toBin = putWord8 . getI- fromBin = I <$> getWord8-instance BinaryCodec (I 'S 'I1 e) where toBin = putInt8 . getI- fromBin = I <$> getInt8--instance BinaryCodec (I 'U 'I2 'BE) where toBin = putWord16be . getI- fromBin = I <$> getWord16be-instance BinaryCodec (I 'U 'I2 'LE) where toBin = putWord16le . getI- fromBin = I <$> getWord16le-instance BinaryCodec (I 'S 'I2 'BE) where toBin = putInt16be . getI- fromBin = I <$> getInt16be-instance BinaryCodec (I 'S 'I2 'LE) where toBin = putInt16le . getI- fromBin = I <$> getInt16le--instance BinaryCodec (I 'U 'I4 'BE) where toBin = putWord32be . getI- fromBin = I <$> getWord32be-instance BinaryCodec (I 'U 'I4 'LE) where toBin = putWord32le . getI- fromBin = I <$> getWord32le-instance BinaryCodec (I 'S 'I4 'BE) where toBin = putInt32be . getI- fromBin = I <$> getInt32be-instance BinaryCodec (I 'S 'I4 'LE) where toBin = putInt32le . getI- fromBin = I <$> getInt32le--instance BinaryCodec (I 'U 'I8 'BE) where toBin = putWord64be . getI- fromBin = I <$> getWord64be-instance BinaryCodec (I 'U 'I8 'LE) where toBin = putWord64le . getI- fromBin = I <$> getWord64le-instance BinaryCodec (I 'S 'I8 'BE) where toBin = putInt64be . getI- fromBin = I <$> getInt64be-instance BinaryCodec (I 'S 'I8 'LE) where toBin = putInt64le . getI- fromBin = I <$> getInt64le---- | Byte order.-data Endianness- = BE -- ^ big endian, MSB first. e.g. most network protocols- | LE -- ^ little endian, MSB last. e.g. most processor architectures---- | Machine integer sign-data ISign- = S -- ^ signed- | U -- ^ unsigned---- | Machine integer size in number of bytes.-data ISize = I1 | I2 | I4 | I8--type family IRep (sign :: ISign) (size :: ISize) where- IRep 'U 'I1 = Word8- IRep 'S 'I1 = Int8- IRep 'U 'I2 = Word16- IRep 'S 'I2 = Int16- IRep 'U 'I4 = Word32- IRep 'S 'I4 = Int32- IRep 'U 'I8 = Word64- IRep 'S 'I8 = Int64
− src/Binrep/Types/Strings.hs
@@ -1,111 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Binrep.Types.Strings where--import Binrep.Codec-import Binrep.ByteLen-import Binrep.Types.Ints-import Binrep.Util-import Refined-import Refined.WithRefine-import Data.ByteString qualified as BS-import Data.ByteString.Lazy qualified as BL-import Data.ByteString.Builder qualified as B-import Data.Serialize-import Data.Word-import Data.Typeable ( Typeable, typeRep )-import Control.Monad ( replicateM )---- | TODO-data StrRep = C | Pascal ISize Endianness---- | TODO------ We also use this as a predicate, because the 'Pascal' constructor looks--- identical to what we would want for a @LengthPrefixed@ predicate.-newtype Str (rep :: StrRep)- = Str { getStr :: BS.ByteString }--fromBinCString :: Get BS.ByteString-fromBinCString = go mempty- where go buf = do- getWord8 >>= \case- 0x00 -> return $ BL.toStrict $ B.toLazyByteString buf- nonNull -> go $ buf <> B.word8 nonNull--instance ByteLen (Str 'C) where- blen cstr = fromIntegral $ BS.length (getStr cstr) + 1--instance ByteLen (I 'U size e) => ByteLen (Str ('Pascal size e )) where- blen pstr = fromIntegral (blen @(I 'U size e) undefined) + fromIntegral (BS.length (getStr pstr))---- | Total shite parsing efficiency. But, to be fair, that's why we don't--- serialize arbitrary-length C strings!-instance BinaryCodec (Str 'C) where- toBin cstr = do- putByteString $ getStr cstr- putWord8 0x00- fromBin = Str <$> fromBinCString--instance BinaryCodecWith _r (Str 'C)---- TODO yeah I gotta do this because now the size info is actually in the--- newtype -- which makes the most sense, because I want to do similar on the--- value level! looks a tiny bit jank but ✓-data WellSized---- | TODO explain why safe-instance BinaryCodec (WithRefine 'Enforced WellSized (Str ('Pascal 'I1 e))) where- toBin wrepstr = do- toBin @(I 'U 'I1 e) $ fromIntegral $ BS.length bs- putByteString bs- where bs = getStr $ unWithRefine wrepstr- fromBin = do- len <- fromBin @(I 'U 'I1 e)- bs <- getByteString $ fromIntegral len- return $ reallyUnsafeEnforce $ Str bs--instance BinaryCodecWith StrRep BS.ByteString where- toBinWith strRep bs =- case strRep of- C -> toBinWith undefined $ Str @'C bs- Pascal size _e -> do- case size of- I1 -> do- if len > fromIntegral (maxBound @Word8)- then Left "bytestring too long for configured static-size length prefix"- else Right $ B.byteString bs- _ -> undefined- where len = BS.length bs- fromBinWith = \case C -> fromBinCString- Pascal _size _e -> undefined---- Fun and correct, but it does give us an orphan instance lol-type LenPfx size e = Str ('Pascal size e)---- | TODO why safe-instance (ByteLen a, itype ~ I 'U size e, ByteLen itype)- => ByteLen (WithRefine 'Enforced (LenPfx size e) a) where- blen wrelpa = blen @itype undefined + blen (unWithRefine wrelpa)--instance (Foldable f, Typeable f, Typeable e) => Predicate (LenPfx 'I4 e) (f a) where- validate p a- | len > fromIntegral max'- = throwRefineOtherException (typeRep p) $- "too long for given length prefix type: "<>tshow len<>" > "<>tshow max'- | otherwise = success- where- len = length a- max' = maxBound @(IRep 'U 'I4)---- | TODO why safe-instance (BinaryCodec a, irep ~ IRep 'U size, itype ~ I 'U size e, Num irep, Integral irep, BinaryCodec itype)- => BinaryCodec (WithRefine 'Enforced (LenPfx size e) [a]) where- fromBin = do- len <- fromBin @itype- as <- replicateM (fromIntegral len) (fromBin @a)- return $ reallyUnsafeEnforce as- toBin wreas = do- toBin @itype $ fromIntegral $ length as- mapM_ (toBin @a) as- where as = unWithRefine wreas
src/Binrep/Util.hs view
@@ -1,7 +1,31 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+ module Binrep.Util where +-- tshow import Data.Text qualified as Text import Data.Text ( Text ) +-- posIntToNat+import GHC.Exts ( Int(..), int2Word# )+import GHC.Num.Natural ( Natural(..) )++-- natVal''+import GHC.TypeNats ( KnownNat, natVal' )+import GHC.Exts ( proxy#, Proxy# )+ tshow :: Show a => a -> Text tshow = Text.pack . show++-- | Convert some 'Int' @i@ where @i >= 0@ to a 'Natural'.+--+-- This is intended for wrapping the output of 'length' functions.+--+-- underflows if you call it with a negative 'Int' :)+posIntToNat :: Int -> Natural+posIntToNat (I# i#) = NS (int2Word# i#)+{-# INLINE posIntToNat #-}++natVal'' :: forall a. KnownNat a => Natural+natVal'' = natVal' (proxy# :: Proxy# a)+{-# INLINE natVal'' #-}
+ src/Data/Aeson/Extra/SizedVector.hs view
@@ -0,0 +1,19 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Data.Aeson.Extra.SizedVector where++import Data.Aeson+import Data.Vector.Generic.Sized.Internal qualified as VSI+import Data.Vector.Generic.Sized qualified as VS+import Data.Vector.Generic qualified as V+import GHC.TypeNats ( KnownNat )++instance ToJSON (v a) => ToJSON (VSI.Vector v n a) where+ toJSON (VSI.Vector v) = toJSON v+ toEncoding (VSI.Vector v) = toEncoding v+instance (FromJSON (v a), KnownNat n, V.Vector v a) => FromJSON (VSI.Vector v n a) where+ parseJSON j = do+ v <- parseJSON j+ case VS.toSized v of+ Nothing -> fail "TODO bad size"+ Just v' -> return v'
+ test/ArbitraryOrphans.hs view
@@ -0,0 +1,10 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE UndecidableInstances #-}++module ArbitraryOrphans() where++import Test.QuickCheck ( Arbitrary )+import Binrep.Type.Int ( I(..), IRep )++-- | Machine integers steal their underlying representation's instance.+deriving via (IRep sign size) instance Arbitrary (IRep sign size) => Arbitrary (I sign size e)
+ test/Binrep/Extra/HexByteStringSpec.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedStrings #-}++module Binrep.Extra.HexByteStringSpec ( spec ) where++import Binrep.Extra.HexByteString+import Test.Hspec++import Data.ByteString qualified as B+import Text.Megaparsec+import Data.Void ( Void )++megaparsecParseFromCharStream :: forall s a. (Stream s, Token s ~ Char) => Parsec Void s a -> s -> Maybe a+megaparsecParseFromCharStream parser text = parseMaybe parser text++spec :: Spec+spec = do+ let bs = B.pack+ describe "parse" $ do+ let p = megaparsecParseFromCharStream @String (parseHexByteString B.pack)+ it "parses valid hex bytestrings" $ do+ p "00" `shouldBe` Just (bs [0x00])+ p "FF" `shouldBe` Just (bs [0xFF])+ p "1234" `shouldBe` Just (bs [0x12, 0x34])+ p "01 9A FE" `shouldBe` Just (bs [0x01, 0x9A, 0xFE])+ p "FFFFFFFF" `shouldBe` Just (B.replicate 4 0xFF)+ p "12 34 AB CD" `shouldBe` Just (bs [0x12, 0x34, 0xAB, 0xCD])+ it "fails to parse invalid hex bytestrings" $ do+ p "-00" `shouldBe` Nothing+ p "FG" `shouldBe` Nothing+ it "fails to parse 0x prefix" $ do+ p "1234" `shouldBe` Just (bs [0x12, 0x34])+ p "0x1234" `shouldBe` Nothing+ describe "print" $ do+ it "prints pretty hex bytestrings" $ do+ let p = prettyHexByteString B.unpack+ p (bs [0x5a, 0x7d]) `shouldBe` "5A 7D"+ it "prints compact hex bytestrings" $ do+ let pc = prettyHexByteStringCompact B.unpack+ pc (bs [0xab, 0x25]) `shouldBe` "ab25"
+ test/Binrep/LawsSpec.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE OverloadedStrings #-}++module Binrep.LawsSpec ( spec ) where++import Test.Hspec+import Test.Hspec.QuickCheck+import Test.QuickCheck.Instances.ByteString()+import Generic.Random+import Test.QuickCheck+import ArbitraryOrphans()++import Binrep+import Binrep.Generic+import Binrep.Type.Int+import Binrep.Type.Common ( Endianness(..) )+import Binrep.Type.ByteString+import Data.Word ( Word8 )+import Data.ByteString qualified as B+import GHC.Generics ( Generic )++spec :: Spec+spec = do+ prop "put is identity on ByteString" $ do+ \(bs :: B.ByteString) -> runPut bs `shouldBe` bs+ prop "parse-print roundtrip isomorphism (ByteString)" $ do+ \(bs :: B.ByteString) -> runGet (runPut bs) `shouldBe` Right (bs, "")+ prop "parse-print roundtrip isomorphism (generic, sum tag via nullterm constructor)" $ do+ \(d :: D) -> runGet (runPut d) `shouldBe` Right (d, "")++--------------------------------------------------------------------------------++type W1 = (I 'U 'I1 'LE)+type W2LE = (I 'U 'I2 'LE)+type W8BE = (I 'U 'I8 'BE)++data D+ = D01Bla Word8 W1 W8BE+ | D23 W2LE B.ByteString -- dangerous bytestring, must be last+ | DUnicode例 Word8+ | DSymbols_#+ deriving stock (Generic, Eq, Show)+deriving via (GenericArbitraryU `AndShrinking` D) instance Arbitrary D++dCfg :: Cfg (AsByteString 'C)+dCfg = Cfg { cSumTag = cSumTagNullTerm }++instance BLen D where blen = blenGeneric dCfg+instance Put D where put = putGeneric dCfg+instance Get D where get = getGeneric dCfg
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}