structured (empty) → 0.1
raw patch · 5 files changed
+705/−0 lines, 5 filesdep +aesondep +arraydep +base
Dependencies added: aeson, array, base, base16-bytestring, binary, bytestring, containers, hashable, nats, scientific, semigroups, tagged, text, time-compat, transformers, unordered-containers, uuid-types, vector
Files
- LICENSE +30/−0
- src/Data/Structured.hs +61/−0
- src/Data/Structured/Internal.hs +487/−0
- src/Data/Structured/MD5.hs +60/−0
- structured.cabal +67/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2019-2020, Oleg Grenrus++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Oleg Grenrus nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ src/Data/Structured.hs view
@@ -0,0 +1,61 @@+-- |+--+-- Copyright: (c) 2019-2020 Oleg Grenrus+--+-- Structurally tag data.+--+-- See @binary-tagged@ package taking use of this.+-- Useful when most 'Binary' instances are 'Generic' derived.+--+-- Say you have a data type+--+-- @+-- data Record = Record+-- { _recordFields :: HM.HashMap Text (Integer, ByteString)+-- , _recordEnabled :: Bool+-- }+-- deriving (Eq, Show, Generic)+--+-- instance Binary Record+-- instance 'Structured' Record+-- @+--+-- then you can serialise and deserialise @Record@ values with a structure tag by simply+--+-- @+-- 'structuredEncode' record :: LBS.ByteString+-- 'structuredDecode' lbs :: Either String Record+-- @+--+-- If structure of @Record@ changes in between, deserialisation will fail early.+--+-- Technically, 'Structured' is not related to 'Binary', and may+-- be useful in other ways.+--+module Data.Structured (+ -- * Structured class+ Structured (structure),+ structureHash,+ structureBuilder,+ genericStructure,+ GStructured,+ nominalStructure,+ containerStructure,+ -- * Structure type+ Structure (..),+ TypeName,+ ConstructorName,+ TypeVersion,+ SopStructure,+ hashStructure,+ typeVersion,+ typeName,+ -- * MD5+ MD5,+ showMD5,+ md5,+ md5FromInteger,+ ) where++import Data.Structured.Internal+import Data.Structured.MD5
+ src/Data/Structured/Internal.hs view
@@ -0,0 +1,487 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+#if __GLASGOW_HASKELL__ >= 711+{-# LANGUAGE PatternSynonyms #-}+#endif+#if __GLASGOW_HASKELL__ >= 800+{-# LANGUAGE TypeInType #-}+#endif+{-# OPTIONS_HADDOCK not-home #-}++module Data.Structured.Internal where++import Data.Structured.MD5++import Data.Int (Int16, Int32, Int64, Int8)+import Data.List.NonEmpty (NonEmpty)+import Data.Proxy (Proxy (..))+import Data.Ratio (Ratio)+import Data.Tagged (Tagged (..), untag)+import Data.Word (Word, Word16, Word32, Word64, Word8)+import Numeric.Natural (Natural)++import qualified Control.Monad.Trans.State.Strict as State++import GHC.Generics++import qualified Data.Aeson as Aeson+import qualified Data.Array.IArray as Array+import qualified Data.Array.Unboxed as Array+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS+import qualified Data.ByteString.Lazy.Builder as Builder+import qualified Data.ByteString.Short as SBS+import qualified Data.Fixed as Fixed+import qualified Data.HashMap.Lazy as HML+import qualified Data.HashSet as HS+import qualified Data.IntMap as IM+import qualified Data.IntSet as IS+import qualified Data.Map as Map+import qualified Data.Monoid as Monoid+import qualified Data.Scientific as Sci+import qualified Data.Semigroup as Semigroup+import qualified Data.Sequence as Seq+import qualified Data.Set as Set+import qualified Data.Text as T+import qualified Data.Text.Lazy as LT+import qualified Data.Time.Compat as Time+import qualified Data.UUID.Types as UUID+import qualified Data.Vector as V+import qualified Data.Vector.Storable as SV+import qualified Data.Vector.Unboxed as UV+import qualified Data.Version as Version++#if __GLASGOW_HASKELL__ >= 800+import Data.Kind (Type)+#else+#define Type *+#endif++import Data.Typeable (TypeRep, Typeable, typeRep)++import Data.Monoid (mconcat)++import qualified Data.Foldable+import qualified Data.Semigroup++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative (pure)+import Data.Traversable (traverse)+#endif++#if !MIN_VERSION_base(4,7,0)+import Data.Typeable (Typeable1, typeOf1)+#endif+++-------------------------------------------------------------------------------+-- Types+-------------------------------------------------------------------------------++type TypeName = String+type ConstructorName = String++-- | A sematic version of a data type. Usually 0.+type TypeVersion = Word32++-- | Structure of a datatype.+--+-- It can be infinite, as far as 'TypeRep's involved are finite.+-- (e.g. polymorphic recursion might cause troubles).+--+data Structure+ = Nominal !TypeRep !TypeVersion TypeName [Structure] -- ^ nominal, yet can be parametrised by other structures.+ | Newtype !TypeRep !TypeVersion TypeName Structure -- ^ a newtype wrapper+ | Structure !TypeRep !TypeVersion TypeName SopStructure -- ^ sum-of-products structure+ deriving (Eq, Ord, Show, Generic)++type SopStructure = [(ConstructorName, [Structure])]++-- | A MD5 hash digest of 'Structure'.+hashStructure :: Structure -> MD5+hashStructure = md5 . LBS.toStrict . Builder.toLazyByteString . structureBuilder++-- | A van-Laarhoven lens into 'TypeVersion' of 'Structure'+--+-- @+-- 'typeVersion' :: Lens' 'Structure' 'TypeVersion'+-- @+typeVersion :: Functor f => (TypeVersion -> f TypeVersion) -> Structure -> f Structure+typeVersion f (Nominal t v n s) = fmap (\v' -> Nominal t v' n s) (f v)+typeVersion f (Newtype t v n s) = fmap (\v' -> Newtype t v' n s) (f v)+typeVersion f (Structure t v n s) = fmap (\v' -> Structure t v' n s) (f v)++-- | A van-Laarhoven lens into 'TypeName' of 'Structure'+--+-- @+-- 'typeName' :: Lens' 'Structure' 'TypeName'+-- @+typeName :: Functor f => (TypeName -> f TypeName) -> Structure -> f Structure+typeName f (Nominal t v n s) = fmap (\n' -> Nominal t v n' s) (f n)+typeName f (Newtype t v n s) = fmap (\n' -> Newtype t v n' s) (f n)+typeName f (Structure t v n s) = fmap (\n' -> Structure t v n' s) (f n)++-------------------------------------------------------------------------------+-- Builder+-------------------------------------------------------------------------------++-- | Flatten 'Structure' into something we can calculate hash of.+--+-- As 'Structure' can be potentially infinite. For mutually recursive types,+-- we keep track of 'TypeRep's, and put just 'TypeRep' name when it's occurred+-- another time.+structureBuilder :: Structure -> Builder.Builder+structureBuilder s0 = State.evalState (go s0) Map.empty where+ go :: Structure -> State.State (Map.Map String (NonEmpty TypeRep)) Builder.Builder+ go (Nominal t v n s) = withTypeRep t $ do+ s' <- traverse go s+ return $ mconcat $ Builder.word8 1 : Builder.word32LE v : Builder.stringUtf8 n : s'++ go (Newtype t v n s) = withTypeRep t $ do+ s' <- go s+ return $ mconcat [Builder.word8 2, Builder.word32LE v, Builder.stringUtf8 n, s']++ go (Structure t v n s) = withTypeRep t $ do+ s' <- goSop s+ return $ mconcat [Builder.word8 3, Builder.word32LE v, Builder.stringUtf8 n, s']++ withTypeRep t k = do+ acc <- State.get+ case insert t acc of+ Nothing -> return $ mconcat [ Builder.word8 0, Builder.stringUtf8 (show t) ]+ Just acc' -> do+ State.put acc'+ k++ goSop :: SopStructure -> State.State (Map.Map String (NonEmpty TypeRep)) Builder.Builder+ goSop sop = do+ parts <- traverse part sop+ return $ mconcat parts++ part (cn, s) = do+ s' <- traverse go s+ return $ Data.Monoid.mconcat [ Builder.stringUtf8 cn, mconcat s' ]++ insert :: TypeRep -> Map.Map String (NonEmpty TypeRep) -> Maybe (Map.Map String (NonEmpty TypeRep))+ insert tr m = case Map.lookup trShown m of+ Nothing -> inserted+ Just ne | tr `Data.Foldable.elem` ne -> Nothing+ | otherwise -> inserted+ where+ inserted = Just (Map.insertWith (Data.Semigroup.<>) trShown (pure tr) m)+ trShown = show tr++-------------------------------------------------------------------------------+-- Classes+-------------------------------------------------------------------------------++-- | Class of types with a known 'Structure'.+--+-- For regular data types 'Structured' can be derived generically.+--+-- @+-- data Record = Record { a :: Int, b :: Bool, c :: [Char] } deriving ('Generic')+-- instance 'Structured' Record+-- @+--+-- @since 3.2.0.0+--+class Typeable a => Structured a where+ structure :: Proxy a -> Structure+ default structure :: (Generic a, GStructured (Rep a)) => Proxy a -> Structure+ structure = genericStructure++ -- This member is hidden. It's there to precalc+ structureHash' :: Tagged a MD5+ structureHash' = Tagged (hashStructure (structure (Proxy :: Proxy a)))++-- | Semantically @'hashStructure' . 'structure'@.+structureHash :: forall a. Structured a => Proxy a -> MD5+structureHash _ = untag (structureHash' :: Tagged a MD5)++-------------------------------------------------------------------------------+-- Smart constructors+-------------------------------------------------------------------------------++-- | Use 'Typeable' to infer name+nominalStructure :: Typeable a => Proxy a -> Structure+nominalStructure p = Nominal tr 0 (show tr) [] where+ tr = typeRep p++#if MIN_VERSION_base(4,7,0)+containerStructure :: forall f a. (Typeable f, Structured a) => Proxy (f a) -> Structure+containerStructure _ = Nominal faTypeRep 0 (show fTypeRep)+ [ structure (Proxy :: Proxy a)+ ]+ where+ fTypeRep = typeRep (Proxy :: Proxy f)+ faTypeRep = typeRep (Proxy :: Proxy (f a))++#else+containerStructure :: forall f a. (Typeable1 f, Structured a) => Proxy (f a) -> Structure+containerStructure _ = Nominal faTypeRep 0 (show fTypeRep)+ [ structure (Proxy :: Proxy a)+ ]+ where+ fTypeRep = typeOf1 (undefined :: f ())+ faTypeRep = typeRep (Proxy :: Proxy (f a))+#endif++-------------------------------------------------------------------------------+-- Generic+-------------------------------------------------------------------------------++-- | Derive 'structure' genrically.+genericStructure :: forall a. (Typeable a, Generic a, GStructured (Rep a)) => Proxy a -> Structure+genericStructure _ = gstructured (typeRep (Proxy :: Proxy a)) (Proxy :: Proxy (Rep a)) 0++-- | Used to implement 'genericStructure'.+class GStructured (f :: Type -> Type) where+ gstructured :: TypeRep -> Proxy f -> TypeVersion -> Structure++instance (i ~ D, Datatype c, GStructuredSum f) => GStructured (M1 i c f) where+ gstructured tr _ v = case sop of+#if MIN_VERSION_base(4,7,0)+ [(_, [s])] | isNewtype p -> Newtype tr v name s+#endif+ _ -> Structure tr v name sop+ where+ p = undefined :: M1 i c f ()+ name = datatypeName p+ sop = gstructuredSum (Proxy :: Proxy f) []++class GStructuredSum (f :: Type -> Type) where+ gstructuredSum :: Proxy f -> SopStructure -> SopStructure++instance (i ~ C, Constructor c, GStructuredProd f) => GStructuredSum (M1 i c f) where+ gstructuredSum _ xs = (name, prod) : xs+ where+ name = conName (undefined :: M1 i c f ())+ prod = gstructuredProd (Proxy :: Proxy f) []++instance (GStructuredSum f, GStructuredSum g) => GStructuredSum (f :+: g) where+ gstructuredSum _ xs+ = gstructuredSum (Proxy :: Proxy f)+ $ gstructuredSum (Proxy :: Proxy g) xs++instance GStructuredSum V1 where+ gstructuredSum _ = id++class GStructuredProd (f :: Type -> Type) where+ gstructuredProd :: Proxy f -> [Structure] -> [Structure]++instance (i ~ S, GStructuredProd f) => GStructuredProd (M1 i c f) where+ gstructuredProd _ = gstructuredProd (Proxy :: Proxy f)++instance Structured c => GStructuredProd (K1 i c) where+ gstructuredProd _ xs = structure (Proxy :: Proxy c) : xs++instance GStructuredProd U1 where+ gstructuredProd _ = id++instance (GStructuredProd f, GStructuredProd g) => GStructuredProd (f :*: g) where+ gstructuredProd _ xs+ = gstructuredProd (Proxy :: Proxy f)+ $ gstructuredProd (Proxy :: Proxy g) xs++-------------------------------------------------------------------------------+-- base+-------------------------------------------------------------------------------++instance Structured ()+instance Structured Bool+instance Structured Ordering++instance Structured Char where structure = nominalStructure++instance (Structured a, Structured b) => Structured (a -> b) where+ structure _ = Nominal+ (typeRep (Proxy :: Proxy (a -> b)))+ 0+ ("(->)")+ [structure (Proxy :: Proxy a), structure (Proxy :: Proxy b)]++instance Structured a => Structured (Maybe a)+instance (Structured a, Structured b) => Structured (Either a b)+instance Structured a => Structured (Ratio a) where structure = containerStructure+instance Structured a => Structured [a] where structure = containerStructure+instance Structured a => Structured (NonEmpty a) where structure = containerStructure++instance (Structured a1, Structured a2) => Structured (a1, a2)+instance (Structured a1, Structured a2, Structured a3) => Structured (a1, a2, a3)+instance (Structured a1, Structured a2, Structured a3, Structured a4) => Structured (a1, a2, a3, a4)+instance (Structured a1, Structured a2, Structured a3, Structured a4, Structured a5) => Structured (a1, a2, a3, a4, a5)+instance (Structured a1, Structured a2, Structured a3, Structured a4, Structured a5, Structured a6) => Structured (a1, a2, a3, a4, a5, a6)+instance (Structured a1, Structured a2, Structured a3, Structured a4, Structured a5, Structured a6, Structured a7) => Structured (a1, a2, a3, a4, a5, a6, a7)++-------------------------------------------------------------------------------+-- base: numbers+-------------------------------------------------------------------------------++instance Structured Int where structure = nominalStructure+instance Structured Integer where structure = nominalStructure++instance Structured Data.Word.Word where structure = nominalStructure++instance Structured Int8 where structure = nominalStructure+instance Structured Int16 where structure = nominalStructure+instance Structured Int32 where structure = nominalStructure+instance Structured Int64 where structure = nominalStructure++instance Structured Word8 where structure = nominalStructure+instance Structured Word16 where structure = nominalStructure+instance Structured Word32 where structure = nominalStructure+instance Structured Word64 where structure = nominalStructure++instance Structured Float where structure = nominalStructure+instance Structured Double where structure = nominalStructure++#if __GLASGOW_HASKELL__ >=810+instance (Typeable k, Typeable (a :: k), Fixed.HasResolution a) => Structured (Fixed.Fixed a) where+#else+instance (Typeable a, Fixed.HasResolution a) => Structured (Fixed.Fixed a) where+#endif+ structure _ = Nominal+ (typeRep (Proxy :: Proxy (Fixed.Fixed a)))+ 0+ ("Fixed " ++ show (Fixed.resolution (Proxy :: Proxy a)))+ []++instance Structured Natural where structure = nominalStructure++-------------------------------------------------------------------------------+-- semigroup+-------------------------------------------------------------------------------++instance Structured a => Structured (Semigroup.Min a)+instance Structured a => Structured (Semigroup.Max a)+instance Structured a => Structured (Semigroup.First a)+instance Structured a => Structured (Semigroup.Last a)+instance Structured a => Structured (Semigroup.WrappedMonoid a)++-------------------------------------------------------------------------------+-- monoid+-------------------------------------------------------------------------------++instance Structured a => Structured (Monoid.First a)+instance Structured a => Structured (Monoid.Last a)+instance Structured a => Structured (Monoid.Sum a)+instance Structured a => Structured (Monoid.Product a)+instance Structured a => Structured (Monoid.Dual a)+instance Structured a => Structured (Monoid.Endo a)+instance Structured Monoid.All+instance Structured Monoid.Any++-------------------------------------------------------------------------------+-- bytestring+-------------------------------------------------------------------------------++instance Structured BS.ByteString where structure = nominalStructure+instance Structured LBS.ByteString where structure = nominalStructure+instance Structured SBS.ShortByteString where structure = nominalStructure++-------------------------------------------------------------------------------+-- text+-------------------------------------------------------------------------------++instance Structured T.Text where structure = nominalStructure+instance Structured LT.Text where structure = nominalStructure++-------------------------------------------------------------------------------+-- containers+-------------------------------------------------------------------------------++instance (Structured k, Structured v) => Structured (Map.Map k v) where structure _ = Nominal (typeRep (Proxy :: Proxy (Map.Map k v))) 0 "Map" [ structure (Proxy :: Proxy k), structure (Proxy :: Proxy v) ]+instance (Structured k) => Structured (Set.Set k) where structure = containerStructure+instance (Structured v) => Structured (IM.IntMap v) where structure = containerStructure+instance Structured IS.IntSet where structure = nominalStructure+instance (Structured v) => Structured (Seq.Seq v) where structure = containerStructure++-------------------------------------------------------------------------------+-- time+-------------------------------------------------------------------------------++instance Structured Time.UTCTime where structure = nominalStructure+instance Structured Time.DiffTime where structure = nominalStructure+instance Structured Time.UniversalTime where structure = nominalStructure+instance Structured Time.NominalDiffTime where structure = nominalStructure+instance Structured Time.Day where structure = nominalStructure+instance Structured Time.TimeZone where structure = nominalStructure+instance Structured Time.TimeOfDay where structure = nominalStructure+instance Structured Time.LocalTime where structure = nominalStructure+instance Structured Time.DayOfWeek where structure = nominalStructure++-------------------------------------------------------------------------------+-- array+-------------------------------------------------------------------------------++instance (Structured i, Structured e) => Structured (Array.Array i e) where+ structure _ = Nominal (typeRep (Proxy :: Proxy (Array.Array i e))) 0 "Array" [ structure (Proxy :: Proxy i), structure (Proxy :: Proxy e) ]++instance (Structured i, Structured e) => Structured (Array.UArray i e) where+ structure _ = Nominal (typeRep (Proxy :: Proxy (Array.UArray i e))) 0 "UArray" [ structure (Proxy :: Proxy i), structure (Proxy :: Proxy e) ]++-------------------------------------------------------------------------------+-- aeson+-------------------------------------------------------------------------------++instance Structured Aeson.Value++-------------------------------------------------------------------------------+-- unordered-containers+-------------------------------------------------------------------------------++instance (Structured k, Structured v) => Structured (HML.HashMap k v) where structure _ = Nominal (typeRep (Proxy :: Proxy (HML.HashMap v))) 0 "HashMap" [ structure (Proxy :: Proxy k), structure (Proxy :: Proxy v) ]+instance (Structured k) => Structured (HS.HashSet k) where structure = containerStructure++-------------------------------------------------------------------------------+-- vector+-------------------------------------------------------------------------------++instance (Structured v) => Structured (V.Vector v) where structure = containerStructure+instance (Structured v) => Structured (SV.Vector v) where structure = containerStructure+instance (Structured v) => Structured (UV.Vector v) where structure = containerStructure++-------------------------------------------------------------------------------+-- scientific+-------------------------------------------------------------------------------++instance Structured Sci.Scientific where structure = nominalStructure++-------------------------------------------------------------------------------+-- uuid-types+-------------------------------------------------------------------------------++instance Structured UUID.UUID where structure = nominalStructure++-------------------------------------------------------------------------------+-- base: version+-------------------------------------------------------------------------------++-- Generic Version is since base-4.9.0.0+instance Structured Version.Version where structure = nominalStructure++-------------------------------------------------------------------------------+-- tagged+-------------------------------------------------------------------------------++#if __GLASGOW_HASKELL__ >= 800+instance (Typeable k, Typeable (b :: k), Structured a) => Structured (Tagged b a)+#else+instance (Typeable (b :: Type), Structured a) => Structured (Tagged b a)+#endif+-- Proxy isn't Typeable in base-4.8 / base++-- #if __GLASGOW_HASKELL__ >= 800+-- instance (Typeable k, Typeable (a :: k)) => Structured (Proxy a)+-- #else+-- instance (Typeable a) => Structured (Proxy a) where+-- structure p = Structure (typeRep p) 0 "Proxy" [("Proxy",[])]+-- #endif
+ src/Data/Structured/MD5.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE Trustworthy #-}+module Data.Structured.MD5 (+ MD5,+ showMD5,+ md5,+ md5FromInteger,+ ) where++import Data.Bits (complement, shiftR, (.&.))+import Foreign.Ptr (castPtr)+import GHC.Fingerprint (Fingerprint (..), fingerprintData)+import Numeric (showHex)+import System.IO.Unsafe (unsafeDupablePerformIO)++import qualified Data.ByteString as BS+import qualified Data.ByteString.Unsafe as BS++type MD5 = Fingerprint++-- | Show 'MD5' in human readable form+--+-- >>> showMD5 (Fingerprint 123 456)+-- "000000000000007b00000000000001c8"+--+-- >>> showMD5 $ md5 $ BS.pack [0..127]+-- "37eff01866ba3f538421b30b7cbefcac"+--+-- @since 3.2.0.0+showMD5 :: MD5 -> String+showMD5 (Fingerprint a b) = pad a' ++ pad b' where+ a' = showHex a ""+ b' = showHex b ""+ pad s = replicate (16 - length s) '0' ++ s++-- | @since 3.2.0.0+md5 :: BS.ByteString -> MD5+md5 bs = unsafeDupablePerformIO $ BS.unsafeUseAsCStringLen bs $ \(ptr, len) ->+ fingerprintData (castPtr ptr) len++-- |+--+-- >>> showMD5 $ md5FromInteger 0x37eff01866ba3f538421b30b7cbefcac+-- "37eff01866ba3f538421b30b7cbefcac"+--+-- Note: the input is truncated:+--+-- >>> showMD5 $ md5FromInteger 0x1230000037eff01866ba3f538421b30b7cbefcac+-- "37eff01866ba3f538421b30b7cbefcac"+--+-- Yet, negative numbers are not a problem...+--+-- >>> showMD5 $ md5FromInteger (-1)+-- "ffffffffffffffffffffffffffffffff"+--+-- @since 3.4.0.0+md5FromInteger :: Integer -> MD5+md5FromInteger i = Fingerprint hi lo where+ mask = complement 0+ lo = mask .&. fromInteger i+ hi = mask .&. fromInteger (i `shiftR` 64)
+ structured.cabal view
@@ -0,0 +1,67 @@+cabal-version: 2.2+name: structured+version: 0.1+synopsis: Structure (hash) of your data types+category: Data+description:+ Calculate the hash of a data structure.+ It can be used as a magic number for the serialization formats.+ See <https://hackage.haskell.org/package/binary-tagged binary-tagged>+ for a @binary@ bindings.++bug-reports: https://github.com/phadej/binary-tagged/issues+author: Oleg Grenrus <oleg.grenrus@iki.fi>+maintainer: Oleg Grenrus <oleg.grenrus@iki.fi>+license: BSD-3-Clause+license-file: LICENSE+build-type: Simple+tested-with:+ GHC ==7.8.4+ || ==7.10.3+ || ==8.0.2+ || ==8.2.2+ || ==8.4.4+ || ==8.6.5+ || ==8.8.3+ || ==8.10.1++source-repository head+ type: git+ location: https://github.com/phadej/binary-tagged+ subdir: structured++library+ default-language: Haskell2010+ hs-source-dirs: src+ ghc-options: -Wall+ exposed-modules: Data.Structured+ exposed-modules: Data.Structured.Internal+ other-modules: Data.Structured.MD5++ -- Libraries bundled with GHC+ build-depends:+ array >=0.5.0.0 && <0.6+ , base >=4.7.0.2 && <4.15+ , binary >=0.7.1.0 && <0.10+ , bytestring >=0.10.4.0 && <0.11+ , containers >=0.5.5.1 && <0.7+ , text >=1.2.3.0 && <1.3+ , time-compat >=1.9.2.2 && <1.10+ , transformers >=0.3.0.0 && <0.6++ -- other dependencies+ build-depends:+ aeson >=0.8 && <1.5+ , base16-bytestring >=0.1.1.6 && <0.2+ , hashable >=1.2 && <1.4+ , scientific >=0.3 && <0.4+ , tagged >=0.7 && <0.9+ , unordered-containers >=0.2 && <0.3+ , uuid-types >=1.0.3 && <1.1+ , vector >=0.10 && <0.13++ if !impl(ghc >=8.0)+ build-depends: semigroups >=0.18.5 && <0.20++ if !impl(ghc >=7.10)+ build-depends: nats >=1.1.2 && <1.2