-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP support sets (well, kinda of) #79
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @adinapoli, I think sets would be very useful to support more natively in api-tools
. I have a few concerns about the CBOR-related details and I think we can do something simpler, but the general idea seems good to me.
instance (Ord a, FromJSONWithErrs a) => FromJSONWithErrs (Set.Set a) where | ||
parseJSONWithErrs v@(JS.Object kvs) = case jsonParseCborSet kvs of | ||
Nothing -> failWith $ expectedSet v | ||
Just xs -> fmap Set.fromList <$> traverse help $ zip (V.toList xs) [0..] | ||
where | ||
help (x, i) = stepInside (InElem i) $ parseJSONWithErrs x | ||
parseJSONWithErrs JS.Null = pure mempty | ||
parseJSONWithErrs v = failWith $ expectedArray v |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the JSON representation of a set should simply be the list of its elements (insensitive to order, when decoding, and ordered when encoding).
@@ -188,6 +190,7 @@ Type :: { APIType } | |||
Type | |||
: '?' Type { TyMaybe $2 } | |||
| '[' Type ']' { TyList $2 } | |||
| '{' Type '}' { TySet $2 } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about using Set T
as the syntax, rather than {T}
? Similarly I think in retrospect Maybe T
would have been better than ? T
; we could even add that as an alternative now?
@@ -296,6 +299,7 @@ instance NFData BasicType where | |||
-- | A default value for a field | |||
data DefaultValue | |||
= DefValList | |||
| DefValSet |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we need DefValSet
with its own syntax, can we just use DefValList
for both?
TySet ty -> case v of | ||
JS.Array arr -> Set . Set.fromDistinctAscList <$> traverse (parseJSON api ty) (V.toList arr) | ||
_ -> failWith (expectedArray v) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why fromDistinctAscList
? Is it clear we can assume the list is sorted here?
-- | Cribbed from 'cardano-base' and 'cardano-sl', functions that I (adinapoli) | ||
-- wrote eons ago anyway. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't necessarily use these without satisfying the license conditions on the source packages (which probably means incorporating their licenses).
-- | ||
-- Encoding and decoding sets | ||
-- | ||
|
||
encodeSetLikeWith :: (a -> Encoding) -> [a] -> Encoding | ||
encodeSetLikeWith f xs = encodeSetSkel f length foldr xs | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer not to complicate the CBOR encoding/decoding code unless absolutely necessary, and I don't think we need special support for CBOR sets. Let's just lists.
@@ -679,6 +681,10 @@ updateTypeAt' :: Map TypeName UpdateDeclPos | |||
updateTypeAt' upds alter (UpdateList upd) v p = do | |||
xs <- expectList v p | |||
List <$!> mapM (\ (i, v') -> updateTypeAt' upds alter upd v' (InElem i : p)) (zip [0..] xs) | |||
updateTypeAt' upds alter (UpdateSet upd) v p = do | |||
xs <- expectSet v p | |||
Set . Set.fromDistinctAscList <$!> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming the elements are distinct and sorted looks a bit dangerous to me?
@@ -372,6 +390,7 @@ arbitraryOfType :: NormAPI -> APIType -> QC.Gen Value | |||
arbitraryOfType api ty0 = case ty0 of | |||
TyName tn -> arbitraryOfDecl api (lookupTyName api tn) | |||
TyList ty -> List <$> QC.listOf (arbitraryOfType api ty) | |||
TySet ty -> Set . Set.fromDistinctAscList <$> QC.listOf (arbitraryOfType api ty) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely not safe.
@@ -246,6 +256,7 @@ decode :: NormAPI -> APIType -> CBOR.Decoder s Value | |||
decode api ty0 = case ty0 of | |||
TyName tn -> decodeDecl api (lookupTyName api tn) | |||
TyList ty -> List <$!> decodeListWith (decode api ty) | |||
TySet ty -> Set . Set.fromDistinctAscList <$!> decodeSetLikeWith (decode api ty) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this use of fromDistinctAscList
is probably safe, but I'm wary...
@@ -93,6 +95,7 @@ data Value = String !T.Text | |||
| Bool !Bool | |||
| Int !Int | |||
| List ![Value] | |||
| Set !(Set.Set Value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to make sure that the CBOR encoding/decoding of the "generic representation" Value
is consistent with the specific CBOR encoding/decoding instances generated by TH for particular types. Here's a worry: what if the Ord
instance for the specific type used an ordering that isn't consistent with the ordering of the corresponding Value
s?
Maybe this is okay, provided the decoder doesn't assume that the values are sorted, because it can sort them when constructing the set in memory.
To be discussed. This introduces a
{x}
syntax for sets of typex
, and serialises to CBOR using the IANA cbor spec.