Skip to content
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

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

adinapoli
Copy link
Contributor

To be discussed. This introduces a {x} syntax for sets of type x, and serialises to CBOR using the IANA cbor spec.

Copy link
Contributor

@adamgundry adamgundry left a 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.

Comment on lines +211 to +218
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
Copy link
Contributor

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 }
Copy link
Contributor

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
Copy link
Contributor

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?

Comment on lines +200 to +202
TySet ty -> case v of
JS.Array arr -> Set . Set.fromDistinctAscList <$> traverse (parseJSON api ty) (V.toList arr)
_ -> failWith (expectedArray v)
Copy link
Contributor

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?

Comment on lines +132 to +133
-- | Cribbed from 'cardano-base' and 'cardano-sl', functions that I (adinapoli)
-- wrote eons ago anyway.
Copy link
Contributor

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).

Comment on lines +87 to +93
--
-- Encoding and decoding sets
--

encodeSetLikeWith :: (a -> Encoding) -> [a] -> Encoding
encodeSetLikeWith f xs = encodeSetSkel f length foldr xs

Copy link
Contributor

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 <$!>
Copy link
Contributor

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)
Copy link
Contributor

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)
Copy link
Contributor

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)
Copy link
Contributor

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 Values?

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants