binrep 0.8.0 → 1.0.0
raw patch · 39 files changed
+980/−606 lines, 39 filesdep +ghc-bignumdep +rerefineddep +text-builder-lineardep −refined1dep ~basedep ~bytezapdep ~generic-data-functionsPVP ok
version bump matches the API change (PVP)
Dependencies added: ghc-bignum, rerefined, text-builder-linear, type-level-show
Dependencies removed: refined1
Dependency ranges changed: base, bytezap, generic-data-functions, strongweak, text, type-level-bytestrings
API changes (from Hackage documentation)
- Binrep.BLen: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.BLen.BLen (Refined.Unsafe.Type.Refined pr (Refined.Unsafe.Type.Refined pl a)) => Binrep.BLen.BLen (Refined.Unsafe.Type.Refined (Refined.And pl pr) a)
- Binrep.CBLen: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.CBLen.IsCBLen (Refined.Unsafe.Type.Refined pr (Refined.Unsafe.Type.Refined pl a)) => Binrep.CBLen.IsCBLen (Refined.Unsafe.Type.Refined (Refined.And pl pr) a)
- Binrep.Get: eBase :: EBase -> Getter a
- Binrep.Get: getEBase :: Getter a -> EBase -> Getter a
- Binrep.Get: getWrapGeneric :: Get a => String -> (E -> EGeneric E) -> Getter a
- Binrep.Get: getWrapGeneric' :: Getter a -> String -> (E -> EGeneric E) -> Getter a
- Binrep.Get: instance Generic.Data.Function.Traverse.Sum.GenericTraverseSum Binrep.Get.Get
- Binrep.Get: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.Get.Get (Refined.Unsafe.Type.Refined pr (Refined.Unsafe.Type.Refined pl a)) => Binrep.Get.Get (Refined.Unsafe.Type.Refined (Refined.And pl pr) a)
- Binrep.Get.Error: E :: Int -> EMiddle -> E
- Binrep.Get.Error: EAnd :: E -> EBase -> EMiddle
- Binrep.Get.Error: EBase :: EBase -> EMiddle
- Binrep.Get.Error: EExpected :: ByteString -> ByteString -> EBase
- Binrep.Get.Error: EExpectedByte :: Word8 -> Word8 -> EBase
- Binrep.Get.Error: EFail :: E
- Binrep.Get.Error: EFailNamed :: String -> EBase
- Binrep.Get.Error: EFailParse :: String -> ByteString -> Word8 -> EBase
- Binrep.Get.Error: EGeneric :: String -> EGeneric E -> EMiddle
- Binrep.Get.Error: EGenericField :: String -> Maybe String -> Natural -> e -> EGeneric e
- Binrep.Get.Error: EGenericSum :: EGenericSum e -> EGeneric e
- Binrep.Get.Error: EGenericSumTag :: e -> EGenericSum e
- Binrep.Get.Error: EGenericSumTagNoMatch :: [String] -> Text -> EGenericSum e
- Binrep.Get.Error: EOverlong :: Int -> Int -> EBase
- Binrep.Get.Error: ERanOut :: Int -> EBase
- Binrep.Get.Error: data E
- Binrep.Get.Error: data EBase
- Binrep.Get.Error: data EGeneric e
- Binrep.Get.Error: data EGenericSum e
- Binrep.Get.Error: data EMiddle
- Binrep.Get.Error: instance GHC.Classes.Eq Binrep.Get.Error.E
- Binrep.Get.Error: instance GHC.Classes.Eq Binrep.Get.Error.EBase
- Binrep.Get.Error: instance GHC.Classes.Eq Binrep.Get.Error.EMiddle
- Binrep.Get.Error: instance GHC.Classes.Eq e => GHC.Classes.Eq (Binrep.Get.Error.EGeneric e)
- Binrep.Get.Error: instance GHC.Classes.Eq e => GHC.Classes.Eq (Binrep.Get.Error.EGenericSum e)
- Binrep.Get.Error: instance GHC.Generics.Generic (Binrep.Get.Error.EGeneric e)
- Binrep.Get.Error: instance GHC.Generics.Generic (Binrep.Get.Error.EGenericSum e)
- Binrep.Get.Error: instance GHC.Generics.Generic Binrep.Get.Error.E
- Binrep.Get.Error: instance GHC.Generics.Generic Binrep.Get.Error.EBase
- Binrep.Get.Error: instance GHC.Generics.Generic Binrep.Get.Error.EMiddle
- Binrep.Get.Error: instance GHC.Show.Show Binrep.Get.Error.E
- Binrep.Get.Error: instance GHC.Show.Show Binrep.Get.Error.EBase
- Binrep.Get.Error: instance GHC.Show.Show Binrep.Get.Error.EMiddle
- Binrep.Get.Error: instance GHC.Show.Show e => GHC.Show.Show (Binrep.Get.Error.EGeneric e)
- Binrep.Get.Error: instance GHC.Show.Show e => GHC.Show.Show (Binrep.Get.Error.EGenericSum e)
- Binrep.Get.Struct: eCBase :: EBase -> GetterC a
- Binrep.Get.Struct: getECBase :: GetterC a -> EBase -> GetterC a
- Binrep.Get.Struct: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.Get.Struct.GetC (Refined.Unsafe.Type.Refined pr (Refined.Unsafe.Type.Refined pl a)) => Binrep.Get.Struct.GetC (Refined.Unsafe.Type.Refined (Refined.And pl pr) a)
- Binrep.Get.Struct: unsafeRunGetC' :: forall a buf. GetC a => (forall e. buf -> Parser e a -> Result e a) -> buf -> Either E a
- Binrep.Put: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.Put.Put (Refined.Unsafe.Type.Refined pr (Refined.Unsafe.Type.Refined pl a)) => Binrep.Put.Put (Refined.Unsafe.Type.Refined (Refined.And pl pr) a)
- Binrep.Put.Struct: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.Put.Struct.PutC (Refined.Unsafe.Type.Refined pr (Refined.Unsafe.Type.Refined pl a)) => Binrep.Put.Struct.PutC (Refined.Unsafe.Type.Refined (Refined.And pl pr) a)
- Binrep.Test: DMagic :: Magic '[0xFF, 0, 1, 0, 1, 0, 1, 0xFF] -> DMagic
- Binrep.Test: DMagicSum1 :: Magic '[0] -> DMagicSum
- Binrep.Test: DMagicSum2 :: Magic '[0xFF] -> DMagicSum
- Binrep.Test: DStruct :: Magic '[0xFF, 0, 1, 0xFF] -> ByteOrdered LE Word32 -> () -> DStruct
- Binrep.Test: [dMagic1_8b] :: DMagic -> Magic '[0xFF, 0, 1, 0, 1, 0, 1, 0xFF]
- Binrep.Test: [dStruct1] :: DStruct -> Magic '[0xFF, 0, 1, 0xFF]
- Binrep.Test: [dStruct2] :: DStruct -> ByteOrdered LE Word32
- Binrep.Test: [dStruct3] :: DStruct -> ()
- Binrep.Test: data DMagic
- Binrep.Test: data DMagicSum
- Binrep.Test: data DStruct
- Binrep.Test: instance Binrep.CBLen.IsCBLen Binrep.Test.DMagic
- Binrep.Test: instance Binrep.CBLen.IsCBLen Binrep.Test.DStruct
- Binrep.Test: instance Binrep.Get.Struct.GetC Binrep.Test.DStruct
- Binrep.Test: instance Binrep.Put.Struct.PutC Binrep.Test.DMagic
- Binrep.Test: instance Binrep.Put.Struct.PutC Binrep.Test.DStruct
- Binrep.Test: instance GHC.Generics.Generic Binrep.Test.DMagic
- Binrep.Test: instance GHC.Generics.Generic Binrep.Test.DMagicSum
- Binrep.Test: instance GHC.Generics.Generic Binrep.Test.DStruct
- Binrep.Test: instance GHC.Show.Show Binrep.Test.DStruct
- Binrep.Type.Magic: Magic :: Magic (a :: k)
- Binrep.Type.Magic: instance Binrep.Type.Magic.Magical ns
- Binrep.Type.Magic: instance forall (bs :: [GHC.Num.Natural.Natural]) k (a :: k). (bs GHC.Types.~ Binrep.Type.Magic.MagicBytes a, Bytezap.Parser.Struct.TypeLits.Bytes.ParseReifyBytesW64 bs, Bytezap.Struct.TypeLits.Bytes.ReifyBytesW64 bs, GHC.TypeNats.KnownNat (Binrep.Type.Magic.Length 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.MagicBytes a, Bytezap.Parser.Struct.TypeLits.Bytes.ParseReifyBytesW64 bs, Bytezap.Struct.TypeLits.Bytes.ReifyBytesW64 bs, GHC.TypeNats.KnownNat (Binrep.Type.Magic.Length bs)) => Binrep.Get.Struct.GetC (Binrep.Type.Magic.Magic a)
- Binrep.Type.NullPadded: instance (Binrep.BLen.BLen a, GHC.TypeNats.KnownNat n) => Refined.Predicate (Binrep.Type.NullPadded.NullPad n) a
- Binrep.Type.NullTerminated: class NullCheck a
- Binrep.Type.NullTerminated: hasNoNulls :: NullCheck a => a -> Bool
- Binrep.Type.NullTerminated: instance Binrep.Type.NullTerminated.NullCheck Data.ByteString.Internal.Type.ByteString
- Binrep.Type.NullTerminated: instance Binrep.Type.NullTerminated.NullCheck a => Refined.Predicate Binrep.Type.NullTerminated.NullTerminate a
- Binrep.Type.Prefix.Count: instance (Binrep.Util.Prefix.Prefix pfx, Binrep.Type.Prefix.Count.GetCount f, Binrep.Get.Get pfx, Binrep.Get.Get a) => Binrep.Get.Get (Binrep.Type.Prefix.Count.CountPrefixed pfx f a)
- Binrep.Type.Prefix.Count: instance (Binrep.Util.Prefix.Prefix pfx, Data.Foldable.Foldable f, Binrep.BLen.BLen pfx, Binrep.BLen.BLen (f a)) => Binrep.BLen.BLen (Binrep.Type.Prefix.Count.CountPrefixed pfx f a)
- Binrep.Type.Prefix.Count: instance (Binrep.Util.Prefix.Prefix pfx, Data.Foldable.Foldable f, Binrep.Put.Put pfx, Binrep.Put.Put (f a)) => Binrep.Put.Put (Binrep.Type.Prefix.Count.CountPrefixed pfx f a)
- Binrep.Type.Prefix.Count: instance (GHC.TypeNats.KnownNat (Binrep.Util.Prefix.Max pfx), Data.Foldable.Foldable f, Data.Typeable.Internal.Typeable pfx) => Refined.Predicate (Binrep.Type.Prefix.Count.CountPrefix pfx) (f a)
- Binrep.Type.Prefix.Count: instance (GHC.TypeNats.KnownNat (Binrep.Util.Prefix.Max pfx), Data.Foldable.Foldable f, Data.Typeable.Internal.Typeable pfx) => Refined.Predicate1 (Binrep.Type.Prefix.Count.CountPrefix pfx) f
- Binrep.Type.Prefix.Count: instance forall k pfx (f :: k -> GHC.Types.Type) (a :: k). Binrep.CBLen.IsCBLen (Binrep.Type.Prefix.Count.CountPrefixed pfx f a)
- Binrep.Type.Prefix.Size: instance (Binrep.Util.Prefix.Prefix pfx, Binrep.BLen.BLen a, Binrep.BLen.BLen pfx) => Binrep.BLen.BLen (Binrep.Type.Prefix.Size.SizePrefixed pfx a)
- Binrep.Type.Prefix.Size: instance (Binrep.Util.Prefix.Prefix pfx, Binrep.BLen.BLen a, Binrep.Put.Put pfx, Binrep.Put.Put a) => Binrep.Put.Put (Binrep.Type.Prefix.Size.SizePrefixed pfx a)
- Binrep.Type.Prefix.Size: instance (Binrep.Util.Prefix.Prefix pfx, Binrep.Type.Prefix.Size.GetSize a, Binrep.Get.Get pfx) => Binrep.Get.Get (Binrep.Type.Prefix.Size.SizePrefixed pfx a)
- Binrep.Type.Prefix.Size: instance (GHC.TypeNats.KnownNat (Binrep.Util.Prefix.Max pfx), Binrep.BLen.BLen a, Data.Typeable.Internal.Typeable pfx) => Refined.Predicate (Binrep.Type.Prefix.Size.SizePrefix pfx) a
- Binrep.Type.Sized: instance (Binrep.BLen.BLen a, GHC.TypeNats.KnownNat n) => Refined.Predicate (Binrep.Type.Sized.Size n) a
- Binrep.Type.Text.Encoding.Ascii: catchErrorCall :: (a -> b) -> a -> Either String b
- Binrep.Type.Text.Encoding.Ascii: instance Refined.Predicate Binrep.Type.Text.Encoding.Ascii.Ascii Data.Text.Internal.Text
- Binrep.Type.Text.Encoding.ShiftJis: instance Refined.Predicate Binrep.Type.Text.Encoding.ShiftJis.ShiftJis Data.Text.Internal.Text
- Binrep.Type.Text.Encoding.Utf16: instance Data.Typeable.Internal.Typeable end => Refined.Predicate (Binrep.Type.Text.Encoding.Utf16.Utf16 end) Data.Text.Internal.Text
- Binrep.Type.Text.Encoding.Utf32: instance Data.Typeable.Internal.Typeable end => Refined.Predicate (Binrep.Type.Text.Encoding.Utf32.Utf32 end) Data.Text.Internal.Text
- Binrep.Type.Text.Encoding.Utf8: instance Refined.Predicate Binrep.Type.Text.Encoding.Utf8.Utf8 Data.Text.Internal.Text
- Binrep.Util: natVal'' :: forall a. KnownNat a => Natural
- Binrep.Util: posIntToNat :: Int -> Natural
- Binrep.Util: tshow :: Show a => a -> Text
- Binrep.Util.Prefix: class Prefix a where {
- Binrep.Util.Prefix: instance Binrep.Util.Prefix.Prefix ()
- Binrep.Util.Prefix: instance Binrep.Util.Prefix.Prefix GHC.Word.Word16
- Binrep.Util.Prefix: instance Binrep.Util.Prefix.Prefix GHC.Word.Word32
- Binrep.Util.Prefix: instance Binrep.Util.Prefix.Prefix GHC.Word.Word64
- Binrep.Util.Prefix: instance Binrep.Util.Prefix.Prefix GHC.Word.Word8
- Binrep.Util.Prefix: instance Binrep.Util.Prefix.Prefix a => Binrep.Util.Prefix.Prefix (Raehik.Compat.Data.Primitive.Types.Endian.ByteOrdered end a)
- Binrep.Util.Prefix: lenToPfx :: Prefix a => Int -> a
- Binrep.Util.Prefix: pfxToLen :: Prefix a => a -> Int
- Binrep.Util.Prefix: type Max a :: Natural;
- Binrep.Util.Prefix: }
+ Binrep.BLen: blenGenericSumRaw :: (Generic a, GFoldMapSum BLen Raw (Rep a), GAssertNotVoid a, GAssertSum a) => (String -> Int) -> a -> Int
+ Binrep.BLen: instance (GHC.Generics.Generic a, Generic.Data.Function.FoldMap.NonSum.GFoldMapNonSum Binrep.BLen.BLen (GHC.Generics.Rep a), Generic.Type.Assert.GAssertNotVoid a, Generic.Type.Assert.GAssertNotSum a) => Binrep.BLen.BLen (Binrep.Common.Via.Generically.NonSum.GenericallyNonSum a)
+ Binrep.BLen: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.BLen.BLen (Rerefined.Refine.Refined pr (Rerefined.Refine.Refined pl a)) => Binrep.BLen.BLen (Rerefined.Refine.Refined (Rerefined.Predicate.Logical.And.And pl pr) a)
+ Binrep.CBLen: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.CBLen.IsCBLen (Rerefined.Refine.Refined pr (Rerefined.Refine.Refined pl a)) => Binrep.CBLen.IsCBLen (Rerefined.Refine.Refined (Rerefined.Predicate.Logical.And.And pl pr) a)
+ Binrep.Example.Sum: SumType1 :: Word8 -> SumType
+ Binrep.Example.Sum: SumType2 :: Word8 -> Word8 -> SumType
+ Binrep.Example.Sum: data SumType
+ Binrep.Example.Sum: instance Binrep.Get.Get Binrep.Example.Sum.SumType
+ Binrep.Example.Sum: instance GHC.Generics.Generic Binrep.Example.Sum.SumType
+ Binrep.Example.Sum: instance GHC.Show.Show Binrep.Example.Sum.SumType
+ Binrep.Example.Tga: HasColorMap :: ColorMapType
+ Binrep.Example.Tga: Header :: SW s Word8 -> ColorMapType -> ImageType -> Header (s :: Strength) (a :: k)
+ Binrep.Example.Tga: NoColorMap :: ColorMapType
+ Binrep.Example.Tga: NoImageData :: ImageType
+ Binrep.Example.Tga: RLEBW :: ImageType
+ Binrep.Example.Tga: RLEColorMapped :: ImageType
+ Binrep.Example.Tga: RLETrueColor :: ImageType
+ Binrep.Example.Tga: UncompBW :: ImageType
+ Binrep.Example.Tga: UncompColorMapped :: ImageType
+ Binrep.Example.Tga: UncompTrueColor :: ImageType
+ Binrep.Example.Tga: [colorMapType] :: Header (s :: Strength) (a :: k) -> ColorMapType
+ Binrep.Example.Tga: [idLen] :: Header (s :: Strength) (a :: k) -> SW s Word8
+ Binrep.Example.Tga: [imageType] :: Header (s :: Strength) (a :: k) -> ImageType
+ Binrep.Example.Tga: data ColorMapType
+ Binrep.Example.Tga: data Header (s :: Strength) (a :: k)
+ Binrep.Example.Tga: data ImageType
+ Binrep.Get: cut1 :: forall (st :: ZeroBitType) text a. ParserT st (ParseError Pos text) a -> [text] -> ParserT st (ParseError Pos text) a
+ Binrep.Get: cutting1 :: forall (st :: ZeroBitType) text a. ParserT st (ParseError Pos text) a -> [text] -> ParserT st (ParseError Pos text) a
+ Binrep.Get: err1 :: forall text (st :: ZeroBitType) a. [text] -> ParserT st (ParseError Pos text) a
+ Binrep.Get: getGenericSumRaw :: forall pt a. (Generic a, GTraverseSum Get Raw (Rep a), Get pt, GAssertNotVoid a, GAssertSum a) => (String -> pt) -> (pt -> pt -> Bool) -> Getter a
+ Binrep.Get: instance Generic.Data.FOnCstr.GenericFOnCstr Binrep.Get.Get
+ Binrep.Get: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.Get.Get (Rerefined.Refine.Refined pr (Rerefined.Refine.Refined pl a)) => Binrep.Get.Get (Rerefined.Refine.Refined (Rerefined.Predicate.Logical.And.And pl pr) a)
+ Binrep.Get.Error: ParseErrorSingle :: pos -> [text] -> ParseErrorSingle pos text
+ Binrep.Get.Error: [parseErrorSinglePos] :: ParseErrorSingle pos text -> pos
+ Binrep.Get.Error: [parseErrorSingleText] :: ParseErrorSingle pos text -> [text]
+ Binrep.Get.Error: data ParseErrorSingle pos text
+ Binrep.Get.Error: instance (GHC.Show.Show pos, GHC.Show.Show text) => GHC.Show.Show (Binrep.Get.Error.ParseErrorSingle pos text)
+ Binrep.Get.Error: mapParseErrorSinglePos :: (pos1 -> pos2) -> ParseErrorSingle pos1 text -> ParseErrorSingle pos2 text
+ Binrep.Get.Error: parseError1 :: [text] -> pos -> ParseError pos text
+ Binrep.Get.Error: parseErrorTextGenericFieldBld :: String -> String -> Maybe String -> Natural -> [Builder]
+ Binrep.Get.Error: parseErrorTextGenericNoCstrMatchBld :: String -> [Builder]
+ Binrep.Get.Error: parseErrorTextGenericSumTagBld :: String -> [Builder]
+ Binrep.Get.Error: type ParseError pos text = [ParseErrorSingle pos text]
+ Binrep.Get.Struct: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.Get.Struct.GetC (Rerefined.Refine.Refined pr (Rerefined.Refine.Refined pl a)) => Binrep.Get.Struct.GetC (Rerefined.Refine.Refined (Rerefined.Predicate.Logical.And.And pl pr) a)
+ Binrep.Put: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.Put.Put (Rerefined.Refine.Refined pr (Rerefined.Refine.Refined pl a)) => Binrep.Put.Put (Rerefined.Refine.Refined (Rerefined.Predicate.Logical.And.And pl pr) a)
+ Binrep.Put: putGenericSumRaw :: (Generic a, GFoldMapSum Put Raw (Rep a), GAssertNotVoid a, GAssertSum a) => (String -> Putter) -> a -> Putter
+ Binrep.Put.Struct: instance forall k1 k (pr :: k1) (pl :: k) a. Binrep.Put.Struct.PutC (Rerefined.Refine.Refined pr (Rerefined.Refine.Refined pl a)) => Binrep.Put.Struct.PutC (Rerefined.Refine.Refined (Rerefined.Predicate.Logical.And.And pl pr) a)
+ Binrep.Type.AsciiNat: asciiBytesToNat :: Num a => (a -> Maybe a) -> a -> ByteString -> Either Word8 a
+ Binrep.Type.AsciiNat: asciiNatCompare :: forall a (bl :: Natural) (br :: Natural). Ord a => Refined (AsciiNat bl) a -> Refined (AsciiNat br) a -> Ordering
+ Binrep.Type.AsciiNat: class HasBaseOps a
+ Binrep.Type.AsciiNat: data AsciiNat (base :: Natural)
+ Binrep.Type.AsciiNat: getAsciiNatByByte :: Num a => a -> Builder -> (a -> Maybe a) -> Getter a
+ Binrep.Type.AsciiNat: instance (Binrep.Type.AsciiNat.HasBaseOps a, GHC.TypeNats.KnownNat base) => Binrep.BLen.BLen (Rerefined.Refine.Refined (Binrep.Type.AsciiNat.AsciiNat base) a)
+ Binrep.Type.AsciiNat: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Binrep.Get.Get (Rerefined.Refine.Refined (Binrep.Type.AsciiNat.AsciiNat 10) a)
+ Binrep.Type.AsciiNat: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Binrep.Get.Get (Rerefined.Refine.Refined (Binrep.Type.AsciiNat.AsciiNat 16) a)
+ Binrep.Type.AsciiNat: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Binrep.Get.Get (Rerefined.Refine.Refined (Binrep.Type.AsciiNat.AsciiNat 2) a)
+ Binrep.Type.AsciiNat: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Binrep.Get.Get (Rerefined.Refine.Refined (Binrep.Type.AsciiNat.AsciiNat 8) a)
+ Binrep.Type.AsciiNat: instance (Rerefined.Predicate.KnownPredicateName (Binrep.Type.AsciiNat.AsciiNat base), GHC.Num.Num a, GHC.Classes.Ord a) => Rerefined.Predicate.Refine (Binrep.Type.AsciiNat.AsciiNat base) a
+ Binrep.Type.AsciiNat: instance Binrep.Type.AsciiNat.HasBaseOps GHC.Int.Int16
+ Binrep.Type.AsciiNat: instance Binrep.Type.AsciiNat.HasBaseOps GHC.Int.Int32
+ Binrep.Type.AsciiNat: instance Binrep.Type.AsciiNat.HasBaseOps GHC.Int.Int64
+ Binrep.Type.AsciiNat: instance Binrep.Type.AsciiNat.HasBaseOps GHC.Int.Int8
+ Binrep.Type.AsciiNat: instance Binrep.Type.AsciiNat.HasBaseOps GHC.Num.Natural.Natural
+ Binrep.Type.AsciiNat: instance Binrep.Type.AsciiNat.HasBaseOps GHC.Types.Int
+ Binrep.Type.AsciiNat: instance Binrep.Type.AsciiNat.HasBaseOps GHC.Types.Word
+ Binrep.Type.AsciiNat: instance Binrep.Type.AsciiNat.HasBaseOps GHC.Word.Word16
+ Binrep.Type.AsciiNat: instance Binrep.Type.AsciiNat.HasBaseOps GHC.Word.Word32
+ Binrep.Type.AsciiNat: instance Binrep.Type.AsciiNat.HasBaseOps GHC.Word.Word64
+ Binrep.Type.AsciiNat: instance Binrep.Type.AsciiNat.HasBaseOps GHC.Word.Word8
+ Binrep.Type.AsciiNat: instance GHC.Real.Integral a => Binrep.Put.Put (Rerefined.Refine.Refined (Binrep.Type.AsciiNat.AsciiNat 10) a)
+ Binrep.Type.AsciiNat: instance GHC.Real.Integral a => Binrep.Put.Put (Rerefined.Refine.Refined (Binrep.Type.AsciiNat.AsciiNat 16) a)
+ Binrep.Type.AsciiNat: instance GHC.Real.Integral a => Binrep.Put.Put (Rerefined.Refine.Refined (Binrep.Type.AsciiNat.AsciiNat 2) a)
+ Binrep.Type.AsciiNat: instance GHC.Real.Integral a => Binrep.Put.Put (Rerefined.Refine.Refined (Binrep.Type.AsciiNat.AsciiNat 8) a)
+ Binrep.Type.AsciiNat: instance Rerefined.Predicate.Predicate (Binrep.Type.AsciiNat.AsciiNat base)
+ Binrep.Type.AsciiNat: parseBinaryAsciiDigit :: (Num a, Ord a) => a -> Maybe a
+ Binrep.Type.AsciiNat: parseDecimalAsciiDigit :: (Num a, Ord a) => a -> Maybe a
+ Binrep.Type.AsciiNat: parseHexAsciiDigit :: (Num a, Ord a) => a -> Maybe a
+ Binrep.Type.AsciiNat: parseOctalAsciiDigit :: (Num a, Ord a) => a -> Maybe a
+ Binrep.Type.AsciiNat: sizeInBase# :: HasBaseOps a => Word# -> a -> Word#
+ Binrep.Type.AsciiNat: sizeInBaseWordSize :: Integral a => Word# -> a -> Word#
+ Binrep.Type.AsciiNat: unsafeDigits :: forall b a. (Integral a, Integral b) => a -> a -> NonEmpty b
+ Binrep.Type.AsciiNat: unsafeHexDigitToAsciiLower :: (Num a, Ord a) => a -> a
+ Binrep.Type.Magic: -- <a>Natural</a>s).
+ Binrep.Type.Magic: [Magic] :: forall {k} (a :: k). Magic a
+ Binrep.Type.Magic: instance Binrep.Type.Magic.Magical bs
+ Binrep.Type.Magic: instance forall (bs :: [GHC.Num.Natural.Natural]) k (a :: k). (bs GHC.Types.~ Binrep.Type.Magic.MagicBytes a, Bytezap.Parser.Struct.TypeLits.Bytes.ParseReifyBytesW64 0 bs, Bytezap.Struct.TypeLits.Bytes.ReifyBytesW64 bs, GHC.TypeNats.KnownNat (Binrep.Type.Magic.Length 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.MagicBytes a, Bytezap.Parser.Struct.TypeLits.Bytes.ParseReifyBytesW64 0 bs) => Binrep.Get.Struct.GetC (Binrep.Type.Magic.Magic a)
+ Binrep.Type.NullPadded: instance (Rerefined.Predicate.KnownPredicateName (Binrep.Type.NullPadded.NullPad n), Binrep.BLen.BLen a, GHC.TypeNats.KnownNat n) => Rerefined.Predicate.Refine (Binrep.Type.NullPadded.NullPad n) a
+ Binrep.Type.NullPadded: instance Rerefined.Predicate.Predicate (Binrep.Type.NullPadded.NullPad n)
+ Binrep.Type.NullTerminated: instance Rerefined.Predicate.Predicate Binrep.Type.NullTerminated.NullTerminate
+ Binrep.Type.NullTerminated: instance Rerefined.Predicate.Refine Binrep.Type.NullTerminated.NullTerminate Data.ByteString.Internal.Type.ByteString
+ Binrep.Type.Prefix.Count: instance (Binrep.Type.Prefix.Internal.LenNat pfx, Binrep.Type.Prefix.Count.GetCount f, Binrep.Get.Get pfx, Binrep.Get.Get a) => Binrep.Get.Get (Binrep.Type.Prefix.Count.CountPrefixed pfx f a)
+ Binrep.Type.Prefix.Count: instance (Binrep.Type.Prefix.Internal.LenNat pfx, Data.Foldable.Foldable f, Binrep.BLen.BLen pfx, Binrep.BLen.BLen (f a)) => Binrep.BLen.BLen (Binrep.Type.Prefix.Count.CountPrefixed pfx f a)
+ Binrep.Type.Prefix.Count: instance (Binrep.Type.Prefix.Internal.LenNat pfx, Data.Foldable.Foldable f, Binrep.Put.Put pfx, Binrep.Put.Put (f a)) => Binrep.Put.Put (Binrep.Type.Prefix.Count.CountPrefixed pfx f a)
+ Binrep.Type.Prefix.Count: instance (Rerefined.Predicate.KnownPredicateName (Binrep.Type.Prefix.Count.CountPrefix pfx), GHC.TypeNats.KnownNat (Binrep.Type.Prefix.Internal.LenNatMax pfx), Data.Foldable.Foldable f) => Rerefined.Predicate.Refine (Binrep.Type.Prefix.Count.CountPrefix pfx) (f a)
+ Binrep.Type.Prefix.Count: instance (Rerefined.Predicate.KnownPredicateName (Binrep.Type.Prefix.Count.CountPrefix pfx), GHC.TypeNats.KnownNat (Binrep.Type.Prefix.Internal.LenNatMax pfx), Data.Foldable.Foldable f) => Rerefined.Predicate.Refine1 (Binrep.Type.Prefix.Count.CountPrefix pfx) f
+ Binrep.Type.Prefix.Count: instance Rerefined.Predicate.Predicate (Binrep.Type.Prefix.Count.CountPrefix pfx)
+ Binrep.Type.Prefix.Count: instance forall k1 pfx (f :: k1 -> GHC.Types.Type) (a :: k1). Binrep.CBLen.IsCBLen (Binrep.Type.Prefix.Count.CountPrefixed pfx f a)
+ Binrep.Type.Prefix.Internal: -- | The name of the type, to display when used as part of a predicate.
+ Binrep.Type.Prefix.Internal: class LenNat a where {
+ Binrep.Type.Prefix.Internal: instance Binrep.Type.Prefix.Internal.LenNat ()
+ Binrep.Type.Prefix.Internal: instance Binrep.Type.Prefix.Internal.LenNat GHC.Word.Word16
+ Binrep.Type.Prefix.Internal: instance Binrep.Type.Prefix.Internal.LenNat GHC.Word.Word32
+ Binrep.Type.Prefix.Internal: instance Binrep.Type.Prefix.Internal.LenNat GHC.Word.Word64
+ Binrep.Type.Prefix.Internal: instance Binrep.Type.Prefix.Internal.LenNat GHC.Word.Word8
+ Binrep.Type.Prefix.Internal: instance Binrep.Type.Prefix.Internal.LenNat a => Binrep.Type.Prefix.Internal.LenNat (Raehik.Compat.Data.Primitive.Types.Endian.ByteOrdered end a)
+ Binrep.Type.Prefix.Internal: lenToNat :: LenNat a => Int -> a
+ Binrep.Type.Prefix.Internal: natToLen :: LenNat a => a -> Int
+ Binrep.Type.Prefix.Internal: type LenNatMax a :: Natural;
+ Binrep.Type.Prefix.Internal: type LenNatName a :: Symbol;
+ Binrep.Type.Prefix.Internal: }
+ Binrep.Type.Prefix.Size: instance (Binrep.Type.Prefix.Internal.LenNat pfx, Binrep.BLen.BLen a, Binrep.BLen.BLen pfx) => Binrep.BLen.BLen (Binrep.Type.Prefix.Size.SizePrefixed pfx a)
+ Binrep.Type.Prefix.Size: instance (Binrep.Type.Prefix.Internal.LenNat pfx, Binrep.BLen.BLen a, Binrep.Put.Put pfx, Binrep.Put.Put a) => Binrep.Put.Put (Binrep.Type.Prefix.Size.SizePrefixed pfx a)
+ Binrep.Type.Prefix.Size: instance (Binrep.Type.Prefix.Internal.LenNat pfx, Binrep.Type.Prefix.Size.GetSize a, Binrep.Get.Get pfx) => Binrep.Get.Get (Binrep.Type.Prefix.Size.SizePrefixed pfx a)
+ Binrep.Type.Prefix.Size: instance (Rerefined.Predicate.KnownPredicateName (Binrep.Type.Prefix.Size.SizePrefix pfx), GHC.TypeNats.KnownNat (Binrep.Type.Prefix.Internal.LenNatMax pfx), Binrep.BLen.BLen a) => Rerefined.Predicate.Refine (Binrep.Type.Prefix.Size.SizePrefix pfx) a
+ Binrep.Type.Prefix.Size: instance Rerefined.Predicate.Predicate (Binrep.Type.Prefix.Size.SizePrefix pfx)
+ Binrep.Type.Sized: instance (Rerefined.Predicate.KnownPredicateName (Binrep.Type.Sized.Size n), Binrep.BLen.BLen a, GHC.TypeNats.KnownNat n) => Rerefined.Predicate.Refine (Binrep.Type.Sized.Size n) a
+ Binrep.Type.Sized: instance Rerefined.Predicate.Predicate (Binrep.Type.Sized.Size n)
+ Binrep.Type.Text.Encoding.Ascii: instance Rerefined.Predicate.Predicate Binrep.Type.Text.Encoding.Ascii.Ascii
+ Binrep.Type.Text.Encoding.Ascii: instance Rerefined.Predicate.Refine Binrep.Type.Text.Encoding.Ascii.Ascii Data.Text.Internal.Text
+ Binrep.Type.Text.Encoding.ShiftJis: instance Rerefined.Predicate.Predicate Binrep.Type.Text.Encoding.ShiftJis.ShiftJis
+ Binrep.Type.Text.Encoding.ShiftJis: instance Rerefined.Predicate.Refine Binrep.Type.Text.Encoding.ShiftJis.ShiftJis Data.Text.Internal.Text
+ Binrep.Type.Text.Encoding.Utf16: instance Rerefined.Predicate.Predicate (Binrep.Type.Text.Encoding.Utf16.Utf16 end)
+ Binrep.Type.Text.Encoding.Utf16: instance Rerefined.Predicate.Refine (Binrep.Type.Text.Encoding.Utf16.Utf16 end) Data.Text.Internal.Text
+ Binrep.Type.Text.Encoding.Utf32: instance Rerefined.Predicate.Predicate (Binrep.Type.Text.Encoding.Utf32.Utf32 end)
+ Binrep.Type.Text.Encoding.Utf32: instance Rerefined.Predicate.Refine (Binrep.Type.Text.Encoding.Utf32.Utf32 end) Data.Text.Internal.Text
+ Binrep.Type.Text.Encoding.Utf8: instance Rerefined.Predicate.Predicate Binrep.Type.Text.Encoding.Utf8.Utf8
+ Binrep.Type.Text.Encoding.Utf8: instance Rerefined.Predicate.Refine Binrep.Type.Text.Encoding.Utf8.Utf8 Data.Text.Internal.Text
+ Binrep.Util.ByteOrder: type family EndianSuffix (end :: ByteOrder) :: Symbol
+ Raehik.Compat.FlatParse.Basic.CutWithPos: cut' :: forall (st :: ZeroBitType) e a. ParserT st e a -> (Pos -> e) -> ParserT st e a
+ Raehik.Compat.FlatParse.Basic.CutWithPos: err' :: forall e (st :: ZeroBitType) a. (Pos -> e) -> ParserT st e a
+ Util.TypeNats: natValWord :: forall (n :: Nat). KnownNat n => Word
- Binrep.BLen: blenGenericNonSum :: forall a. (Generic a, GFoldMapNonSum BLen (Rep a), GAssertNotVoid a, GAssertNotSum a) => a -> Int
+ Binrep.BLen: blenGenericNonSum :: (Generic a, GFoldMapNonSum BLen (Rep a), GAssertNotVoid a, GAssertNotSum a) => a -> Int
- Binrep.BLen: blenGenericSum :: forall a. (Generic a, GFoldMapSum BLen (Rep a), GAssertNotVoid a, GAssertSum a) => (String -> Int) -> a -> Int
+ Binrep.BLen: blenGenericSum :: forall {k} (sumtag :: k) a. (Generic a, GFoldMapSum BLen sumtag (Rep a), GAssertNotVoid a, GAssertSum a) => ParseCstrTo sumtag Int -> a -> Int
- Binrep.BLen: cblen :: forall a. KnownNat (CBLen a) => Int
+ Binrep.BLen: cblen :: forall {k} (a :: k). KnownNat (CBLen a) => Int
- Binrep.CBLen: cblen :: forall a. KnownNat (CBLen a) => Int
+ Binrep.CBLen: cblen :: forall {k} (a :: k). KnownNat (CBLen a) => Int
- Binrep.CBLen: cblen# :: forall a. KnownNat (CBLen a) => Int#
+ Binrep.CBLen: cblen# :: forall {k} (a :: k). KnownNat (CBLen a) => Int#
- Binrep.CBLen: cblenProxy# :: forall a. KnownNat (CBLen a) => Proxy# a -> Int#
+ Binrep.CBLen: cblenProxy# :: forall {k} (a :: k). KnownNat (CBLen a) => Proxy# a -> Int#
- Binrep.CBLen: class IsCBLen a where {
+ Binrep.CBLen: class IsCBLen (a :: k) where {
- Binrep.CBLen: data CBLenSym a
+ Binrep.CBLen: data CBLenSym (a1 :: FunKind a Natural)
- Binrep.CBLen: data JustX a b
+ Binrep.CBLen: data JustX (a :: k) (b :: k1)
- Binrep.CBLen: type CBLen a :: Natural;
+ Binrep.CBLen: type CBLen (a :: k) :: Natural;
- Binrep.CBLen: type CBLenGenericNonSum a = GTFoldMapCAddition CBLenSym (Rep a)
+ Binrep.CBLen: type CBLenGenericNonSum a = GTFoldMapCAddition CBLenSym :: FunKind Type Natural -> Type Rep a
- Binrep.CBLen: type CBLenGenericSum (w :: Type) a = GCBLen w (Rep a)
+ Binrep.CBLen: type CBLenGenericSum w a = GCBLen w Rep a
- Binrep.CBLen: type family GCBLenCaseMaybe a
+ Binrep.CBLen: type family GCBLenCaseMaybe a :: k
- Binrep.Common.Class.TypeErrors: type ENoSum = 'Text "No binary representation for unannotated sum data type" :$$: 'Text "Consider defining a custom data type" :<>: 'Text " and deriving a generic instance with explicit sum handling"
+ Binrep.Common.Class.TypeErrors: type ENoSum = 'Text "No binary representation for unannotated sum data type" ':$$: 'Text "Consider defining a custom data type" ':<>: 'Text " and deriving a generic instance with explicit sum handling"
- Binrep.Get: bzToFp :: forall a e st. KnownNat (CBLen a) => ParserT st e a -> ParserT st e a
+ Binrep.Get: bzToFp :: KnownNat (CBLen a) => GetterC a -> Getter a
- Binrep.Get: fpToBz :: ParserT st e a -> Int# -> (a -> Int# -> ParserT st e r) -> ParserT st e r
+ Binrep.Get: fpToBz :: forall (st :: ZeroBitType) text a r. ParserT st (ParseError Pos text) a -> Int# -> (a -> Int# -> ParserT st (ParseError Int text) r) -> ParserT st (ParseError Int text) r
- Binrep.Get: getGenericNonSum :: forall a. (Generic a, GTraverseNonSum Get (Rep a), GAssertNotVoid a, GAssertNotSum a) => Getter a
+ Binrep.Get: getGenericNonSum :: (Generic a, GTraverseNonSum Get (Rep a), GAssertNotVoid a, GAssertNotSum a) => Getter a
- Binrep.Get: getGenericSum :: forall pt a. (Generic a, GTraverseSum Get (Rep a), Get pt, GAssertNotVoid a, GAssertSum a) => PfxTagCfg pt -> Getter a
+ Binrep.Get: getGenericSum :: forall {k} (sumtag :: k) pt a. (Generic a, GTraverseSum Get sumtag (Rep a), Get pt, GAssertNotVoid a, GAssertSum a) => ParseCstrTo sumtag pt -> (pt -> pt -> Bool) -> Getter a
- Binrep.Get: getPrim :: forall a. Prim' a => Getter a
+ Binrep.Get: getPrim :: Prim' a => Getter a
- Binrep.Get: runGet :: Get a => ByteString -> Either E (a, ByteString)
+ Binrep.Get: runGet :: Get a => ByteString -> Either (ParseError Int Builder) (a, ByteString)
- Binrep.Get: runGetter :: Getter a -> ByteString -> Either E (a, ByteString)
+ Binrep.Get: runGetter :: Getter a -> ByteString -> Either (ParseError Int Builder) (a, ByteString)
- Binrep.Get: type Getter a = Parser E a
+ Binrep.Get: type Getter = Parser ParseError Pos Builder
- Binrep.Get.Struct: getGenericStruct :: forall a. (Generic a, GParse GetC (Rep a), GAssertNotVoid a, GAssertNotSum a) => GetterC a
+ Binrep.Get.Struct: getGenericStruct :: (Generic a, GParse GetC (Rep a), GAssertNotVoid a, GAssertNotSum a) => GetterC a
- Binrep.Get.Struct: runGetCBs :: forall a. (GetC a, KnownNat (CBLen a)) => ByteString -> Either E a
+ Binrep.Get.Struct: runGetCBs :: (GetC a, KnownNat (CBLen a)) => ByteString -> Either (ParseError Int Builder) a
- Binrep.Get.Struct: type GetterC = Parser E
+ Binrep.Get.Struct: type GetterC = Parser ParseError Int Builder
- Binrep.Get.Struct: unsafeRunGetCPtr :: forall a. GetC a => Ptr Word8 -> Either E a
+ Binrep.Get.Struct: unsafeRunGetCPtr :: GetC a => Ptr Word8 -> Either (ParseError Int Builder) a
- Binrep.Put: putGenericNonSum :: forall a. (Generic a, GFoldMapNonSum Put (Rep a), GAssertNotVoid a, GAssertNotSum a) => a -> Putter
+ Binrep.Put: putGenericNonSum :: (Generic a, GFoldMapNonSum Put (Rep a), GAssertNotVoid a, GAssertNotSum a) => a -> Putter
- Binrep.Put: putGenericSum :: forall a. (Generic a, GFoldMapSum Put (Rep a), GAssertNotVoid a, GAssertSum a) => (String -> Putter) -> a -> Putter
+ Binrep.Put: putGenericSum :: forall {k} (sumtag :: k) a. (Generic a, GFoldMapSum Put sumtag (Rep a), GAssertNotVoid a, GAssertSum a) => ParseCstrTo sumtag Putter -> a -> Putter
- Binrep.Put.Struct: putGenericStruct :: forall a. (Generic a, GPoke PutC (Rep a), GAssertNotVoid a, GAssertNotSum a) => a -> PutterC
+ Binrep.Put.Struct: putGenericStruct :: (Generic a, GPoke PutC (Rep a), GAssertNotVoid a, GAssertNotSum a) => a -> PutterC
- Binrep.Put.Struct: runPutC :: forall a. (PutC a, KnownNat (CBLen a)) => a -> ByteString
+ Binrep.Put.Struct: runPutC :: (PutC a, KnownNat (CBLen a)) => a -> ByteString
- Binrep.Type.Derived.NullTermPadded: type NullTermPad n = NullTerminate `And` NullPad n
+ Binrep.Type.Derived.NullTermPadded: type NullTermPad (n :: Natural) = And NullTerminate NullPad n
- Binrep.Type.Derived.NullTermPadded: type NullTermPadded n = Refined (NullTermPad n)
+ Binrep.Type.Derived.NullTermPadded: type NullTermPadded (n :: Natural) = Refined NullTermPad n
- Binrep.Type.Magic: -- | How to turn the type into a list of bytes.
+ Binrep.Type.Magic: -- | How to turn the type into a list of bytes (stored using
- Binrep.Type.Magic: type MagicBytes a :: [Natural];
+ Binrep.Type.Magic: type MagicBytes (a :: k) :: [Natural];
- Binrep.Type.NullPadded: type NullPadded n a = Refined (NullPad n) a
+ Binrep.Type.NullPadded: type NullPadded (n :: Natural) a = Refined NullPad n a
- Binrep.Type.Prefix.Count: class GetCount f
+ Binrep.Type.Prefix.Count: class GetCount (f :: Type -> Type)
- Binrep.Type.Prefix.Count: data CountPrefix (pfx :: Type)
+ Binrep.Type.Prefix.Count: data CountPrefix pfx
- Binrep.Type.Prefix.Count: type CountPrefixed pfx = Refined1 (CountPrefix pfx)
+ Binrep.Type.Prefix.Count: type CountPrefixed pfx = Refined1 CountPrefix pfx :: k1 -> Type -> k1 -> Type
- Binrep.Type.Prefix.Size: data SizePrefix (pfx :: Type)
+ Binrep.Type.Prefix.Size: data SizePrefix pfx
- Binrep.Type.Prefix.Size: type SizePrefixed pfx = Refined (SizePrefix pfx)
+ Binrep.Type.Prefix.Size: type SizePrefixed pfx = Refined SizePrefix pfx
- Binrep.Type.Sized: type Sized n = Refined (Size n)
+ Binrep.Type.Sized: type Sized (n :: Natural) = Refined Size n
- Binrep.Type.Text: class Decode enc
+ Binrep.Type.Text: class Decode (enc :: k)
- Binrep.Type.Text: class Encode enc
+ Binrep.Type.Text: class Encode (enc :: k)
- Binrep.Type.Text: encode :: forall enc. Encode enc => AsText enc -> Bytes
+ Binrep.Type.Text: encode :: forall {k} (enc :: k). Encode enc => AsText enc -> Bytes
- Binrep.Type.Text: encodeToRep :: forall rep enc. (Encode enc, Predicate rep Bytes) => AsText enc -> Either RefineException (Refined rep Bytes)
+ Binrep.Type.Text: encodeToRep :: forall {k1} {k2} (rep :: k1) (enc :: k2). (Encode enc, Refine rep Bytes) => AsText enc -> Either RefineFailure (Refined rep Bytes)
- Binrep.Type.Text: type AsText enc = Refined enc Text
+ Binrep.Type.Text: type AsText (enc :: k) = Refined enc Text
- Binrep.Type.Text.Internal: class Decode enc
+ Binrep.Type.Text.Internal: class Decode (enc :: k)
- Binrep.Type.Text.Internal: class Encode enc
+ Binrep.Type.Text.Internal: class Encode (enc :: k)
- Binrep.Type.Text.Internal: decodeText :: forall enc e. (e -> String) -> (Bytes -> Either e Text) -> Bytes -> Either String (AsText enc)
+ Binrep.Type.Text.Internal: decodeText :: forall {k} (enc :: k) e. (e -> String) -> (Bytes -> Either e Text) -> Bytes -> Either String (AsText enc)
- Binrep.Type.Text.Internal: type AsText enc = Refined enc Text
+ Binrep.Type.Text.Internal: type AsText (enc :: k) = Refined enc Text
- Binrep.Util.ByteOrder: data () => ByteOrder
+ Binrep.Util.ByteOrder: data ByteOrder
- Binrep.Util.ByteOrder: newtype () => ByteOrdered (end :: ByteOrder) a
+ Binrep.Util.ByteOrder: newtype ByteOrdered (end :: ByteOrder) a
- Raehik.Compat.FlatParse.Basic.Prim: anyPrim :: forall a e st. Prim' a => ParserT st e a
+ Raehik.Compat.FlatParse.Basic.Prim: anyPrim :: forall a e (st :: ZeroBitType). Prim' a => ParserT st e a
- Raehik.Compat.FlatParse.Basic.WithLength: parseWithLength :: ParserT st e a -> ParserT st e (a, Int)
+ Raehik.Compat.FlatParse.Basic.WithLength: parseWithLength :: forall (st :: ZeroBitType) e a. ParserT st e a -> ParserT st e (a, Int)
- Util.TypeNats: natVal'' :: forall n. KnownNat n => Natural
+ Util.TypeNats: natVal'' :: forall (n :: Nat). KnownNat n => Natural
- Util.TypeNats: natValInt :: forall n. KnownNat n => Int
+ Util.TypeNats: natValInt :: forall (n :: Nat). KnownNat n => Int
Files
- CHANGELOG.md +9/−0
- LICENSE +1/−1
- README.md +17/−7
- binrep.cabal +43/−31
- src/Binrep/BLen.hs +29/−11
- src/Binrep/CBLen.hs +2/−1
- src/Binrep/Example/Sum.hs +16/−0
- src/Binrep/Example/Tga.hs +28/−0
- src/Binrep/Generic.hs +2/−2
- src/Binrep/Get.hs +125/−76
- src/Binrep/Get/Error.hs +49/−81
- src/Binrep/Get/Struct.hs +52/−35
- src/Binrep/Put.hs +17/−10
- src/Binrep/Put/Struct.hs +3/−4
- src/Binrep/Test.hs +0/−26
- src/Binrep/Type/AsciiNat.hs +257/−0
- src/Binrep/Type/Derived/NullTermPadded.hs +2/−1
- src/Binrep/Type/Magic.hs +36/−44
- src/Binrep/Type/NullPadded.hs +18/−18
- src/Binrep/Type/NullTerminated.hs +17/−13
- src/Binrep/Type/Prefix/Count.hs +31/−21
- src/Binrep/Type/Prefix/Internal.hs +65/−0
- src/Binrep/Type/Prefix/Size.hs +23/−18
- src/Binrep/Type/Sized.hs +17/−13
- src/Binrep/Type/Text.hs +3/−3
- src/Binrep/Type/Text/Encoding/Ascii.hs +12/−28
- src/Binrep/Type/Text/Encoding/ShiftJis.hs +3/−2
- src/Binrep/Type/Text/Encoding/Utf16.hs +7/−3
- src/Binrep/Type/Text/Encoding/Utf32.hs +7/−3
- src/Binrep/Type/Text/Encoding/Utf8.hs +3/−2
- src/Binrep/Type/Text/Internal.hs +2/−3
- src/Binrep/Util.hs +0/−31
- src/Binrep/Util/ByteOrder.hs +7/−2
- src/Binrep/Util/Prefix.hs +0/−62
- src/Raehik/Compat/FlatParse/Basic/CutWithPos.hs +15/−0
- src/Util/TypeNats.hs +4/−0
- test/Binrep/GenericSpec.hs +39/−0
- test/Binrep/LawsSpec.hs +0/−54
- test/Binrep/TypesSpec.hs +19/−0
CHANGELOG.md view
@@ -1,3 +1,12 @@+## 1.0.0 (2024-10-03)+* fix `NullTerminate` check being inverted (OOPS LOL)+* fix `Get [a]` instance (list backwards xd)+* add type-level constructor parsing for generics (!!)+* rewrite `AsciiNat`+* switch from refined to rerefined (my refined rewrite)+* add missing `BLen (GenericallyNonSum a)` instance+* other various cleanup+ ## 0.8.0 (2024-04-13) * add missing `And` predicate combinators instances (`PutC`, `GetC`) * add `Type.Derived.NullTermPadded` (type synonym over `And`)
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2022 Ben Orchard (@raehik) <thefirstmuffinman@gmail.com>+Copyright (c) 2022-2024 Ben Orchard (@raehik) <thefirstmuffinman@gmail.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
README.md view
@@ -7,14 +7,13 @@ # binrep binrep is a Haskell library for *precisely modelling binary schemas*, especially-byte-oriented file formats, and working with them effectively and efficiently.-Here's why it's useful:+low-context byte-oriented file formats e.g. C enums, and working with them+effectively and efficiently. Here's why it's useful: * **Explicit:** Define Haskell data types with the binary schema "baked in". Use highly parameterized binary representation primitives including null-terminated data (e.g. C-style strings), Pascal-style data (length- prefixed), sized explicit-endian machine integers, null-padded data. Write- your own primitives if you want (if so, please consider making a PR!).+ prefixed), sized explicit-endian machine integers, null-padded data. * **Low boilerplate:** Free performant parsers and serializers via generics. _(See [Generic binary representation](#generic-binary-representation).)_ * **Easy validation:** Use the [strongweak][gh-strongweak] library design@@ -70,12 +69,23 @@ _(Generics are now handled by [generic-data-functions][hackage-gdf]. This info is largely the same, but the code is elsewhere.)_ -binrep's generic deriving makes very few decisions:+binrep includes powerful generics for automatically writing instances.+They all work the same way: * 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.+ * For sum types, the constructor is disambiguated via a tag obtained from the+ constructor name.+ * Tags may be parsed on the type or term level.++Note that when parsing sum types, we compare tags sequentially. You may design+your tag schema to have a more efficient approach. In such cases, consider using+`Generic.Data.FOnCstr` from [generic-data-functions][hackage-gdf].++As an example, you could encode constructor names as a null-terminated ASCII+bytestring for a tag. (This is provided at `Binrep.Generic.nullTermCstrPfxTag`.)+Alternatively, you may encode each constructor at a unique byte value, stated at+the end of the constructor name. 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
binrep.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.35.2.+-- This file has been generated from package.yaml by hpack version 0.36.1. -- -- see: https://github.com/sol/hpack name: binrep-version: 0.8.0+version: 1.0.0 synopsis: Encode precise binary representations directly in types description: Please see README.md. category: Data, Serialization, Generics@@ -17,7 +17,7 @@ license-file: LICENSE build-type: Simple tested-with:- GHC ==9.4.4+ GHC==9.8 extra-source-files: README.md CHANGELOG.md@@ -39,18 +39,21 @@ Binrep.Common.Class.TypeErrors Binrep.Common.Via.Generically.NonSum Binrep.Common.Via.Prim+ Binrep.Example.Sum+ Binrep.Example.Tga Binrep.Generic Binrep.Get Binrep.Get.Error Binrep.Get.Struct Binrep.Put Binrep.Put.Struct- Binrep.Test+ Binrep.Type.AsciiNat Binrep.Type.Derived.NullTermPadded Binrep.Type.Magic Binrep.Type.NullPadded Binrep.Type.NullTerminated Binrep.Type.Prefix.Count+ Binrep.Type.Prefix.Internal Binrep.Type.Prefix.Size Binrep.Type.Sized Binrep.Type.Text@@ -61,10 +64,9 @@ Binrep.Type.Text.Encoding.Utf8 Binrep.Type.Text.Internal Binrep.Type.Thin- Binrep.Util Binrep.Util.ByteOrder Binrep.Util.Generic- Binrep.Util.Prefix+ Raehik.Compat.FlatParse.Basic.CutWithPos Raehik.Compat.FlatParse.Basic.Prim Raehik.Compat.FlatParse.Basic.WithLength Util.TypeNats@@ -83,22 +85,25 @@ TypeFamilies DataKinds MagicHash- ghc-options: -Wall+ ghc-options: -Wall -Wno-unticked-promoted-constructors build-depends:- base >=4.14 && <5+ base >=4.18 && <5 , bytestring >=0.11 && <0.13- , bytezap >=1.2.0 && <1.3+ , bytezap >=1.6.0 && <1.7 , deepseq >=1.4.6.1 && <1.6 , defun-core ==0.1.* , flatparse >=0.5.0.2 && <0.6- , generic-data-functions >=0.5.0 && <0.6+ , generic-data-functions >=0.6.0 && <0.7 , generic-type-asserts >=0.3.0 && <0.4 , generic-type-functions >=0.1.0 && <0.2+ , ghc-bignum ==1.3.* , parser-combinators >=1.3.0 && <1.4- , refined1 ==0.9.*- , strongweak >=0.6.0 && <0.7- , text >=1.2.5.0 && <2.1- , type-level-bytestrings >=0.1.0 && <0.2+ , rerefined >=0.6.0 && <0.7+ , strongweak >=0.9.1 && <0.10+ , text >=2.0 && <2.2+ , text-builder-linear >=0.1.3 && <0.2+ , type-level-bytestrings >=0.1.0 && <0.3+ , type-level-show >=0.3.0 && <0.4 default-language: GHC2021 if flag(icu) cpp-options: -DHAVE_ICU@@ -110,7 +115,8 @@ main-is: Spec.hs other-modules: ArbitraryOrphans- Binrep.LawsSpec+ Binrep.GenericSpec+ Binrep.TypesSpec Paths_binrep hs-source-dirs: test@@ -125,29 +131,32 @@ TypeFamilies DataKinds MagicHash- ghc-options: -Wall+ ghc-options: -Wall -Wno-unticked-promoted-constructors build-tool-depends: hspec-discover:hspec-discover >=2.7 && <2.12 build-depends: QuickCheck >=2.14.2 && <2.15- , base >=4.14 && <5+ , base >=4.18 && <5 , binrep , bytestring >=0.11 && <0.13- , bytezap >=1.2.0 && <1.3+ , bytezap >=1.6.0 && <1.7 , deepseq >=1.4.6.1 && <1.6 , defun-core ==0.1.* , flatparse >=0.5.0.2 && <0.6- , generic-data-functions >=0.5.0 && <0.6+ , generic-data-functions >=0.6.0 && <0.7 , generic-random >=1.5.0.1 && <1.6 , generic-type-asserts >=0.3.0 && <0.4 , generic-type-functions >=0.1.0 && <0.2+ , ghc-bignum ==1.3.* , hspec >=2.7 && <2.12 , parser-combinators >=1.3.0 && <1.4 , quickcheck-instances >=0.3.26 && <0.4- , refined1 ==0.9.*- , strongweak >=0.6.0 && <0.7- , text >=1.2.5.0 && <2.1- , type-level-bytestrings >=0.1.0 && <0.2+ , rerefined >=0.6.0 && <0.7+ , strongweak >=0.9.1 && <0.10+ , text >=2.0 && <2.2+ , text-builder-linear >=0.1.3 && <0.2+ , type-level-bytestrings >=0.1.0 && <0.3+ , type-level-show >=0.3.0 && <0.4 default-language: GHC2021 if flag(icu) cpp-options: -DHAVE_ICU@@ -172,24 +181,27 @@ TypeFamilies DataKinds MagicHash- ghc-options: -Wall+ ghc-options: -Wall -Wno-unticked-promoted-constructors build-depends:- base >=4.14 && <5+ base >=4.18 && <5 , binrep , bytestring >=0.11 && <0.13- , bytezap >=1.2.0 && <1.3+ , bytezap >=1.6.0 && <1.7 , deepseq >=1.4.6.1 && <1.6 , defun-core ==0.1.* , flatparse >=0.5.0.2 && <0.6 , gauge- , generic-data-functions >=0.5.0 && <0.6+ , generic-data-functions >=0.6.0 && <0.7 , generic-type-asserts >=0.3.0 && <0.4 , generic-type-functions >=0.1.0 && <0.2+ , ghc-bignum ==1.3.* , parser-combinators >=1.3.0 && <1.4- , refined1 ==0.9.*- , strongweak >=0.6.0 && <0.7- , text >=1.2.5.0 && <2.1- , type-level-bytestrings >=0.1.0 && <0.2+ , rerefined >=0.6.0 && <0.7+ , strongweak >=0.9.1 && <0.10+ , text >=2.0 && <2.2+ , text-builder-linear >=0.1.3 && <0.2+ , type-level-bytestrings >=0.1.0 && <0.3+ , type-level-show >=0.3.0 && <0.4 default-language: GHC2021 if flag(icu) cpp-options: -DHAVE_ICU
src/Binrep/BLen.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE UndecidableInstances #-} -- for 'ViaCBLen', 'TypeError'+{-# LANGUAGE AllowAmbiguousTypes #-} -- for type-level sum type handling {- | Byte length as a simple pure function, no bells or whistles. @@ -18,7 +19,7 @@ module Binrep.BLen ( BLen(blen)- , blenGenericNonSum, blenGenericSum+ , blenGenericNonSum, blenGenericSum, blenGenericSumRaw , ViaCBLen(..), cblen ) where @@ -37,10 +38,12 @@ import Data.Monoid qualified as Monoid import GHC.Generics import Generic.Data.Function.FoldMap+import Generic.Data.MetaParse.Cstr ( Raw, ParseCstrTo ) import Generic.Type.Assert+import Binrep.Common.Via.Generically.NonSum -import Refined-import Refined.Unsafe+import Rerefined.Refine+import Rerefined.Predicate.Logical.And -- | Class for types with easily-calculated length in bytes. --@@ -65,26 +68,41 @@ ) => a -> Int blenGenericNonSum = Monoid.getSum . genericFoldMapNonSum @BLen +instance+ ( Generic a, GFoldMapNonSum BLen (Rep a)+ , GAssertNotVoid a, GAssertNotSum a+ ) => BLen (GenericallyNonSum a) where+ blen = blenGenericNonSum . unGenericallyNonSum+ -- | Measure the byte length of a term of the sum type @a@ via its 'Generic' -- instance.------ You must provide a function to obtain the byte length for the prefix tag, via--- inspecting the reified constructor names. This is regrettably inefficient.--- Alas. Do write your own instance if you want better performance! blenGenericSum+ :: forall sumtag a+ . ( Generic a, GFoldMapSum BLen sumtag (Rep a)+ , GAssertNotVoid a, GAssertSum a+ ) => ParseCstrTo sumtag Int -> a -> Int+blenGenericSum f =+ Monoid.getSum . genericFoldMapSum @BLen @sumtag (\p -> Monoid.Sum (f p))++-- TODO perhaps provide some handy wrappers that fill in blen for sumtag type+-- with cblen? how to do this well?++-- | Measure the byte length of a term of the sum type @a@ via its 'Generic'+-- instance.+blenGenericSumRaw :: forall a- . ( Generic a, GFoldMapSum BLen (Rep a)+ . ( Generic a, GFoldMapSum BLen Raw (Rep a) , GAssertNotVoid a, GAssertSum a ) => (String -> Int) -> a -> Int-blenGenericSum f =- Monoid.getSum . genericFoldMapSum @BLen (Monoid.Sum <$> f)+blenGenericSumRaw f =+ Monoid.getSum . genericFoldMapSumRaw @BLen (Monoid.Sum <$> f) -- We can't provide a Generically instance because the user must choose between -- sum and non-sum handlers. instance BLen (Refined pr (Refined pl a)) => BLen (Refined (pl `And` pr) a) where- blen = blen . reallyUnsafeRefine @_ @pr . reallyUnsafeRefine @_ @pl . unrefine+ blen = blen . unsafeRefine @_ @pr . unsafeRefine @_ @pl . unrefine instance TypeError ENoEmpty => BLen Void where blen = undefined instance TypeError ENoSum => BLen (Either a b) where blen = undefined
src/Binrep/CBLen.hs view
@@ -13,7 +13,8 @@ import DeFun.Core ( type (~>), type App ) -import Refined+import Rerefined.Refine+import Rerefined.Predicate.Logical.And import Binrep.Common.Class.TypeErrors ( ENoEmpty )
+ src/Binrep/Example/Sum.hs view
@@ -0,0 +1,16 @@+module Binrep.Example.Sum where++import Binrep+import Data.Word+import GHC.Generics ( type Generic )+import Generic.Data.FOnCstr++data SumType = SumType1 Word8 | SumType2 Word8 Word8+ deriving stock (Generic, Show)++instance Get SumType where+ get = do+ get @Word8 >>= \case+ 1 -> genericFOnCstr @Get @"SumType1"+ 2 -> genericFOnCstr @Get @"SumType2"+ _ -> error "TODO"
+ src/Binrep/Example/Tga.hs view
@@ -0,0 +1,28 @@+module Binrep.Example.Tga where++{-+import Binrep+import Binrep.Type.Derived.NullTermPadded+import Binrep.Type.AsciiNat+import Rerefined+-}+import Strongweak+import Data.Word++data Header (s :: Strength) a = Header+ { idLen :: SW s Word8+ , colorMapType :: ColorMapType+ , imageType :: ImageType+ --, colorMapSpec :: + --, imageSpec+ }++data ColorMapType = NoColorMap {- ^ 0 -} | HasColorMap {- ^ 1 -}+data ImageType+ = NoImageData+ | UncompColorMapped+ | UncompTrueColor+ | UncompBW+ | RLEColorMapped+ | RLETrueColor+ | RLEBW
src/Binrep/Generic.hs view
@@ -4,12 +4,12 @@ import Data.ByteString qualified as B import Data.Text qualified as Text import Data.Text.Encoding qualified as Text-import Refined.Unsafe+import Rerefined.Refine ( unsafeRefine ) -- | Turn a constructor name into a prefix tag by adding a null terminator. -- -- Not common in binary data representations, but safe and useful for debugging. nullTermCstrPfxTag :: String -> NullTerminated B.ByteString-nullTermCstrPfxTag = reallyUnsafeRefine . Text.encodeUtf8 . Text.pack+nullTermCstrPfxTag = unsafeRefine . Text.encodeUtf8 . Text.pack -- ^ reallyUnsafeRefine : safe assuming Haskell constructor names are UTF-8 with -- no null bytes allowed
src/Binrep/Get.hs view
@@ -1,5 +1,6 @@-{-# LANGUAGE UndecidableInstances #-} -- required below GHC 9.6-{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE UndecidableInstances #-} -- for various stuff+{-# LANGUAGE AllowAmbiguousTypes #-} -- for type-level sum type handling+{-# LANGUAGE OverloadedStrings #-} -- for easy error building module Binrep.Get ( module Binrep.Get@@ -7,18 +8,20 @@ ) where import Binrep.Get.Error+import Data.Text.Builder.Linear qualified as TBL import Binrep.Util.ByteOrder import Binrep.Common.Via.Prim ( ViaPrim(..) )-import Raehik.Compat.Data.Primitive.Types ( Prim', sizeOf )+import Raehik.Compat.Data.Primitive.Types ( Prim' ) import Raehik.Compat.Data.Primitive.Types.Endian ( ByteSwap ) -import Binrep.Get.Struct ( GetC(getC) )+import Binrep.Get.Struct ( GetC(getC), GetterC ) import Bytezap.Parser.Struct qualified as BZ import Binrep.CBLen ( IsCBLen(CBLen), cblen ) import GHC.TypeLits ( KnownNat ) import FlatParse.Basic qualified as FP import Raehik.Compat.FlatParse.Basic.Prim qualified as FP+import Raehik.Compat.FlatParse.Basic.CutWithPos qualified as FP import Data.ByteString qualified as B @@ -27,12 +30,13 @@ import GHC.Generics import Generic.Data.Function.Traverse+import Generic.Data.MetaParse.Cstr ( Raw, ParseCstrTo ) import Generic.Type.Assert import GHC.Exts ( minusAddr#, Int(I#), Int#, plusAddr#, (+#) ) -import Refined-import Refined.Unsafe+import Rerefined.Refine+import Rerefined.Predicate.Logical.And import Data.Word import Data.Int@@ -40,33 +44,42 @@ import Data.Functor.Identity import Binrep.Common.Via.Generically.NonSum -type Getter a = FP.Parser E a+import Generic.Data.FOnCstr+import Generic.Data.Function.Traverse.Constructor hiding ( ENoEmpty )+import GHC.Exts ( Proxy# ) +type Getter = FP.Parser (ParseError FP.Pos TBL.Builder)+ class Get a where -- | Parse from binary. get :: Getter a -runGet :: Get a => B.ByteString -> Either E (a, B.ByteString)+runGet+ :: Get a+ => B.ByteString+ -> Either (ParseError Int TBL.Builder) (a, B.ByteString) runGet = runGetter get -runGetter :: Getter a -> B.ByteString -> Either E (a, B.ByteString)-runGetter g bs = case FP.runParser g bs of- FP.OK a bs' -> Right (a, bs')- FP.Fail -> Left EFail- FP.Err e -> Left e+runGetter+ :: Getter a+ -> B.ByteString+ -> Either (ParseError Int TBL.Builder) (a, B.ByteString)+runGetter p bs =+ case FP.runParser p bs of+ FP.OK a bs' -> Right (a, bs')+ FP.Err e ->+ -- TODO check this is right. might need length of bs' ... ?+ Left $ fmap (mapParseErrorSinglePos (\(FP.Pos pos) -> len - pos)) e+ FP.Fail -> Left []+ where len = B.length bs instance GenericTraverse Get where- type GenericTraverseF Get = FP.Parser E+ type GenericTraverseF Get = Getter type GenericTraverseC Get a = Get a- genericTraverseAction cd cc mcs si =- getWrapGeneric cd $ EGenericField cc mcs si--instance GenericTraverseSum Get where- genericTraverseSumPfxTagAction cd =- getWrapGeneric cd $ EGenericSum . EGenericSumTag- -- TODO proper offset info- genericTraverseSumNoMatchingCstrAction cd cstrs ptText =- FP.err $ E 0 $ EGeneric cd $ EGenericSum $ EGenericSumTagNoMatch cstrs ptText+ genericTraverseAction dtName cstrName mFieldName fieldIdx =+ get `cutting1` e+ where+ e = parseErrorTextGenericFieldBld dtName cstrName mFieldName fieldIdx getGenericNonSum :: forall a@@ -82,72 +95,111 @@ get = GenericallyNonSum <$> getGenericNonSum getGenericSum+ :: forall sumtag pt a+ . ( Generic a, GTraverseSum Get sumtag (Rep a)+ , Get pt+ , GAssertNotVoid a, GAssertSum a+ ) => ParseCstrTo sumtag pt+ -> (pt -> pt -> Bool)+ -> Getter a+getGenericSum parseCstr ptEq =+ genericTraverseSum @Get @sumtag parseCstr ptGet fNoMatch ptEq+ where+ fNoMatch dtName = err1 (parseErrorTextGenericNoCstrMatchBld dtName)+ ptGet dtName = get `cutting1` parseErrorTextGenericSumTagBld dtName++getGenericSumRaw :: forall pt a- . ( Generic a, GTraverseSum Get (Rep a)+ . ( Generic a, GTraverseSum Get Raw (Rep a) , Get pt , GAssertNotVoid a, GAssertSum a- ) => PfxTagCfg pt -> Getter a-getGenericSum = genericTraverseSum @Get+ ) => (String -> pt)+ -> (pt -> pt -> Bool)+ -> Getter a+getGenericSumRaw parseCstr ptEq =+ genericTraverseSumRaw @Get parseCstr ptGet fNoMatch ptEq+ where+ fNoMatch dtName = err1 (parseErrorTextGenericNoCstrMatchBld dtName)+ ptGet dtName = get `cutting1` parseErrorTextGenericSumTagBld dtName --- We can't provide a Generically instance because the user must choose between--- sum and non-sum handlers.+-- | Emit a single error. Use with flatparse primitives that only 'FP.Fail'.+err1 :: [text] -> FP.ParserT st (ParseError FP.Pos text) a+err1 = FP.err' . parseError1 -eBase :: EBase -> Getter a-eBase eb = FP.ParserT \_fp eob s st ->- let os = I# (minusAddr# eob s)- in FP.Err# st (E os $ EBase eb)+-- | Turn a 'FP.Fail' into a single error. (Re-emits existing 'FP.Error's.)+--+-- Use when wrapping flatparse primitives that directly only 'FP.Fail'. (It's+-- fine to use with combinators if the combinator itself doesn't 'FP.Error'.)+cut1+ :: FP.ParserT st (ParseError FP.Pos text) a -> [text]+ -> FP.ParserT st (ParseError FP.Pos text) a+cut1 p texts = p `FP.cut'` parseError1 texts -getEBase :: Getter a -> EBase -> Getter a-getEBase (FP.ParserT f) eb =- FP.ParserT \fp eob s st ->- let os = I# (minusAddr# eob s)- in case f fp eob s st of- FP.Fail# st' -> FP.Err# st' (E os $ EBase eb)- FP.Err# st' e -> FP.Err# st' (E os $ EAnd e eb)- x -> x+-- | Turn a 'FP.Fail' into a single error, or prepend it to any existing ones.+--+-- Use when wrapping other 'get'ters.+--+-- We reimplement 'FP.cutting' with a tweak. Otherwise, we'd have to join lists+-- in the error case (instead of simply prepending).+cutting1+ :: FP.ParserT st (ParseError FP.Pos text) a -> [text]+ -> FP.ParserT st (ParseError FP.Pos text) a+cutting1 (FP.ParserT p) texts =+ FP.getPos >>= \pos -> FP.ParserT $ \fp eob s st ->+ case p fp eob s st of+ FP.Fail# st' -> FP.Err# st' [ParseErrorSingle pos texts]+ FP.Err# st' e' -> FP.Err# st' (ParseErrorSingle pos texts : e')+ x -> x --- | Convert a bytezap struct parser to a flatparse parser.-bzToFp- :: forall a e st. KnownNat (CBLen a)- => BZ.ParserT st e a -> FP.ParserT st e a-bzToFp (BZ.ParserT p) = FP.ensure (I# len#) >> (FP.ParserT $ \fpc _eob s st0 ->- case p fpc s 0# st0 of- BZ.OK# st1 a -> FP.OK# st1 a (s `plusAddr#` len#)- BZ.Fail# st1 -> FP.Fail# st1- BZ.Err# st1 e -> FP.Err# st1 e- )- where- !(I# len#) = cblen @a+-- We can't provide a Generically instance because the user must choose between+-- sum and non-sum handlers. +instance GenericFOnCstr Get where+ type GenericFOnCstrF Get = Getter+ type GenericFOnCstrC Get dtName cstrName gf =+ GTraverseC Get dtName cstrName 0 gf+ genericFOnCstrF (_ :: Proxy# '(dtName, cstrName)) =+ gTraverseC @Get @dtName @cstrName @0++-- TODO this is hard to parse visually. document...? fpToBz- :: FP.ParserT st e a -> Int#- -> (a -> Int# -> BZ.ParserT st e r) -> BZ.ParserT st e r+ :: FP.ParserT st (ParseError FP.Pos text) a -> Int#+ -> (a -> Int# -> BZ.ParserT st (ParseError Int text) r)+ -> BZ.ParserT st (ParseError Int text) r fpToBz (FP.ParserT p) len# fp = BZ.ParserT $ \fpc base# os# st0 -> case p fpc (base# `plusAddr#` (os# +# len#)) (base# `plusAddr#` os#) st0 of FP.OK# st1 a s -> let unconsumed# = s `minusAddr#` (base# `plusAddr#` os#) in BZ.runParserT# (fp a unconsumed#) fpc base# (os# +# unconsumed#) st1+ FP.Err# st1 e ->+ -- on error, we turn the flatparse 'FP.Pos' indices into actual byte+ -- offsets (which bytezap deals in), then emit+ let e' = fmap (mapParseErrorSinglePos (\(FP.Pos pos) -> I# len# - pos)) e+ in BZ.Err# st1 e' FP.Fail# st1 -> BZ.Fail# st1- FP.Err# st1 e -> BZ.Err# st1 e --- | Parse. On parse error, coat it in a generic context layer.-getWrapGeneric :: Get a => String -> (E -> EGeneric E) -> Getter a-getWrapGeneric = getWrapGeneric' get--getWrapGeneric' :: Getter a -> String -> (E -> EGeneric E) -> Getter a-getWrapGeneric' (FP.ParserT f) cd fe =- FP.ParserT \fp eob s st ->- let os = I# (minusAddr# eob s)- in case f fp eob s st of- FP.Fail# st' -> FP.Err# st' (E os $ EGeneric cd $ fe EFail)- FP.Err# st' e -> FP.Err# st' (E os $ EGeneric cd $ fe e)- x -> x- newtype ViaGetC a = ViaGetC { unViaGetC :: a } instance (GetC a, KnownNat (CBLen a)) => Get (ViaGetC a) where {-# INLINE get #-} get = ViaGetC <$> bzToFp getC +-- TODO messy ran out of input handling. should be a util for it+-- TODO pos handling seems correct on quick test. need stronger assertion plz+bzToFp :: forall a. KnownNat (CBLen a) => GetterC a -> Getter a+bzToFp (BZ.ParserT p) =+ (FP.ensure (I# len#) `cut1` eRanOut) >> FP.getPos >>= \(FP.Pos pos) ->+ FP.ParserT $ \fpc _eob s st0 ->+ case p fpc s 0# st0 of+ BZ.OK# st1 a -> FP.OK# st1 a (s `plusAddr#` len#)+ BZ.Err# st1 e ->+ let e' = fmap (mapParseErrorSinglePos (\idx -> FP.Pos (pos - idx))) e+ in FP.Err# st1 e'+ BZ.Fail# st1 -> FP.Fail# st1+ where+ !(I# len#) = cblen @a+ eRanOut = [ "ran out of input while running inner parser"+ , "bytes needed: "<>TBL.fromDec (I# len#) ]+ instance TypeError ENoEmpty => Get Void where get = undefined instance TypeError ENoSum => Get (Either a b) where get = undefined @@ -181,13 +233,10 @@ -- | Parse elements until EOF. Sometimes used at the "top" of binary formats. instance Get a => Get [a] where- get = go+ -- TODO slow, uses reverse. build a DList instead+ get = go [] where- go = do- FP.withOption FP.eof (\() -> pure []) $ do- a <- get- as <- go- pure $ a : as+ go as = FP.branch FP.eof (pure (reverse as)) (get >>= \a -> go (a : as)) -- | Return the rest of the input. --@@ -217,7 +266,7 @@ -- | Parse any 'Prim''. getPrim :: forall a. Prim' a => Getter a-getPrim = getEBase FP.anyPrim (ERanOut (sizeOf (undefined :: a)))+getPrim = FP.anyPrim `FP.cut'` parseError1 ["IDK"] instance Prim' a => Get (ViaPrim a) where get = ViaPrim <$> getPrim @@ -229,7 +278,7 @@ instance (Prim' a, ByteSwap a) => Get (ByteOrdered 'BigEndian a) instance Get (Refined pr (Refined pl a)) => Get (Refined (pl `And` pr) a) where- get = (reallyUnsafeRefine . unrefine @pl . unrefine @pr) <$> get+ get = (unsafeRefine . unrefine @pl . unrefine @pr) <$> get {-
src/Binrep/Get/Error.hs view
@@ -1,92 +1,60 @@--- | Error data type definitions (shared between parsers).+{-# LANGUAGE OverloadedStrings #-} -- for easy error building +-- | Common parser error definitions.+ module Binrep.Get.Error where -import GHC.Generics ( Generic )-import Data.Text ( Text )+import Data.Text.Builder.Linear qualified as TBL+import Data.Text qualified as Text import Numeric.Natural ( Natural )-import Data.Word ( Word8 )-import Data.ByteString ( ByteString ) --- | Structured parse error.-data E- = E Int EMiddle-- -- | Unhandled parse error.- --- -- You get this if you don't change a flatparse fail to an error.- --- -- Should not be set except by library code.- | EFail-- deriving stock (Eq, Show, Generic)--data EMiddle-- -- | Parse error with no further context.- = EBase EBase-- -- | Somehow, we got two parse errors.- --- -- I have a feeling that seeing this indicates a problem in your code.- | EAnd E EBase-- -- | Parse error decorated with generic info.- --- -- Should not be set except by library code.- | EGeneric String {- ^ data type name -} (EGeneric E)-- deriving stock (Eq, Show, Generic)--data EBase- = EExpectedByte Word8 Word8- -- ^ expected first, got second-- | EOverlong Int Int- -- ^ expected first, got second-- | EExpected ByteString ByteString- -- ^ expected first, got second-- | EFailNamed String- -- ^ known fail-- | EFailParse String ByteString Word8- -- ^ parse fail (where you parse a larger object, then a smaller one in it)+-- | Top-level parse error.+--+-- The final element is the concrete error. Prior elements should "contain" the+-- error (i.e. be the larger part that the error occurred in).+--+-- Really should be non-empty-- but by using List, we can use the empty list for+-- Fail. Bit of a cute cheat.+type ParseError pos text = [ParseErrorSingle pos text] - | ERanOut Int- -- ^ ran out of input, needed precisely @n@ bytes for this part (n > 0)- --- -- Actually a 'Natural', but we use 'Int' because that's what flatparse uses- -- internally.+-- | A single indexed parse error.+data ParseErrorSingle pos text = ParseErrorSingle+ { parseErrorSinglePos :: pos+ , parseErrorSingleText :: [text]+ } deriving stock Show - deriving stock (Eq, Show, Generic)+-- | Map over the @pos@ index type of a 'ParseErrorSingle'.+mapParseErrorSinglePos+ :: (pos1 -> pos2)+ -> ParseErrorSingle pos1 text+ -> ParseErrorSingle pos2 text+mapParseErrorSinglePos f (ParseErrorSingle pos text) =+ ParseErrorSingle (f pos) text --- | A generic context layer for a parse error of type @e@.------ Recursive: parse errors occurring in fields are wrapped up here. (Those--- errors may also have a generic context layer.)------ Making this explicitly recursive may seem strange, but it clarifies that this--- data type is to be seen as a layer over a top-level type.-data EGeneric e- -- | Parse error relating to sum types (constructors).- = EGenericSum (EGenericSum e)+-- | Shorthand for one parse error.+parseError1 :: [text] -> pos -> ParseError pos text+parseError1 texts pos = [ParseErrorSingle pos texts] - -- | Parse error in a constructor field.- | EGenericField- String -- ^ constructor name- (Maybe String) -- ^ field record name (if present)- Natural -- ^ field index in constructor- e -- ^ field parse error- deriving stock (Eq, Show, Generic)+-- | Construct a parse error message for a generic field failure.+parseErrorTextGenericFieldBld+ :: String -> String -> Maybe String -> Natural+ -> [TBL.Builder]+parseErrorTextGenericFieldBld dtName cstrName (Just fieldName) _fieldIdx =+ [ "in " <> TBL.fromText (Text.pack dtName)+ <> "." <> TBL.fromText (Text.pack cstrName)+ <> "." <> TBL.fromText (Text.pack fieldName) ]+parseErrorTextGenericFieldBld dtName cstrName Nothing fieldIdx =+ [ "in " <> TBL.fromText (Text.pack dtName)+ <> "." <> TBL.fromText (Text.pack cstrName)+ <> "." <> TBL.fromUnboundedDec fieldIdx ] -data EGenericSum e- -- | Parse error parsing prefix tag.- = EGenericSumTag e+-- | Construct a parse error message for a generic sum tag no-match.+parseErrorTextGenericNoCstrMatchBld :: String -> [TBL.Builder]+parseErrorTextGenericNoCstrMatchBld dtName =+ [ "sum tag did not match any constructors in "+ <> TBL.fromText (Text.pack dtName) ] - -- | Unable to match a constructor to the parsed prefix tag.- | EGenericSumTagNoMatch- [String] -- ^ constructors tested- Text -- ^ prettified prefix tag- deriving stock (Eq, Show, Generic)+-- | Construct a parse error message for a generic sum tag parse error.+parseErrorTextGenericSumTagBld :: String -> [TBL.Builder]+parseErrorTextGenericSumTagBld dtName =+ [ "while parsing sum tag in " <> TBL.fromText (Text.pack dtName) ]
src/Binrep/Get/Struct.hs view
@@ -1,8 +1,15 @@ {-# LANGUAGE UndecidableInstances #-} -- for Generically instance+{-# LANGUAGE OverloadedStrings #-} -- for easy error building -module Binrep.Get.Struct where+module Binrep.Get.Struct+ ( GetterC, GetC(getC)+ , getGenericStruct+ , runGetCBs+ , unsafeRunGetCPtr+ ) where import Binrep.Get.Error+import Data.Text.Builder.Linear qualified as TBL import Bytezap.Parser.Struct import Bytezap.Parser.Struct.Generic import Binrep.CBLen@@ -27,46 +34,67 @@ import Binrep.Common.Via.Generically.NonSum -import Refined-import Refined.Unsafe+import Rerefined.Refine+import Rerefined.Predicate.Logical.And -type GetterC = Parser E+type GetterC = Parser (ParseError Int TBL.Builder) -- | constant size parser class GetC a where getC :: GetterC a +-- | Consume 'Result'.+finishGetterC+ :: Result (ParseError Int TBL.Builder) a+ -> Either (ParseError Int TBL.Builder) a+finishGetterC = \case+ OK a -> Right a+ Err e -> Left e+ Fail -> Left []+ runGetCBs :: forall a. (GetC a, KnownNat (CBLen a))- => B.ByteString -> Either E a+ => B.ByteString -> Either (ParseError Int TBL.Builder) a runGetCBs bs =- if cblen @a <= B.length bs- then unsafeRunGetC' unsafeRunParserBs bs- else Left $ E 0 $ EBase $ ERanOut 0 -- TODO made up numbers---- | doesn't check len-unsafeRunGetC'- :: forall a buf. GetC a- => (forall e. buf -> Parser e a -> Result e a)- -> buf -> Either E a-unsafeRunGetC' p buf =- case p buf getC of- OK a -> Right a- Fail -> Left EFail- Err e -> Left e+ if lenReq <= lenAvail+ then finishGetterC $ unsafeRunParserBs bs getC+ else Left [ParseErrorSingle 0 [errMsg]]+ where+ lenReq = cblen @a+ lenAvail = B.length bs+ errMsg =+ "input too short (need "<>TBL.fromDec lenReq+ <>", got "<>TBL.fromDec lenAvail<>")" -- | doesn't check len unsafeRunGetCPtr :: forall a. GetC a- => Ptr Word8 -> Either E a-unsafeRunGetCPtr = unsafeRunGetC' unsafeRunParserPtr+ => Ptr Word8 -> Either (ParseError Int TBL.Builder) a+unsafeRunGetCPtr ptr = finishGetterC $ unsafeRunParserPtr ptr getC instance GParseBase GetC where type GParseBaseSt GetC = Proxy# Void type GParseBaseC GetC a = GetC a- type GParseBaseE GetC = E- gParseBase = getC+ type GParseBaseE GetC = ParseError Int TBL.Builder+ gParseBase dtName cstrName mFieldName fieldIdx = getC `cutting1` e+ where+ e = parseErrorTextGenericFieldBld dtName cstrName mFieldName fieldIdx type GParseBaseLenTF GetC = CBLenSym +-- | Turn a 'Fail' into a single error, or prepend it to any existing ones.+--+-- Use when wrapping other 'get'ters.+--+-- We reimplement @cutting@ with a tweak. Otherwise, we'd have to join lists in+-- the error case (instead of simply prepending).+cutting1+ :: ParserT st (ParseError Int text) a -> [text]+ -> ParserT st (ParseError Int text) a+cutting1 (ParserT p) texts = ParserT $ \fpc base# os# st ->+ case p fpc base# os# st of+ Fail# st' -> Err# st' [ParseErrorSingle (I# os#) texts]+ Err# st' e' -> Err# st' (ParseErrorSingle (I# os#) texts : e')+ x -> x+ -- | Serialize a term of the struct-like type @a@ via its 'Generic' instance. getGenericStruct :: forall a@@ -89,7 +117,7 @@ instance GetC (Refined pr (Refined pl a)) => GetC (Refined (pl `And` pr) a) where- getC = (reallyUnsafeRefine . unrefine @pl . unrefine @pr) <$> getC+ getC = (unsafeRefine . unrefine @pl . unrefine @pr) <$> getC instance GetC () where {-# INLINE getC #-}@@ -128,14 +156,3 @@ putC (l, r) = sequencePokes (putC l) (cblen @l) (putC r) -}--eCBase :: EBase -> GetterC a-eCBase eb = ParserT $ \_fpc _base os# st ->- Err# st (E (I# os#) $ EBase eb)--getECBase :: GetterC a -> EBase -> GetterC a-getECBase (ParserT p) eb = ParserT $ \fpc base os# st0 ->- case p fpc base os# st0 of- Fail# st1 -> Err# st1 (E (I# os#) $ EBase eb)- Err# st1 e -> Err# st1 (E (I# os#) $ EAnd e eb)- x -> x
src/Binrep/Put.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE UndecidableInstances #-} -- required below GHC 9.6+{-# LANGUAGE UndecidableInstances #-} -- for various stuff+{-# LANGUAGE AllowAmbiguousTypes #-} -- for type-level sum type handling module Binrep.Put where @@ -17,14 +18,15 @@ import GHC.Generics import Generic.Data.Function.FoldMap+import Generic.Data.MetaParse.Cstr ( Raw, ParseCstrTo ) import Generic.Type.Assert import Control.Monad.ST ( RealWorld ) import Binrep.Put.Struct ( PutC(putC) ) -import Refined-import Refined.Unsafe+import Rerefined.Refine+import Rerefined.Predicate.Logical.And import Data.Word import Data.Int@@ -59,16 +61,21 @@ put = putGenericNonSum . unGenericallyNonSum -- | Serialize a term of the sum type @a@ via its 'Generic' instance.------ You must provide a serializer for @a@'s constructors. This is regrettably--- inefficient due to having to use 'String's. Alas. Do write your own instance--- if you want better performance! putGenericSum+ :: forall sumtag a+ . ( Generic a, GFoldMapSum Put sumtag (Rep a)+ , GAssertNotVoid a, GAssertSum a+ ) => ParseCstrTo sumtag Putter -> a -> Putter+putGenericSum = genericFoldMapSum @Put @sumtag++-- | Serialize a term of the sum type @a@ via its 'Generic' instance, without+-- pre-parsing constructor names.+putGenericSumRaw :: forall a- . ( Generic a, GFoldMapSum Put (Rep a)+ . ( Generic a, GFoldMapSum Put Raw (Rep a) , GAssertNotVoid a, GAssertSum a ) => (String -> Putter) -> a -> Putter-putGenericSum = genericFoldMapSum @Put+putGenericSumRaw = genericFoldMapSumRaw @Put newtype ViaPutC a = ViaPutC { unViaPutC :: a } instance (PutC a, KnownNat (CBLen a)) => Put (ViaPutC a) where@@ -129,4 +136,4 @@ -- | Put types refined with multiple predicates by wrapping the left -- predicate with the right. LOL REALLY? instance Put (Refined pr (Refined pl a)) => Put (Refined (pl `And` pr) a) where- put = put . reallyUnsafeRefine @_ @pr . reallyUnsafeRefine @_ @pl . unrefine+ put = put . unsafeRefine @_ @pr . unsafeRefine @_ @pl . unrefine
src/Binrep/Put/Struct.hs view
@@ -26,8 +26,8 @@ import Binrep.Common.Via.Generically.NonSum -import Refined-import Refined.Unsafe+import Rerefined.Refine+import Rerefined.Predicate.Logical.And type PutterC = Struct.Poke RealWorld @@ -65,8 +65,7 @@ instance PutC (Refined pr (Refined pl a)) => PutC (Refined (pl `And` pr) a) where- putC =- putC . reallyUnsafeRefine @_ @pr . reallyUnsafeRefine @_ @pl . unrefine+ putC = putC . unsafeRefine @_ @pr . unsafeRefine @_ @pl . unrefine instance Prim' a => PutC (ViaPrim a) where putC = Struct.prim . unViaPrim
− src/Binrep/Test.hs
@@ -1,26 +0,0 @@-{-# LANGUAGE UndecidableInstances #-} -- for CBLen instances--module Binrep.Test where--import Binrep-import Binrep.Type.Magic-import GHC.Generics ( Generic )-import Data.Word-import Binrep.Util.ByteOrder--import Binrep.Common.Via.Generically.NonSum--data DMagic = DMagic- { dMagic1_8b :: Magic '[0xFF, 0, 1, 0, 1, 0, 1, 0xFF]- } deriving stock Generic- deriving (IsCBLen, PutC) via GenericallyNonSum DMagic--data DMagicSum = DMagicSum1 (Magic '[0]) | DMagicSum2 (Magic '[0xFF])- deriving stock Generic--data DStruct = DStruct- { dStruct1 :: Magic '[0xFF, 0, 1, 0xFF]- , dStruct2 :: ByteOrdered LE Word32- , dStruct3 :: ()- } deriving stock (Generic, Show)- deriving (IsCBLen, PutC, GetC) via GenericallyNonSum DStruct
+ src/Binrep/Type/AsciiNat.hs view
@@ -0,0 +1,257 @@+{-| Naturals represented via ASCII digits.++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. Pretty silly.++As with other binrep string-likes, you probably want to wrap this with+'Binrep.Type.Sized.Sized' or 'Binrep.Type.Prefix.Size.SizePrefixed'.++We use a refinement to permit using any numeric type, while ensuring that+negative values are not permitted.+-}++{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE OverloadedStrings #-} -- for refined error+{-# LANGUAGE UndecidableInstances #-} -- for deriving predicate instance++module Binrep.Type.AsciiNat where++import Binrep++import GHC.Exts ( Word(W#), Word#, Int(I#), word2Int#, eqWord#, plusWord# )+import Util.TypeNats ( natValWord )+import Data.Semigroup ( sconcat )++import GHC.Num.Primitives ( wordLogBase# )+import GHC.Num.Natural ( naturalSizeInBase# )++import Data.Word+import Data.Int+import Data.List.NonEmpty ( NonEmpty( (:|) ) )++import GHC.TypeNats ( Natural, KnownNat )++import Data.ByteString qualified as B+import Binrep.Type.Thin ( Thin(Thin) )++import Rerefined.Predicate+import Rerefined.Predicate.Via+import Rerefined.Predicate.Relational.Value+import Rerefined.Predicate.Relational+import Rerefined.Refine+import TypeLevelShow.Natural+import TypeLevelShow.Utils++import Data.Text.Builder.Linear qualified as TBL++-- | A natural represented in binary as an ASCII string, where each character is+-- a digit in the given base.+--+-- Only certain bases are supported: 2, 8, 10 and 16.+--+-- Hex parsing permits mixed case digits when parsing (@1-9a-fA-F@), and+-- serializes with lower-case ASCII hex digits.+data AsciiNat (base :: Natural)+--type AsciiNat base = Refined (AsciiNat base)++instance Predicate (AsciiNat base) where+ type PredicateName d (AsciiNat base) = ShowParen (d > 9)+ ("AsciiNat " ++ ShowNatDec base)++instance (KnownPredicateName (AsciiNat base), Num a, Ord a)+ => Refine (AsciiNat base) a where+ validate = validateVia @(CompareValue GTE Pos 0)++-- | Compare two 'AsciiNat's, ignoring base information.+asciiNatCompare+ :: Ord a => Refined (AsciiNat bl) a -> Refined (AsciiNat br) a -> Ordering+asciiNatCompare l r = compare (unrefine l) (unrefine r)++-- | The bytelength of an 'AsciiNat' is the number of digits in the number in+-- the given base. We can calculate this generally with great efficiency+-- using GHC (ghc-bignum) primitives!+instance (HasBaseOps a, KnownNat base) => BLen (Refined (AsciiNat base) a) where+ blen n = I# (word2Int# (sizeInBase# base# (unrefine n)))+ where+ !(W# base#) = natValWord @base++class HasBaseOps a where+ -- | See ghc-bignum internals at @GHC.Num.*@.+ sizeInBase# :: Word# -> a -> Word#++instance HasBaseOps Word where sizeInBase# = sizeInBaseWordSize+instance HasBaseOps Natural where+ sizeInBase# base = \case+ 0 -> 1##+ a -> naturalSizeInBase# base a++instance HasBaseOps Word8 where sizeInBase# = sizeInBaseWordSize+instance HasBaseOps Word16 where sizeInBase# = sizeInBaseWordSize+instance HasBaseOps Word32 where sizeInBase# = sizeInBaseWordSize++-- | TODO unsafe for 32-bit platform+instance HasBaseOps Word64 where sizeInBase# = sizeInBaseWordSize++instance HasBaseOps Int8 where sizeInBase# = sizeInBaseWordSize+instance HasBaseOps Int16 where sizeInBase# = sizeInBaseWordSize+instance HasBaseOps Int32 where sizeInBase# = sizeInBaseWordSize++-- | TODO unsafe for 32-bit platform+instance HasBaseOps Int64 where sizeInBase# = sizeInBaseWordSize++-- | 'Int' can use 'Word' size (but TODO what happens for negatives?)+instance HasBaseOps Int where sizeInBase# = sizeInBaseWordSize++-- | Safe for types smaller than a 'Word'.+--+-- Uses ghc-bignum internals. Slightly unwrapped for better performance.+--+-- One could perhaps write faster algorithms for smaller primitive types too...+-- but performance increase would be minimal if even present.+sizeInBaseWordSize :: Integral a => Word# -> a -> Word#+sizeInBaseWordSize base a =+ case w# `eqWord#` 0## of+ 1# -> 1##+ _ -> 1## `plusWord#` wordLogBase# base w#+ where+ !(W# w#) = fromIntegral a++-- | Serialize any term of an 'Integral' type to binary (base 2) ASCII.+instance Integral a => Put (Refined (AsciiNat 2) a) where+ put = sconcat . fmap (put . (+) 0x30) . unsafeDigits @Word8 2 . unrefine++-- | Serialize any term of an 'Integral' type to octal (base 8) ASCII.+instance Integral a => Put (Refined (AsciiNat 8) a) where+ put = sconcat . fmap (put . (+) 0x30) . unsafeDigits @Word8 8 . unrefine++-- | Serialize any term of an 'Integral' type to decimal (base 10) ASCII.+instance Integral a => Put (Refined (AsciiNat 10) a) where+ put = sconcat . fmap (put . (+) 0x30) . unsafeDigits @Word8 10 . unrefine++-- | Serialize any term of an 'Integral' type to hex (base 16) ASCII.+--+-- Uses lower-case ASCII.+instance Integral a => Put (Refined (AsciiNat 16) a) where+ put =+ sconcat . fmap (put . unsafeHexDigitToAsciiLower)+ . unsafeDigits @Word8 16 . unrefine++-- | Parse a binary (base 2) ASCII natural to any 'Num' type.+instance (Num a, Ord a) => Get (Refined (AsciiNat 2) a) where+ get = unsafeRefine <$> getAsciiNatByByte 2 "binary" parseBinaryAsciiDigit++-- | Parse an octal (base 8) ASCII natural to any 'Num' type.+instance (Num a, Ord a) => Get (Refined (AsciiNat 8) a) where+ get = unsafeRefine <$> getAsciiNatByByte 8 "octal" parseOctalAsciiDigit++-- | Parse a decimal (base 10) ASCII natural to any 'Num' type.+instance (Num a, Ord a) => Get (Refined (AsciiNat 10) a) where+ get = unsafeRefine <$> getAsciiNatByByte 10 "decimal" parseDecimalAsciiDigit++-- | Parse a hex (base 16) ASCII natural to any 'Num' type.+--+-- Parses lower and upper case (mixed permitted).+instance (Num a, Ord a) => Get (Refined (AsciiNat 16) a) where+ get = unsafeRefine <$> getAsciiNatByByte 16 "hex" parseHexAsciiDigit++-- | Parse an ASCII natural in the given base with the given digit parser.+--+-- Parses byte-by-byte. As such, it only supports bases up to 256.+getAsciiNatByByte :: Num a => a -> TBL.Builder -> (a -> Maybe a) -> Getter a+getAsciiNatByByte base baseStr f = do+ Thin bs <- get -- no need to copy since we consume during parsing!+ if B.null bs+ then err1 ["ASCII natural cannot be empty"]+ else case asciiBytesToNat f base bs of+ Left b -> err1 [+ "non-"<>baseStr<>" ASCII digit in "+ <>baseStr<>" ASCII natural: "<>TBL.fromDec b]+ Right n -> pure n++{- | Get the digits in the given number as rendered in the given base.++Digits will be between 0-base. The return type must be sized to support this.++Base must be > 2. This is not checked. (Internal function eh.)++Note the 'NonEmpty' return type. Returns @[0]@ for 0 input. (This does not match+ghc-bignum's @sizeInBase@ primitives!)+-}+unsafeDigits :: forall b a. (Integral a, Integral b) => a -> a -> NonEmpty b+unsafeDigits 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++asciiBytesToNat+ :: Num a => (a -> Maybe a) -> a -> B.ByteString -> Either Word8 a+asciiBytesToNat f base bs =+ -- we use Int for exponent because it seems most sensible & gets SPECIALISEd+ case B.foldr go (Right (0, (0 :: Int))) bs of+ Left w -> Left w+ Right (n, _) -> Right n+ where+ go _ (Left w) = Left w+ go w (Right (n, expo)) =+ case f (fromIntegral w) of+ Nothing -> Left w+ Just d -> Right (n + d * base^expo, expo+1)++parseBinaryAsciiDigit :: (Num a, Ord a) => a -> Maybe a+parseBinaryAsciiDigit = \case+ 0x30 -> Just 0 -- 0+ 0x31 -> Just 1 -- 1+ _ -> Nothing++parseOctalAsciiDigit :: (Num a, Ord a) => a -> Maybe a+parseOctalAsciiDigit a+ | a >= 0x30 && a <= 0x37 = Just $ a - 0x30 -- 0-7+ | otherwise = Nothing++parseDecimalAsciiDigit :: (Num a, Ord a) => a -> Maybe a+parseDecimalAsciiDigit a+ | a >= 0x30 && a <= 0x39 = Just $ a - 0x30 -- 0-9+ | otherwise = Nothing++parseHexAsciiDigit :: (Num a, Ord a) => a -> Maybe a+parseHexAsciiDigit a+ | a >= 0x30 && a <= 0x39 = Just $ a - 0x30 -- 0-9+ | a >= 0x41 && a <= 0x46 = Just $ a - 0x37 -- A-F (upper case)+ | a >= 0x61 && a <= 0x66 = Just $ a - 0x57 -- a-f (lower case)+ | otherwise = Nothing++-- | May only be called with 0<=n<=15.+unsafeHexDigitToAsciiLower :: (Num a, Ord a) => a -> a+unsafeHexDigitToAsciiLower a+ | a <= 9 = 0x30 + a+ | otherwise = 0x57 + a++{-++-- | Print a binary (base 2) ASCII natural with an @0b@ prefix.+prettyAsciiNat2 :: Integral a => Int -> a -> ShowS+prettyAsciiNat2 _ n = showString "0b" . showBin n++-- | Show binary (base 2) ASCII naturals with an @0b@ prefix.+instance Integral a => Show (AsciiNat 2 a) where+ showsPrec _ n = showString "0b" . showBin (unAsciiNat n)++-- | Show octal (base 8) ASCII naturals with an @0o@ prefix.+instance Integral a => Show (AsciiNat 8 a) where+ showsPrec _ n = showString "0o" . showOct (unAsciiNat n)++-- | Show decimal (base 10) ASCII naturals with no prefix.+instance Integral a => Show (AsciiNat 10 a) where+ showsPrec _ = showInt . unAsciiNat++-- | Show hex (base 16) ASCII naturals with an @0x@ prefix.+instance Integral a => Show (AsciiNat 16 a) where+ showsPrec _ n = showString "0x" . showHex (unAsciiNat n)++-}
src/Binrep/Type/Derived/NullTermPadded.hs view
@@ -10,7 +10,8 @@ import Binrep.Type.NullTerminated import Binrep.Type.NullPadded -import Refined+import Rerefined.Predicate.Logical.And+import Rerefined.Refine ( Refined ) -- | Predicate for null-terminated, then null-padded data. type NullTermPad n = NullTerminate `And` NullPad n
src/Binrep/Type/Magic.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE UndecidableInstances #-} -- for weirder type families+{-# LANGUAGE UndecidableInstances #-} -- for tons of stuff+{-# LANGUAGE PatternSynonyms #-} -- TODO wip+{-# LANGUAGE OverloadedStrings #-} -- for easy error building {- | Magic numbers (also just magic): short constant bytestrings usually found at the top of a file, often used as an early sanity check.@@ -8,8 +10,8 @@ * byte magics e.g. Zstandard: @28 B5 2F FD@ * printable magics e.g. Ogg: @4F 67 67 53@ -> @OggS@ (in ASCII) -For byte magics, use type-level 'Natural' lists.-For printable magics, use 'Symbol's (type-level strings).+For byte magics, use type-level 'Natural' lists e.g. @'Magic' \@'[0xFF, 0x01]@+For printable (UTF-8) magics, use 'Symbol's e.g. @'Magic' \@"hello"@. -} module Binrep.Type.Magic@@ -20,7 +22,6 @@ import Data.Type.Symbol.Utf8 ( type SymbolToUtf8 ) -import Util.TypeNats ( natValInt ) import GHC.TypeLits ( type Natural, type Symbol, type KnownNat, type (+) ) import GHC.Generics ( Generic )@@ -32,80 +33,71 @@ import Bytezap.Parser.Struct.TypeLits.Bytes ( ParseReifyBytesW64(parseReifyBytesW64) ) import Bytezap.Parser.Struct qualified as BZ-import Data.ByteString.Internal qualified as B-import GHC.Exts ( Int(I#), plusAddr#, Ptr(Ptr) )-import Foreign.Marshal.Utils ( copyBytes )+import GHC.Exts ( Int(I#) ) import FlatParse.Basic qualified as FP+import Data.Text.Builder.Linear qualified as TBL --- | A singleton data type representing a "magic number" via a phantom type.------ The phantom type variable unambiguously defines a constant bytestring.--- A handful of types are supported for using magics conveniently, e.g. for pure--- ASCII magics, you may use a 'Symbol' type-level string.-data Magic (a :: k) = Magic deriving stock (Generic, Data, Show, Eq)+{- | A unit data type representing a "magic number" via a phantom type. --- | Weaken a @'Magic' a@ to the unit.+The phantom type unambiguously defines a bytestring at compile time. This+depends on the type's kind. See 'MagicBytes' for details.++This is defined using GADT syntax to permit labelling the phantom type kind as+/inferred/, which effectively means hidden (not available for visible type+applications). That kind is always evident from the type, so it's just nicer.+-}+data Magic a where Magic :: forall {k} (a :: k). Magic a+ deriving stock (Generic, Data, Show, Eq)++-- | Weaken a @'Magic' a@ to the unit '()'. instance Weaken (Magic a) where type Weak (Magic a) = () weaken Magic = () --- | Strengthen the unit to some @'Magic' a@.-instance Strengthen (Magic a) where strengthen () = pure Magic+-- | Strengthen the unit '()' to some @'Magic' a@.+instance Strengthen (Magic a) where strengthen () = Right Magic -- | The byte length of a magic is known at compile time. instance IsCBLen (Magic a) where type CBLen (Magic a) = Length (MagicBytes a) --- | The byte length of a magic is obtained via reifying. deriving via ViaCBLen (Magic a) instance KnownNat (Length (MagicBytes a)) => BLen (Magic a) +-- | Efficiently serialize a @'Magic' a@. instance (bs ~ MagicBytes a, ReifyBytesW64 bs) => PutC (Magic a) where putC Magic = reifyBytesW64 @bs deriving via (ViaPutC (Magic a)) instance (bs ~ MagicBytes a, ReifyBytesW64 bs, KnownNat (Length bs)) => Put (Magic a) -{- this works, but is ugly.-* we have to duplicate our error wrapping because errors use parser internals-* we throw the magic into the error, so we need the serializer constraints too-I mean, it's fine. It's correct. It's as fast as possible. But it looks bad :<--}-instance- ( bs ~ MagicBytes a, ParseReifyBytesW64 bs- , ReifyBytesW64 bs, KnownNat (Length bs)- ) => GetC (Magic a) where- getC = BZ.ParserT $ \fpc base os# st0 ->- case BZ.runParserT# (parseReifyBytesW64 @bs) fpc base os# st0 of- BZ.OK# st1 () -> BZ.OK# st1 Magic- BZ.Fail# st1 ->- let bsActual = B.unsafeCreate len (\buf -> copyBytes buf (Ptr (base `plusAddr#` os#)) len)- eb = EExpected bsExpected bsActual- in BZ.Err# st1 (E (I# os#) $ EBase eb)- BZ.Err# st1 e ->- let bsActual = B.unsafeCreate len (\buf -> copyBytes buf (Ptr (base `plusAddr#` os#)) len)- eb = EExpected bsExpected bsActual- in BZ.Err# st1 (E (I# os#) $ EAnd e eb)- where- len = natValInt @(Length bs)- bsExpected = runPutC (Magic :: Magic a)+-- | Efficiently parse a @'Magic' a@. Serialization constraints are included as+-- we emit the expected bytestring in errors.+instance (bs ~ MagicBytes a, ParseReifyBytesW64 0 bs) => GetC (Magic a) where+ getC = BZ.ParserT $ \fpc base# os# st0 ->+ case BZ.runParserT# (parseReifyBytesW64 @0 @bs) fpc base# os# st0 of+ BZ.OK# st1 () -> BZ.OK# st1 Magic+ BZ.Err# st1 (pos, bActual) -> BZ.Err# st1 (parseError1+ ["TODO magic parse error: "<>TBL.fromDec bActual]+ (pos + I# os#))+ BZ.Fail# st1 -> BZ.Fail# st1 -- shouldn't occur deriving via ViaGetC (Magic a) instance- ( bs ~ MagicBytes a, ParseReifyBytesW64 bs+ ( bs ~ MagicBytes a, ParseReifyBytesW64 0 bs , ReifyBytesW64 bs, KnownNat (Length bs) ) => Get (Magic a) -- | Types which define a magic value. class Magical (a :: k) where- -- | How to turn the type into a list of bytes.+ -- | How to turn the type into a list of bytes (stored using 'Natural's). type MagicBytes a :: [Natural] -- | Type-level naturals go as-is. (Make sure you don't go over 255, though!)-instance Magical (ns :: [Natural]) where type MagicBytes ns = ns+instance Magical (bs :: [Natural]) where type MagicBytes bs = bs -- | Type-level symbols are converted to UTF-8. instance Magical (sym :: Symbol) where type MagicBytes sym = SymbolToUtf8 sym -- | The length of a type-level list. type family Length (a :: [k]) :: Natural where- Length '[] = 0 Length (a ': as) = 1 + Length as+ Length '[] = 0
src/Binrep/Type/NullPadded.hs view
@@ -1,6 +1,7 @@ -- | Data null-padded to a given length. -{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE UndecidableInstances #-} -- for PredicateName+{-# LANGUAGE OverloadedStrings #-} -- for refine error builder module Binrep.Type.NullPadded where @@ -11,20 +12,22 @@ import Raehik.Compat.FlatParse.Basic.WithLength qualified as FP import Control.Monad.Combinators ( skipCount ) -import Binrep.Util ( tshow )--import Refined-import Refined.Unsafe+import Rerefined.Predicate.Common+import Rerefined.Refine+import TypeLevelShow.Natural+import TypeLevelShow.Utils+import Data.Text.Builder.Linear qualified as TBL import GHC.TypeNats import Util.TypeNats ( natValInt ) -import Data.Typeable ( typeRep )- import Bytezap.Parser.Struct qualified as BZG import GHC.Exts ( Int(I#) ) data NullPad (n :: Natural)+instance Predicate (NullPad n) where+ type PredicateName d (NullPad n) = ShowParen (d > 9)+ ("NullPad " ++ ShowNatDec n) {- | A type which is to be null-padded to a given total length. @@ -48,12 +51,10 @@ deriving via ViaCBLen (NullPadded n a) instance KnownNat n => BLen (NullPadded n a) -- | Assert that term will fit.-instance (BLen a, KnownNat n) => Predicate (NullPad n) a where- validate p a- | len <= n = success- | otherwise- = throwRefineOtherException (typeRep p) $- "too long: " <> tshow len <> " > " <> tshow n+instance (KnownPredicateName (NullPad n), BLen a, KnownNat n)+ => Refine (NullPad n) a where+ validate p a = validateBool p (len <= n) $+ "too long: " <> TBL.fromDec len <> " > " <> TBL.fromDec n where n = natValInt @n len = blen a@@ -78,7 +79,7 @@ instance (KnownNat n, Get a) => GetC (NullPadded n a) where getC = fpToBz get len# $ \a _unconsumed# -> -- TODO consume nulls lol- BZG.constParse $ reallyUnsafeRefine a+ BZG.constParse $ unsafeRefine a where !(I# len#) = natValInt @n @@ -87,7 +88,6 @@ (a, len) <- FP.parseWithLength get let paddingLen = natValInt @n - len if paddingLen < 0- then eBase $ EFailNamed "TODO used to be EOverlong, cba"- else do- skipCount paddingLen (FP.word8 0x00)- pure $ reallyUnsafeRefine a+ then err1 ["TODO used to be EOverlong, cba"]+ else do skipCount paddingLen (FP.word8 0x00)+ pure $ unsafeRefine a
src/Binrep/Type/NullTerminated.hs view
@@ -13,9 +13,8 @@ import FlatParse.Basic qualified as FP -import Refined-import Refined.Unsafe-import Data.Typeable ( typeRep )+import Rerefined.Predicate.Common+import Rerefined.Refine import Data.ByteString qualified as B import Data.Word ( Word8 )@@ -23,20 +22,18 @@ -- | Null-terminated data. Arbitrary length terminated with a null byte. -- Permits no null bytes inside the data. data NullTerminate++instance Predicate NullTerminate where+ type PredicateName d NullTerminate = "NullTerminate"+ type NullTerminated = Refined NullTerminate -- | Null-terminated data may not contain any null bytes.-instance NullCheck a => Predicate NullTerminate a where- validate p a- | hasNoNulls a = throwRefineOtherException (typeRep p) $+instance Refine NullTerminate B.ByteString where+ -- TODO is there a faster check we can conjure up here...?+ validate p a = validateBool p (not (B.any (== 0x00) a)) $ "null byte not permitted in null-terminated data"- | otherwise = success -class NullCheck a where hasNoNulls :: a -> Bool-instance NullCheck B.ByteString where- {-# INLINE hasNoNulls #-}- hasNoNulls = B.any (== 0x00)- instance BLen a => BLen (NullTerminated a) where blen ra = 1 + blen (unrefine ra) {-# INLINE blen #-}@@ -48,9 +45,16 @@ put a = put (unrefine a) <> put @Word8 0x00 -- | We may parse any null-terminated data using a special flatparse combinator.+--+-- The combinator doesn't permit distinguishing between the two possible+-- failures: either there was no next null, or the inner parser didn't consume+-- up to it. instance Get a => Get (NullTerminated a) where {-# INLINE get #-}- get = reallyUnsafeRefine <$> getEBase (FP.isolateToNextNull get) (EFailNamed "cstring")+ get = unsafeRefine <$> cut1 (FP.isolateToNextNull get) e+ where e = [ "while isolating to next null"+ , "either there was no next null in the input,"+ , "or the inner parser didn't fully consume its input" ] {- I don't know how to do @[a]@. Either I nullterm each element, which is weird
src/Binrep/Type/Prefix/Count.hs view
@@ -3,34 +3,44 @@ module Binrep.Type.Prefix.Count where -import Binrep.Util.Prefix+import Binrep.Type.Prefix.Internal import Binrep import Control.Monad.Combinators qualified as Monad import GHC.TypeNats import Util.TypeNats ( natValInt )-import Refined hiding ( Weaken(..), strengthen )-import Refined.Unsafe ( reallyUnsafeRefine1 ) -import Data.Typeable ( Typeable, typeRep )-import Data.Kind+import Rerefined.Predicate.Common+import Rerefined.Refine+import TypeLevelShow.Utils +import Data.Kind ( type Type )+ import Data.Foldable qualified as Foldable +-- TODO put monofoldable in here, instead of that useless @(f a)@ stuff+ data CountPrefix (pfx :: Type)-type CountPrefixed pfx = Refined1 (CountPrefix pfx) -instance (KnownNat (Max pfx), Foldable f, Typeable pfx)- => Predicate1 (CountPrefix pfx) f where- validate1 p fa- | Foldable.length fa <= natValInt @(Max pfx) = success- | otherwise = throwRefineOtherException (typeRep p) "TODO bad"+instance Predicate (CountPrefix pfx) where+ type PredicateName d (CountPrefix pfx) = ShowParen (d > 9)+ ("CountPrefix " ++ LenNatName pfx) -instance (KnownNat (Max pfx), Foldable f, Typeable pfx)- => Predicate (CountPrefix pfx) (f a) where+instance+ ( KnownPredicateName (CountPrefix pfx), KnownNat (LenNatMax pfx), Foldable f+ ) => Refine1 (CountPrefix pfx) f where+ validate1 p fa =+ validateBool p (Foldable.length fa <= natValInt @(LenNatMax pfx)) $+ "TODO too large for count prefix"++instance+ ( KnownPredicateName (CountPrefix pfx), KnownNat (LenNatMax pfx), Foldable f+ ) => Refine (CountPrefix pfx) (f a) where validate = validate1 --- | We can know byte length at compile time _if_ we know it for the prefix and+type CountPrefixed pfx = Refined1 (CountPrefix pfx)++-- | We can know byte length at compile time /if/ we know it for the prefix and -- the list-like. -- -- This is extremely unlikely, because then what counting are we even@@ -42,22 +52,22 @@ -- (holding the length of the type) plus the length of the type. -- -- Bit confusing. How to explain this? TODO-instance (Prefix pfx, Foldable f, BLen pfx, BLen (f a))+instance (LenNat pfx, Foldable f, BLen pfx, BLen (f a)) => BLen (CountPrefixed pfx f a) where- blen rfa = blen (lenToPfx @pfx (Foldable.length fa)) + blen fa+ blen rfa = blen (lenToNat @pfx (Foldable.length fa)) + blen fa where fa = unrefine1 rfa -instance (Prefix pfx, Foldable f, Put pfx, Put (f a))+instance (LenNat pfx, Foldable f, Put pfx, Put (f a)) => Put (CountPrefixed pfx f a) where- put rfa = put (lenToPfx @pfx (Foldable.length fa)) <> put fa+ put rfa = put (lenToNat @pfx (Foldable.length fa)) <> put fa where fa = unrefine1 rfa class GetCount f where getCount :: Get a => Int -> Getter (f a) instance GetCount [] where getCount n = Monad.count n get -instance (Prefix pfx, GetCount f, Get pfx, Get a)+instance (LenNat pfx, GetCount f, Get pfx, Get a) => Get (CountPrefixed pfx f a) where get = do pfx <- get @pfx- fa <- getCount (pfxToLen pfx)- pure $ reallyUnsafeRefine1 fa+ fa <- getCount (natToLen pfx)+ pure $ unsafeRefine1 fa
+ src/Binrep/Type/Prefix/Internal.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE UndecidableInstances #-} -- for convenient type level arithmetic++module Binrep.Type.Prefix.Internal where++import Binrep.Util.ByteOrder ( ByteOrdered(ByteOrdered) )+import GHC.TypeNats+import GHC.TypeLits ( type Symbol )+import Data.Word+import Data.Kind ( type Type )++-- | Types which can encode natural (positive integer) lengths.+--+-- Types must provide convert to and from 'Int', which is the most common type+-- used for data lengths.+class LenNat a where+ -- | The maximum value the type can encode.+ type LenNatMax a :: Natural++ -- | The name of the type, to display when used as part of a predicate.+ type LenNatName a :: Symbol++ -- | Turn an 'Int' length into an @a@.+ --+ -- It is guaranteed that the 'Int' fits i.e. @<= 'LenNatMax' a@.+ lenToNat :: Int -> a++ -- | Turn an @a@ into an 'Int' length.+ --+ -- Don't worry if @a@ may encode larger numbers than 'Int'. I think other+ -- things will be breaking at that point. Or perhaps it's our responsibility+ -- to emit the runtime error? TODO.+ natToLen :: a -> Int++-- | The unit can only encode 1 value -> lengths of 0 only.+instance LenNat () where+ type LenNatMax () = 0+ type LenNatName () = "()"+ lenToNat = \case+ 0 -> ()+ _ -> error "you lied to refine and broke everything :("+ natToLen () = 0++-- | Byte ordering doesn't change how prefixes work.+deriving via (a :: Type) instance LenNat a => LenNat (ByteOrdered end a)++instance LenNat Word8 where+ type LenNatMax Word8 = 2^8 - 1+ type LenNatName Word8 = "Word8"+ lenToNat = fromIntegral+ natToLen = fromIntegral+instance LenNat Word16 where+ type LenNatMax Word16 = 2^16 - 1+ type LenNatName Word16 = "Word16"+ lenToNat = fromIntegral+ natToLen = fromIntegral+instance LenNat Word32 where+ type LenNatMax Word32 = 2^32 - 1+ type LenNatName Word32 = "Word32"+ lenToNat = fromIntegral+ natToLen = fromIntegral -- TODO check for overflow?+instance LenNat Word64 where+ type LenNatMax Word64 = 2^64 - 1+ type LenNatName Word64 = "Word64"+ lenToNat = fromIntegral+ natToLen = fromIntegral -- TODO check for overflow?
src/Binrep/Type/Prefix/Size.hs view
@@ -3,7 +3,7 @@ module Binrep.Type.Prefix.Size where -import Binrep.Util.Prefix+import Binrep.Type.Prefix.Internal import Binrep.Type.Thin import Binrep import FlatParse.Basic qualified as FP@@ -11,43 +11,48 @@ import GHC.TypeNats import Util.TypeNats ( natValInt ) import Data.ByteString qualified as B-import Refined hiding ( Weaken(..), strengthen )-import Refined.Unsafe -import Data.Typeable ( Typeable, typeRep )-import Data.Kind+import Rerefined.Predicate.Common+import Rerefined.Refine+import TypeLevelShow.Utils +import Data.Kind ( type Type )+ data SizePrefix (pfx :: Type)++instance Predicate (SizePrefix pfx) where+ type PredicateName d (SizePrefix pfx) = ShowParen (d > 9)+ ("SizePrefix " ++ LenNatName pfx)+ type SizePrefixed pfx = Refined (SizePrefix pfx) -instance (KnownNat (Max pfx), BLen a, Typeable pfx)- => Predicate (SizePrefix pfx) a where- validate p a- | blen a <= natValInt @(Max pfx) = Nothing- | otherwise = throwRefineOtherException (typeRep p) $- "thing too big for length prefix type"+instance+ ( KnownPredicateName (SizePrefix pfx), KnownNat (LenNatMax pfx), BLen a+ ) => Refine (SizePrefix pfx) a where+ validate p a = validateBool p (blen a <= natValInt @(LenNatMax pfx)) $+ "thing too big for length prefix type" -- TODO no idea if this is sensible instance IsCBLen (SizePrefixed pfx a) where type CBLen (SizePrefixed pfx a) = CBLen pfx + CBLen a -instance (Prefix pfx, BLen a, BLen pfx)+instance (LenNat pfx, BLen a, BLen pfx) => BLen (SizePrefixed pfx a) where- blen ra = blen (lenToPfx @pfx (blen a)) + blen a+ blen ra = blen (lenToNat @pfx (blen a)) + blen a where a = unrefine ra -instance (Prefix pfx, BLen a, Put pfx, Put a)+instance (LenNat pfx, BLen a, Put pfx, Put a) => Put (SizePrefixed pfx a) where- put ra = put (lenToPfx @pfx (blen a)) <> put a+ put ra = put (lenToNat @pfx (blen a)) <> put a where a = unrefine ra class GetSize a where getSize :: Int -> Getter a instance GetSize B.ByteString where getSize = fmap B.copy . FP.take instance GetSize (Thin B.ByteString) where getSize = fmap Thin . FP.take -instance (Prefix pfx, GetSize a, Get pfx)+instance (LenNat pfx, GetSize a, Get pfx) => Get (SizePrefixed pfx a) where get = do pfx <- get @pfx- a <- getSize (pfxToLen pfx)- pure $ reallyUnsafeRefine a+ a <- getSize (natToLen pfx)+ pure $ unsafeRefine a
src/Binrep/Type/Sized.hs view
@@ -1,31 +1,35 @@ -- | Constant-size data. -{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE UndecidableInstances #-} -- for PredicateName+{-# LANGUAGE OverloadedStrings #-} -- for refine error builder module Binrep.Type.Sized where import Binrep import FlatParse.Basic qualified as FP -import Binrep.Util ( tshow )--import Refined-import Refined.Unsafe-import Data.Typeable ( typeRep )+import Rerefined.Predicate.Common+import Rerefined.Refine+import TypeLevelShow.Natural+import TypeLevelShow.Utils+import Data.Text.Builder.Linear qualified as TBL import GHC.TypeNats import Util.TypeNats ( natValInt ) -- | Essentially runtime reflection of a 'BLen' type to 'CBLen'. data Size (n :: Natural)++instance Predicate (Size n) where+ type PredicateName d (Size n) = ShowParen (d > 9)+ ("Size " ++ ShowNatDec n)+ type Sized n = Refined (Size n) -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+instance (KnownPredicateName (Size n), BLen a, KnownNat n)+ => Refine (Size n) a where+ validate p a = validateBool p (len == n) $+ "not correctly sized: "<>TBL.fromDec len<>" /= "<>TBL.fromDec n where n = natValInt @n len = blen a@@ -42,6 +46,6 @@ instance (Get a, KnownNat n) => Get (Sized n a) where get = do a <- FP.isolate (natValInt @n) get- pure $ reallyUnsafeRefine a+ pure $ unsafeRefine a -- ^ REFINE SAFETY: 'FP.isolate' consumes precisely the number of bytes -- requested when it succeeds
src/Binrep/Type/Text.hs view
@@ -22,7 +22,7 @@ import Binrep.Type.Text.Internal -import Refined+import Rerefined import Binrep.Type.Text.Encoding.Utf8 import Binrep.Type.Text.Encoding.Ascii@@ -47,7 +47,7 @@ -- bs :: Refined 'C Bytes encodeToRep :: forall rep enc- . (Encode enc, Predicate rep Bytes)+ . (Encode enc, Refine rep Bytes) => AsText enc- -> Either RefineException (Refined rep Bytes)+ -> Either RefineFailure (Refined rep Bytes) encodeToRep = refine . encode
src/Binrep/Type/Text/Encoding/Ascii.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module Binrep.Type.Text.Encoding.Ascii where@@ -6,42 +5,27 @@ import Binrep.Type.Text.Internal import Binrep.Type.Text.Encoding.Utf8 -import Refined-import Data.Typeable ( typeRep )+import Rerefined.Predicate.Common+import Rerefined.Refine ( unsafeRefine ) -import Data.Char qualified as Char import Data.Text qualified as Text import Data.Text ( Text ) import Data.Text.Encoding qualified as Text-import Control.Exception qualified-import System.IO.Unsafe qualified -- | 7-bit data Ascii+instance Predicate Ascii where type PredicateName d Ascii = "ASCII" +-- | 'Text' must be validated if you want to permit 7-bit ASCII only.+instance Refine Ascii Text where+ validate p t = validateBool p (Text.isAscii t) "not valid 7-bit ASCII"+ -- | We reuse UTF-8 encoding for ASCII, since it is a subset of UTF-8. instance Encode Ascii where encode' = encode' @Utf8 --- Pre-@text-2.0@, @decodeASCII@ generated a warning and ran @decodeUtf8@.--- TODO can I give some compile time warning about this instance missing on--- below text-2.0?? would be cool-#if MIN_VERSION_text(2,0,0)--- TODO 2023-01-26 raehik: awful UX by text. hopefully safe lol?? works at least-instance Decode Ascii where decode = decodeText id $ catchErrorCall Text.decodeASCII-#endif--catchErrorCall :: (a -> b) -> a -> Either String b-catchErrorCall f a = System.IO.Unsafe.unsafeDupablePerformIO $ do- Control.Exception.try @Control.Exception.ErrorCall (Control.Exception.evaluate (f a)) >>= \case- Right b -> pure $ Right b- Left (Control.Exception.ErrorCallWithLocation msg _) -> pure $ Left msg---- | 'Text' must be validated if you want to permit 7-bit ASCII only.------ TODO there should be a MUCH faster check here in text-2.0. text-short has it,--- text doesn't yet. see: https://github.com/haskell/text/issues/496-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"+instance Decode Ascii where+ decode bs =+ case Text.decodeASCII' bs of+ Just t -> Right $ unsafeRefine t+ Nothing -> Left "not valid 7-bit ASCII"
src/Binrep/Type/Text/Encoding/ShiftJis.hs view
@@ -2,7 +2,7 @@ module Binrep.Type.Text.Encoding.ShiftJis where -import Refined+import Rerefined.Predicate import Data.Text ( Text ) @@ -15,9 +15,10 @@ #endif data ShiftJis+instance Predicate ShiftJis where type PredicateName d ShiftJis = "Shift-JIS" -- | TODO Unsafely assume all 'Text's are valid Shift-JIS.-instance Predicate ShiftJis Text where validate _ _ = success+instance Refine ShiftJis Text where validate _ _ = Nothing #ifdef HAVE_ICU instance Encode ShiftJis where encode' = encodeViaTextICU' "Shift-JIS"
src/Binrep/Type/Text/Encoding/Utf16.hs view
@@ -1,15 +1,19 @@+{-# LANGUAGE UndecidableInstances #-} -- for PredicateName+ module Binrep.Type.Text.Encoding.Utf16 where import Binrep.Type.Text.Internal import Binrep.Util.ByteOrder -import Refined-import Data.Typeable ( Typeable )+import Rerefined.Predicate+import TypeLevelShow.Utils import Data.Text.Encoding qualified as Text import Data.Text ( Text ) data Utf16 (end :: ByteOrder)+instance Predicate (Utf16 end) where+ type PredicateName d (Utf16 end) = "UTF-16" ++ EndianSuffix end instance Encode (Utf16 BE) where encode' = Text.encodeUtf16BE instance Encode (Utf16 LE) where encode' = Text.encodeUtf16LE@@ -18,4 +22,4 @@ instance Decode (Utf16 LE) where decode = decodeText show $ wrapUnsafeDecoder Text.decodeUtf16LE -- | Any 'Text' value is always valid UTF-16.-instance Typeable end => Predicate (Utf16 end) Text where validate _ _ = success+instance Refine (Utf16 end) Text where validate _ _ = Nothing
src/Binrep/Type/Text/Encoding/Utf32.hs view
@@ -1,15 +1,19 @@+{-# LANGUAGE UndecidableInstances #-} -- for PredicateName+ module Binrep.Type.Text.Encoding.Utf32 where import Binrep.Type.Text.Internal import Binrep.Util.ByteOrder -import Refined-import Data.Typeable ( Typeable )+import Rerefined.Predicate+import TypeLevelShow.Utils import Data.Text.Encoding qualified as Text import Data.Text ( Text ) data Utf32 (end :: ByteOrder)+instance Predicate (Utf32 end) where+ type PredicateName d (Utf32 end) = "UTF-32" ++ EndianSuffix end instance Encode (Utf32 BE) where encode' = Text.encodeUtf32BE instance Encode (Utf32 LE) where encode' = Text.encodeUtf32LE@@ -18,4 +22,4 @@ instance Decode (Utf32 LE) where decode = decodeText show $ wrapUnsafeDecoder Text.decodeUtf32LE -- | Any 'Text' value is always valid UTF-32.-instance Typeable end => Predicate (Utf32 end) Text where validate _ _ = success+instance Refine (Utf32 end) Text where validate _ _ = Nothing
src/Binrep/Type/Text/Encoding/Utf8.hs view
@@ -2,15 +2,16 @@ import Binrep.Type.Text.Internal -import Refined+import Rerefined.Predicate import Data.Text.Encoding qualified as Text import Data.Text ( Text ) data Utf8+instance Predicate Utf8 where type PredicateName d Utf8 = "UTF-8" instance Encode Utf8 where encode' = Text.encodeUtf8 instance Decode Utf8 where decode = decodeText show Text.decodeUtf8' -- | Any 'Text' value is always valid UTF-8.-instance Predicate Utf8 Text where validate _ _ = success+instance Refine Utf8 Text where validate _ _ = Nothing
src/Binrep/Type/Text/Internal.hs view
@@ -4,8 +4,7 @@ import Data.Text ( Text ) import Data.ByteString qualified as B-import Refined-import Refined.Unsafe ( reallyUnsafeRefine )+import Rerefined.Refine import System.IO.Unsafe qualified import Control.Exception qualified@@ -40,7 +39,7 @@ :: forall enc e . (e -> String) -> (Bytes -> Either e Text) -> Bytes -> Either String (AsText enc)-decodeText g f = bimap g reallyUnsafeRefine . f+decodeText g f = bimap g unsafeRefine . f -- | Run an unsafe decoder safely. --
− src/Binrep/Util.hs
@@ -1,31 +0,0 @@-{-# 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/Binrep/Util/ByteOrder.hs view
@@ -1,14 +1,15 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} module Binrep.Util.ByteOrder- ( ByteOrder(..), ByteOrdered(..)+ ( ByteOrder(..), ByteOrdered(..), type EndianSuffix , type LE, type BE, type Endian ) where import Raehik.Compat.Data.Primitive.Types.Endian ( ByteOrdered(..) ) import GHC.ByteOrder ( ByteOrder(..) ) import Strongweak-import Data.Kind ( Type )+import Data.Kind ( type Type )+import GHC.TypeLits ( type Symbol ) deriving via (a :: Type) instance Weaken a => Weaken (ByteOrdered end a) deriving via (a :: Type) instance Strengthen a => Strengthen (ByteOrdered end a)@@ -17,3 +18,7 @@ type LE = 'LittleEndian type BE = 'BigEndian type Endian = ByteOrdered++type family EndianSuffix (end :: ByteOrder) :: Symbol where+ EndianSuffix 'LittleEndian = "LE"+ EndianSuffix 'BigEndian = "BE"
− src/Binrep/Util/Prefix.hs
@@ -1,62 +0,0 @@-{-# LANGUAGE UndecidableInstances #-} -- for convenient type level arithmetic--module Binrep.Util.Prefix where--import Binrep.Util.ByteOrder ( ByteOrdered(ByteOrdered) )-import GHC.TypeNats-import Data.Word--import Data.Kind---- | Types which may be used as prefixes.------ Generally, these will be integer types.------ Note that this is separate to binary representation, so endianness is--- irrelevant.------ Note that we are also limited by the host architecture's 'Int' type.--- We don't try to work around this, because most types are indexed with 'Int's,--- so I think other things will break before we do.-class Prefix a where- type Max a :: Natural-- -- | used by put. guaranteed that it fits from refined. that is, lenToPfx <=- -- Max.- lenToPfx :: Int -> a-- -- | used by get. better not lie.- pfxToLen :: a -> Int---- | Length prefixing with the unit means a length of 0.------ This is the only sensible case. 1 doesn't work because refining checks @<=@.------ I think there are laws here, where using this is the same as doing nothing at--- all.-instance Prefix () where- type Max () = 0- lenToPfx = \case- 0 -> ()- _ -> error "you lied to refine and broke everything :("- pfxToLen () = 0---- | Byte ordering doesn't change how prefixes work.-deriving via (a :: Type) instance Prefix a => Prefix (ByteOrdered end a)--instance Prefix Word8 where- type Max Word8 = 2^8 - 1- lenToPfx = fromIntegral- pfxToLen = fromIntegral-instance Prefix Word16 where- type Max Word16 = 2^16 - 1- lenToPfx = fromIntegral- pfxToLen = fromIntegral-instance Prefix Word32 where- type Max Word32 = 2^32 - 1- lenToPfx = fromIntegral- pfxToLen = fromIntegral-instance Prefix Word64 where- type Max Word64 = 2^64 - 1- lenToPfx = fromIntegral- pfxToLen = fromIntegral
+ src/Raehik/Compat/FlatParse/Basic/CutWithPos.hs view
@@ -0,0 +1,15 @@+module Raehik.Compat.FlatParse.Basic.CutWithPos where++import FlatParse.Basic ( ParserT, Pos, getPos, cut, err )++-- | Convert a parsing failure to an error, which also receives the parser+-- position (as a 'Pos', from the end of input).+cut' :: ParserT st e a -> (Pos -> e) -> ParserT st e a+cut' p e = getPos >>= \pos -> cut p (e pos)+{-# inline cut' #-}++-- | Throw a parsing error, which also receives the parser position (as a 'Pos',+-- from the end of input).+err' :: (Pos -> e) -> ParserT st e a+err' e = getPos >>= \pos -> err (e pos)+{-# inline err' #-}
src/Util/TypeNats.hs view
@@ -15,3 +15,7 @@ natValInt :: forall n. KnownNat n => Int natValInt = fromIntegral $ natVal'' @n {-# INLINE natValInt #-}++natValWord :: forall n. KnownNat n => Word+natValWord = fromIntegral $ natVal'' @n+{-# INLINE natValWord #-}
+ test/Binrep/GenericSpec.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedStrings #-}++module Binrep.GenericSpec where++import Test.Hspec++spec :: Spec+spec = pure ()+ {-+spec = do+ prop "parse-print roundtrip isomorphism (generic, sum tag via nullterm constructor)" $ do+ \(d :: D) -> runGet (runPut d) `shouldBe` Right (d, "")++--------------------------------------------------------------------------------++type W1 = Word8+type W2LE = ByteOrdered LE Word16+type W8BE = ByteOrdered BE Word64++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++instance BLen D where blen = blenGenericSum $ blen . nullTermCstrPfxTag+instance Put D where put = putGenericSum $ put . nullTermCstrPfxTag+instance Get D where get = getGenericSum $ eqShowPfxTagCfg nullTermCstrPfxTag++data DNoSum = DNoSum Word8 W1 W2LE W8BE+ deriving stock (Generic, Eq, Show)+deriving via (GenericArbitraryU `AndShrinking` DNoSum) instance Arbitrary DNoSum++instance BLen DNoSum where blen = blenGenericNonSum+instance Put DNoSum where put = putGenericNonSum+instance Get DNoSum where get = getGenericNonSum+ -}
− test/Binrep/LawsSpec.hs
@@ -1,54 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Binrep.LawsSpec 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 ( nullTermCstrPfxTag )-import Binrep.Util.ByteOrder-import Data.Word-import Data.ByteString qualified as B-import GHC.Generics ( Generic )--import Generic.Data.Function.Traverse--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 = Word8-type W2LE = ByteOrdered LE Word16-type W8BE = ByteOrdered BE Word64--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--instance BLen D where blen = blenGenericSum $ blen . nullTermCstrPfxTag-instance Put D where put = putGenericSum $ put . nullTermCstrPfxTag-instance Get D where get = getGenericSum $ eqShowPfxTagCfg nullTermCstrPfxTag--data DNoSum = DNoSum Word8 W1 W2LE W8BE- deriving stock (Generic, Eq, Show)-deriving via (GenericArbitraryU `AndShrinking` DNoSum) instance Arbitrary DNoSum--instance BLen DNoSum where blen = blenGenericNonSum-instance Put DNoSum where put = putGenericNonSum-instance Get DNoSum where get = getGenericNonSum
+ test/Binrep/TypesSpec.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE OverloadedStrings #-}++module Binrep.TypesSpec where++import Test.Hspec+import Test.Hspec.QuickCheck+import Test.QuickCheck.Instances.ByteString()++import Binrep+import Data.ByteString qualified as B++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) `shouldSatisfy`+ (\case Right (bs', "") -> bs == bs'; _ -> False)