{- Copyright 2010-2012 Cognimeta Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -} {-# LANGUAGE TemplateHaskell, FlexibleContexts, TypeFamilies, TupleSections, ScopedTypeVariables, FlexibleInstances, UndecidableInstances #-} module Database.Perdure.RootValidator ( RootValidator(..), ValidationDigestWord(..), module Database.Perdure.Validator ) where import Data.Word import Database.Perdure.Digest import Cgm.Data.Maybe import Cgm.Data.Len import Database.Perdure.Validator import Database.Perdure.CSerializer import Database.Perdure.AllocCopy -- ValidationDigest assiciates a particular digest method to each word type to digest (Word32 and Word64) -- It must be a right inverse of DigestWord. -- We'd need a superclass equality constraint here. -- As a first wordaround attempt we place the equality constraint in instances -- Users fail with an infinite type error. -- Read a relevant post: http://www.haskell.org/pipermail/haskell-cafe/2009-January/053696.html -- Actual workaround we used: removed Digest from superclass of ValidationDigestWord, added digest' method which delegates to digest class (AllocCopy w, Deserializable w, LgMultiple w Bool, LgMultiple w Word8, LgMultiple Word64 w, Persistent (ValidationDigest w), Eq (ValidationDigest w), Show (ValidationDigest w)) => ValidationDigestWord w where type ValidationDigest w digest' :: (ImmArray r, PinnedArray r, ArrayElem r ~ w) => r -> ValidationDigest w instance ValidationDigestWord Word32 where type ValidationDigest Word32 = MD5Digest digest' = digest instance ValidationDigestWord Word64 where type ValidationDigest Word64 = Skein512Digest Word128 digest' = digest data RootValidator w = RootValidator deriving (Eq, Show) type Header w = (Len w Word64, ValidationDigest w) instance (ValidationDigestWord w, Show (ValidationDigest w)) => Validator (RootValidator w) where type ValidatedElem (RootValidator w) = w mkValidationInput b = (RootValidator, [serializeToArray persister ((fmap fromIntegral $ arrayLen b, digest' b) :: Header w), b]) validate RootValidator b = let DeserOut ((len, h) :: Header w) u = deserializeFromArray (unsafeSeqDeserializer persister) b payload = headArrayRange (fmap fromIntegral len) $ skipArrayRange (coarsenLen u) b in payload `justIf` (digest' payload == h) instance Persistent (RootValidator w) where persister = structureMap persister deriveStructured ''RootValidator