{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Ouroboros.Consensus.Util.Versioned (
VersionDecoder (..)
, VersionError (..)
, Versioned (..)
, decodeVersion
, decodeVersionWithHook
, decodeVersioned
, encodeVersion
, encodeVersioned
, VersionNumber
) where
import Cardano.Binary (enforceSize)
import qualified Codec.CBOR.Decoding as Dec
import Codec.Serialise (Serialise (..))
import Codec.Serialise.Decoding (Decoder, decodeWord8)
import Codec.Serialise.Encoding (Encoding, encodeListLen, encodeWord8)
import Control.Exception (Exception)
import Data.Word (Word8)
newtype VersionNumber = VersionNumber Word8
deriving newtype (VersionNumber -> VersionNumber -> Bool
(VersionNumber -> VersionNumber -> Bool)
-> (VersionNumber -> VersionNumber -> Bool) -> Eq VersionNumber
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: VersionNumber -> VersionNumber -> Bool
== :: VersionNumber -> VersionNumber -> Bool
$c/= :: VersionNumber -> VersionNumber -> Bool
/= :: VersionNumber -> VersionNumber -> Bool
Eq, Eq VersionNumber
Eq VersionNumber =>
(VersionNumber -> VersionNumber -> Ordering)
-> (VersionNumber -> VersionNumber -> Bool)
-> (VersionNumber -> VersionNumber -> Bool)
-> (VersionNumber -> VersionNumber -> Bool)
-> (VersionNumber -> VersionNumber -> Bool)
-> (VersionNumber -> VersionNumber -> VersionNumber)
-> (VersionNumber -> VersionNumber -> VersionNumber)
-> Ord VersionNumber
VersionNumber -> VersionNumber -> Bool
VersionNumber -> VersionNumber -> Ordering
VersionNumber -> VersionNumber -> VersionNumber
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: VersionNumber -> VersionNumber -> Ordering
compare :: VersionNumber -> VersionNumber -> Ordering
$c< :: VersionNumber -> VersionNumber -> Bool
< :: VersionNumber -> VersionNumber -> Bool
$c<= :: VersionNumber -> VersionNumber -> Bool
<= :: VersionNumber -> VersionNumber -> Bool
$c> :: VersionNumber -> VersionNumber -> Bool
> :: VersionNumber -> VersionNumber -> Bool
$c>= :: VersionNumber -> VersionNumber -> Bool
>= :: VersionNumber -> VersionNumber -> Bool
$cmax :: VersionNumber -> VersionNumber -> VersionNumber
max :: VersionNumber -> VersionNumber -> VersionNumber
$cmin :: VersionNumber -> VersionNumber -> VersionNumber
min :: VersionNumber -> VersionNumber -> VersionNumber
Ord, Integer -> VersionNumber
VersionNumber -> VersionNumber
VersionNumber -> VersionNumber -> VersionNumber
(VersionNumber -> VersionNumber -> VersionNumber)
-> (VersionNumber -> VersionNumber -> VersionNumber)
-> (VersionNumber -> VersionNumber -> VersionNumber)
-> (VersionNumber -> VersionNumber)
-> (VersionNumber -> VersionNumber)
-> (VersionNumber -> VersionNumber)
-> (Integer -> VersionNumber)
-> Num VersionNumber
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
$c+ :: VersionNumber -> VersionNumber -> VersionNumber
+ :: VersionNumber -> VersionNumber -> VersionNumber
$c- :: VersionNumber -> VersionNumber -> VersionNumber
- :: VersionNumber -> VersionNumber -> VersionNumber
$c* :: VersionNumber -> VersionNumber -> VersionNumber
* :: VersionNumber -> VersionNumber -> VersionNumber
$cnegate :: VersionNumber -> VersionNumber
negate :: VersionNumber -> VersionNumber
$cabs :: VersionNumber -> VersionNumber
abs :: VersionNumber -> VersionNumber
$csignum :: VersionNumber -> VersionNumber
signum :: VersionNumber -> VersionNumber
$cfromInteger :: Integer -> VersionNumber
fromInteger :: Integer -> VersionNumber
Num, Int -> VersionNumber -> ShowS
[VersionNumber] -> ShowS
VersionNumber -> String
(Int -> VersionNumber -> ShowS)
-> (VersionNumber -> String)
-> ([VersionNumber] -> ShowS)
-> Show VersionNumber
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> VersionNumber -> ShowS
showsPrec :: Int -> VersionNumber -> ShowS
$cshow :: VersionNumber -> String
show :: VersionNumber -> String
$cshowList :: [VersionNumber] -> ShowS
showList :: [VersionNumber] -> ShowS
Show)
instance Serialise VersionNumber where
encode :: VersionNumber -> Encoding
encode (VersionNumber Word8
w) = Word8 -> Encoding
encodeWord8 Word8
w
decode :: forall s. Decoder s VersionNumber
decode = Word8 -> VersionNumber
VersionNumber (Word8 -> VersionNumber)
-> Decoder s Word8 -> Decoder s VersionNumber
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Decoder s Word8
forall s. Decoder s Word8
decodeWord8
data Versioned a = Versioned
{ forall a. Versioned a -> VersionNumber
versionNumber :: !VersionNumber
, forall a. Versioned a -> a
versioned :: !a
} deriving (Versioned a -> Versioned a -> Bool
(Versioned a -> Versioned a -> Bool)
-> (Versioned a -> Versioned a -> Bool) -> Eq (Versioned a)
forall a. Eq a => Versioned a -> Versioned a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => Versioned a -> Versioned a -> Bool
== :: Versioned a -> Versioned a -> Bool
$c/= :: forall a. Eq a => Versioned a -> Versioned a -> Bool
/= :: Versioned a -> Versioned a -> Bool
Eq, Int -> Versioned a -> ShowS
[Versioned a] -> ShowS
Versioned a -> String
(Int -> Versioned a -> ShowS)
-> (Versioned a -> String)
-> ([Versioned a] -> ShowS)
-> Show (Versioned a)
forall a. Show a => Int -> Versioned a -> ShowS
forall a. Show a => [Versioned a] -> ShowS
forall a. Show a => Versioned a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> Versioned a -> ShowS
showsPrec :: Int -> Versioned a -> ShowS
$cshow :: forall a. Show a => Versioned a -> String
show :: Versioned a -> String
$cshowList :: forall a. Show a => [Versioned a] -> ShowS
showList :: [Versioned a] -> ShowS
Show)
data VersionError
= IncompatibleVersion VersionNumber String
| UnknownVersion VersionNumber
| MigrationFailed VersionNumber String
deriving stock (Int -> VersionError -> ShowS
[VersionError] -> ShowS
VersionError -> String
(Int -> VersionError -> ShowS)
-> (VersionError -> String)
-> ([VersionError] -> ShowS)
-> Show VersionError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> VersionError -> ShowS
showsPrec :: Int -> VersionError -> ShowS
$cshow :: VersionError -> String
show :: VersionError -> String
$cshowList :: [VersionError] -> ShowS
showList :: [VersionError] -> ShowS
Show)
deriving anyclass (Show VersionError
Typeable VersionError
(Typeable VersionError, Show VersionError) =>
(VersionError -> SomeException)
-> (SomeException -> Maybe VersionError)
-> (VersionError -> String)
-> Exception VersionError
SomeException -> Maybe VersionError
VersionError -> String
VersionError -> SomeException
forall e.
(Typeable e, Show e) =>
(e -> SomeException)
-> (SomeException -> Maybe e) -> (e -> String) -> Exception e
$ctoException :: VersionError -> SomeException
toException :: VersionError -> SomeException
$cfromException :: SomeException -> Maybe VersionError
fromException :: SomeException -> Maybe VersionError
$cdisplayException :: VersionError -> String
displayException :: VersionError -> String
Exception)
data VersionDecoder a where
Incompatible :: String
-> VersionDecoder a
Decode :: (forall s. Decoder s a)
-> VersionDecoder a
Migrate :: VersionDecoder from
-> (from -> Either String to)
-> VersionDecoder to
getVersionDecoder ::
VersionNumber
-> VersionDecoder a
-> forall s. Decoder s a
getVersionDecoder :: forall a.
VersionNumber -> VersionDecoder a -> forall s. Decoder s a
getVersionDecoder VersionNumber
vn = \case
Incompatible String
msg -> String -> Decoder s a
forall a. String -> Decoder s a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Decoder s a) -> String -> Decoder s a
forall a b. (a -> b) -> a -> b
$ VersionError -> String
forall a. Show a => a -> String
show (VersionError -> String) -> VersionError -> String
forall a b. (a -> b) -> a -> b
$ VersionNumber -> String -> VersionError
IncompatibleVersion VersionNumber
vn String
msg
Decode forall s. Decoder s a
dec -> Decoder s a
forall s. Decoder s a
dec
Migrate VersionDecoder from
vDec from -> Either String a
migrate -> do
from
from <- VersionNumber -> VersionDecoder from -> forall s. Decoder s from
forall a.
VersionNumber -> VersionDecoder a -> forall s. Decoder s a
getVersionDecoder VersionNumber
vn VersionDecoder from
vDec
case from -> Either String a
migrate from
from of
Left String
msg -> String -> Decoder s a
forall a. String -> Decoder s a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Decoder s a) -> String -> Decoder s a
forall a b. (a -> b) -> a -> b
$ VersionError -> String
forall a. Show a => a -> String
show (VersionError -> String) -> VersionError -> String
forall a b. (a -> b) -> a -> b
$ VersionNumber -> String -> VersionError
MigrationFailed VersionNumber
vn String
msg
Right a
to -> a -> Decoder s a
forall a. a -> Decoder s a
forall (m :: * -> *) a. Monad m => a -> m a
return a
to
encodeVersion ::
VersionNumber
-> Encoding
-> Encoding
encodeVersion :: VersionNumber -> Encoding -> Encoding
encodeVersion VersionNumber
vn Encoding
encodedA = [Encoding] -> Encoding
forall a. Monoid a => [a] -> a
mconcat
[ Word -> Encoding
encodeListLen Word
2
, VersionNumber -> Encoding
forall a. Serialise a => a -> Encoding
encode VersionNumber
vn
, Encoding
encodedA
]
decodeVersion ::
[(VersionNumber, VersionDecoder a)]
-> forall s. Decoder s a
decodeVersion :: forall a.
[(VersionNumber, VersionDecoder a)] -> forall s. Decoder s a
decodeVersion [(VersionNumber, VersionDecoder a)]
versionDecoders =
Versioned a -> a
forall a. Versioned a -> a
versioned (Versioned a -> a) -> Decoder s (Versioned a) -> Decoder s a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(VersionNumber, VersionDecoder a)]
-> forall s. Decoder s (Versioned a)
forall a.
[(VersionNumber, VersionDecoder a)]
-> forall s. Decoder s (Versioned a)
decodeVersioned [(VersionNumber, VersionDecoder a)]
versionDecoders
decodeVersionWithHook ::
forall a.
(forall s. Maybe Int -> Decoder s a)
-> [(VersionNumber, VersionDecoder a)]
-> forall s. Decoder s a
decodeVersionWithHook :: forall a.
(forall s. Maybe Int -> Decoder s a)
-> [(VersionNumber, VersionDecoder a)] -> forall s. Decoder s a
decodeVersionWithHook forall s. Maybe Int -> Decoder s a
hook [(VersionNumber, VersionDecoder a)]
versionDecoders = do
TokenType
tokenType <- Decoder s TokenType
forall s. Decoder s TokenType
Dec.peekTokenType
if TokenType -> Bool
isListLen TokenType
tokenType then do
Int
len <- Decoder s Int
forall s. Decoder s Int
Dec.decodeListLen
case Int
len of
Int
2 -> Decoder s a
forall s. Decoder s a
goVersioned
Int
_ -> Maybe Int -> Decoder s a
forall s. Maybe Int -> Decoder s a
hook (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
len)
else
Maybe Int -> Decoder s a
forall s. Maybe Int -> Decoder s a
hook Maybe Int
forall a. Maybe a
Nothing
where
isListLen :: Dec.TokenType -> Bool
isListLen :: TokenType -> Bool
isListLen = \case
TokenType
Dec.TypeListLen -> Bool
True
TokenType
Dec.TypeListLen64 -> Bool
True
TokenType
_ -> Bool
False
goVersioned :: forall s. Decoder s a
goVersioned :: forall s. Decoder s a
goVersioned = do
VersionNumber
vn <- Decoder s VersionNumber
forall s. Decoder s VersionNumber
forall a s. Serialise a => Decoder s a
decode
case VersionNumber
-> [(VersionNumber, VersionDecoder a)] -> Maybe (VersionDecoder a)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup VersionNumber
vn [(VersionNumber, VersionDecoder a)]
versionDecoders of
Maybe (VersionDecoder a)
Nothing -> String -> Decoder s a
forall a. String -> Decoder s a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Decoder s a) -> String -> Decoder s a
forall a b. (a -> b) -> a -> b
$ VersionError -> String
forall a. Show a => a -> String
show (VersionError -> String) -> VersionError -> String
forall a b. (a -> b) -> a -> b
$ VersionNumber -> VersionError
UnknownVersion VersionNumber
vn
Just VersionDecoder a
vDec -> VersionNumber -> VersionDecoder a -> forall s. Decoder s a
forall a.
VersionNumber -> VersionDecoder a -> forall s. Decoder s a
getVersionDecoder VersionNumber
vn VersionDecoder a
vDec
encodeVersioned ::
( a -> Encoding)
-> (Versioned a -> Encoding)
encodeVersioned :: forall a. (a -> Encoding) -> Versioned a -> Encoding
encodeVersioned a -> Encoding
enc (Versioned VersionNumber
vn a
a) =
VersionNumber -> Encoding -> Encoding
encodeVersion VersionNumber
vn (a -> Encoding
enc a
a)
decodeVersioned ::
[(VersionNumber, VersionDecoder a)]
-> forall s. Decoder s (Versioned a)
decodeVersioned :: forall a.
[(VersionNumber, VersionDecoder a)]
-> forall s. Decoder s (Versioned a)
decodeVersioned [(VersionNumber, VersionDecoder a)]
versionDecoders = do
Text -> Int -> Decoder s ()
forall s. Text -> Int -> Decoder s ()
enforceSize Text
"Versioned" Int
2
VersionNumber
vn <- Decoder s VersionNumber
forall s. Decoder s VersionNumber
forall a s. Serialise a => Decoder s a
decode
case VersionNumber
-> [(VersionNumber, VersionDecoder a)] -> Maybe (VersionDecoder a)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup VersionNumber
vn [(VersionNumber, VersionDecoder a)]
versionDecoders of
Maybe (VersionDecoder a)
Nothing -> String -> Decoder s (Versioned a)
forall a. String -> Decoder s a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Decoder s (Versioned a))
-> String -> Decoder s (Versioned a)
forall a b. (a -> b) -> a -> b
$ VersionError -> String
forall a. Show a => a -> String
show (VersionError -> String) -> VersionError -> String
forall a b. (a -> b) -> a -> b
$ VersionNumber -> VersionError
UnknownVersion VersionNumber
vn
Just VersionDecoder a
vDec -> VersionNumber -> a -> Versioned a
forall a. VersionNumber -> a -> Versioned a
Versioned VersionNumber
vn (a -> Versioned a) -> Decoder s a -> Decoder s (Versioned a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VersionNumber -> VersionDecoder a -> forall s. Decoder s a
forall a.
VersionNumber -> VersionDecoder a -> forall s. Decoder s a
getVersionDecoder VersionNumber
vn VersionDecoder a
vDec