1+ {-# LANGUAGE AllowAmbiguousTypes #-}
12{-# LANGUAGE DuplicateRecordFields #-}
23{-# LANGUAGE FunctionalDependencies #-}
34{-# LANGUAGE GADTs #-}
45{-# LANGUAGE LambdaCase #-}
56{-# LANGUAGE OverloadedStrings #-}
7+ {-# LANGUAGE PartialTypeSignatures #-}
68{-# LANGUAGE TypeApplications #-}
79{-# LANGUAGE TypeFamilies #-}
810{-# LANGUAGE UndecidableInstances #-}
@@ -59,6 +61,7 @@ module Codec.CBOR.Cuddle.Huddle
5961 text ,
6062
6163 -- * Ctl operators
64+ IsConstrainable ,
6265 IsSizeable ,
6366 sized ,
6467 cbor ,
@@ -261,7 +264,7 @@ instance IsList Group where
261264 toList (Group l) = l
262265
263266data Type2
264- = T2Basic Constrained
267+ = T2Constrained Constrained
265268 | T2Literal Ranged
266269 | T2Map Map
267270 | T2Array Array
@@ -346,11 +349,27 @@ inferInteger i
346349-- Constraints and Ranges
347350--------------------------------------------------------------------------------
348351
349- -- | We only allow constraining basic values.
352+ -- | A reference can be to any type, so we allow it to inhabit all
353+ type AnyRef a = Named Type0
354+
355+ data Constrainable a
356+ = CValue (Value a )
357+ | CRef (AnyRef a )
358+ | CGRef GRef
359+ deriving (Show )
360+
361+ -- | Uninhabited type used as marker for the type of thing a CRef sizes
362+ data CRefType
363+
364+ -- | Uninhabited type used as marker for the type of thing a CGRef sizes
365+ data CGRefType
366+
367+ -- | We only allow constraining basic values, or references. Of course, we
368+ -- can't check what the references refer to.
350369data Constrained where
351370 Constrained ::
352371 forall a .
353- { value :: Value a ,
372+ { value :: Constrainable a ,
354373 constraint :: ValueConstraint a ,
355374 -- | Sometimes constraints reference rules. In this case we need to
356375 -- collect the references in order to traverse them when collecting all
@@ -361,8 +380,20 @@ data Constrained where
361380
362381deriving instance Show Constrained
363382
383+ class IsConstrainable a x | a -> x where
384+ toConstrainable :: a -> Constrainable x
385+
386+ instance IsConstrainable (AnyRef a ) CRefType where
387+ toConstrainable = CRef
388+
389+ instance IsConstrainable (Value a ) a where
390+ toConstrainable = CValue
391+
392+ instance IsConstrainable GRef CGRefType where
393+ toConstrainable = CGRef
394+
364395unconstrained :: Value a -> Constrained
365- unconstrained v = Constrained v def []
396+ unconstrained v = Constrained ( CValue v) def []
366397
367398-- | A constraint on a 'Value' is something applied via CtlOp or RangeOp on a
368399-- Type2, forming a Type1.
@@ -391,6 +422,10 @@ instance IsSizeable ByteString
391422
392423instance IsSizeable T. Text
393424
425+ instance IsSizeable CRefType
426+
427+ instance IsSizeable CGRefType
428+
394429-- | Things which can be used on the RHS of the '.size' operator.
395430class IsSize a where
396431 sizeAsCDDL :: a -> C. Type2
@@ -412,11 +447,20 @@ instance IsSize (Word64, Word64) where
412447 )
413448 sizeAsString (x, y) = show x <> " .." <> show y
414449
415- -- | Declare a size constraint on an int-style type.
416- sized :: (IsSizeable a , IsSize s ) => Value a -> s -> Constrained
450+ -- | Declare a size constraint on an int-style type or reference.
451+ -- Since 0.3.4 this has worked for reference types as well as values.
452+ sized ::
453+ forall c a s .
454+ ( IsSizeable a ,
455+ IsSize s ,
456+ IsConstrainable c a
457+ ) =>
458+ c ->
459+ s ->
460+ Constrained
417461sized v sz =
418462 Constrained
419- v
463+ (toConstrainable @ c @ a v)
420464 ValueConstraint
421465 { applyConstraint = \ t2 ->
422466 C. Type1
@@ -426,10 +470,15 @@ sized v sz =
426470 }
427471 []
428472
429- cbor :: Value ByteString -> Rule -> Constrained
473+ class IsCborable a
474+ instance IsCborable ByteString
475+ instance IsCborable CRef
476+ instance IsCborable CGRef
477+
478+ cbor :: (IsCborable b , IsConstrainable c b ) => c -> Rule -> Constrained
430479cbor v r@ (Named n _ _) =
431480 Constrained
432- v
481+ (toConstrainable v)
433482 ValueConstraint
434483 { applyConstraint = \ t2 ->
435484 C. Type1
@@ -439,10 +488,15 @@ cbor v r@(Named n _ _) =
439488 }
440489 [r]
441490
442- le :: Value Int -> Word64 -> Constrained
491+ class IsComparable a
492+ instance IsComparable Int
493+ instance IsComparable CRef
494+ instance IsComparable CGRef
495+
496+ le :: (IsComparable a , IsConstrainable c a ) => c -> Word64 -> Constrained
443497le v bound =
444498 Constrained
445- v
499+ (toConstrainable v)
446500 ValueConstraint
447501 { applyConstraint = \ t2 ->
448502 C. Type1
@@ -485,7 +539,7 @@ instance IsType0 (Choice Type2) where
485539 toType0 = id
486540
487541instance IsType0 Constrained where
488- toType0 = NoChoice . T2Basic
542+ toType0 = NoChoice . T2Constrained
489543
490544instance IsType0 Map where
491545 toType0 = NoChoice . T2Map
@@ -523,7 +577,7 @@ instance IsType0 Double where
523577 toType0 = NoChoice . T2Literal . Unranged . LDouble
524578
525579instance IsType0 (Value a ) where
526- toType0 = NoChoice . T2Basic . unconstrained
580+ toType0 = NoChoice . T2Constrained . unconstrained
527581
528582instance IsType0 (Named Group ) where
529583 toType0 = NoChoice . T2Group
@@ -667,7 +721,7 @@ instance IsChoosable ByteString Type2 where
667721 toChoice = toChoice . T2Literal . Unranged . LBytes
668722
669723instance IsChoosable Constrained Type2 where
670- toChoice = toChoice . T2Basic
724+ toChoice = toChoice . T2Constrained
671725
672726instance (IsType0 a ) => IsChoosable (Tagged a ) Type2 where
673727 toChoice = toChoice . T2Tagged . fmap toType0
@@ -676,7 +730,7 @@ instance IsChoosable Literal Type2 where
676730 toChoice = toChoice . T2Literal . Unranged
677731
678732instance IsChoosable (Value a ) Type2 where
679- toChoice = toChoice . T2Basic . unconstrained
733+ toChoice = toChoice . T2Constrained . unconstrained
680734
681735instance IsChoosable (Named Group ) Type2 where
682736 toChoice = toChoice . T2Group
@@ -903,7 +957,13 @@ collectFrom topRs =
903957 -- Note that the parameters here may be different, so this doesn't live
904958 -- under the guard
905959 mapM_ goT2 $ args g
906- goT2 (T2Basic (Constrained _ _ refs)) = mapM_ goRule refs
960+ goT2 (T2Constrained (Constrained c _ refs)) =
961+ ( case c of
962+ CValue _ -> pure ()
963+ CRef r -> goRule r
964+ CGRef _ -> pure ()
965+ )
966+ >> mapM_ goRule refs
907967 goT2 _ = pure ()
908968 goArrayEntry (ArrayEntry (Just k) t0 _ _) = goKey k >> goT0 t0
909969 goArrayEntry (ArrayEntry Nothing t0 _ _) = goT0 t0
@@ -985,9 +1045,9 @@ toCDDL' mkPseudoRoot hdl =
9851045
9861046 toCDDLType1 :: Type2 -> C. Type1
9871047 toCDDLType1 = \ case
988- T2Basic (Constrained x constr _) ->
1048+ T2Constrained (Constrained x constr _) ->
9891049 -- TODO Need to handle choices at the top level
990- applyConstraint constr (C. T2Name (toCDDLPostlude x) Nothing )
1050+ applyConstraint constr (C. T2Name (toCDDLConstrainable x) Nothing )
9911051 T2Literal l -> toCDDLRanged l
9921052 T2Map m ->
9931053 C. Type1
@@ -1017,13 +1077,14 @@ toCDDL' mkPseudoRoot hdl =
10171077
10181078 arrayEntryToCDDL :: ArrayEntry -> C. WithComments C. GroupEntry
10191079 arrayEntryToCDDL (ArrayEntry k v occ cmnt) =
1020- C. WithComments
1021- ( C. GEType
1022- (toOccurrenceIndicator occ)
1023- (fmap toMemberKey k)
1024- (toCDDLType0 v)
1080+ C. WithComments
1081+ ( C. GEType
1082+ (toOccurrenceIndicator occ)
1083+ (fmap toMemberKey k)
1084+ (toCDDLType0 v)
10251085 )
10261086 (fmap C. Comment cmnt)
1087+
10271088 toCDDLPostlude :: Value a -> C. Name
10281089 toCDDLPostlude VBool = C. Name " bool"
10291090 toCDDLPostlude VUInt = C. Name " uint"
@@ -1037,6 +1098,11 @@ toCDDL' mkPseudoRoot hdl =
10371098 toCDDLPostlude VAny = C. Name " any"
10381099 toCDDLPostlude VNil = C. Name " nil"
10391100
1101+ toCDDLConstrainable c = case c of
1102+ CValue v -> toCDDLPostlude v
1103+ CRef r -> C. Name $ name r
1104+ CGRef (GRef n) -> C. Name n
1105+
10401106 toCDDLRanged :: Ranged -> C. Type1
10411107 toCDDLRanged (Unranged x) =
10421108 C. Type1 (C. T2Value $ toCDDLValue x) Nothing
0 commit comments