@@ -1,4 +1,5 @@
1{-# LANGUAGE QuantifiedConstraints #-}
1{-# LANGUAGE QuantifiedConstraints #-}
2module OpenAPI.Checker.TracePrefixTree
3module OpenAPI.Checker.TracePrefixTree
3 ( TracePrefixTree
4 ( TracePrefixTree
@@ -8,65 +9,87 @@ module OpenAPI.Checker.TracePrefixTree
13−import qualified GHC.Exts as T
15+import Data.Aeson
14import Data.Foldable hiding (null, toList)
16import Data.Foldable hiding (null, toList)
17+import qualified Data.HashMap.Strict as HM
15import Data.Kind
18import Data.Kind
16import qualified Data.Map as M
19import qualified Data.Map as M
17import Data.Monoid
20import Data.Monoid
18import qualified Data.Set as S
21import qualified Data.Set as S
19−import qualified Data.TypeRepMap as T
22+import qualified Data.Text as T
23+import Data.Type.Equality
24+import qualified Data.TypeRepMap as TRM
25+import qualified Data.Vector as V
26+import qualified GHC.Exts as TRM
20import OpenAPI.Checker.Trace
27import OpenAPI.Checker.Trace
21−import Prelude hiding (null, filter)
22import Type.Reflection
28import Type.Reflection
23−import Data.Type.Equality
29+import Prelude hiding (filter, null)
25-- | A list of @AnItem r f@, but optimized into a prefix tree.
31-- | A list of @AnItem r f@, but optimized into a prefix tree.
26data TracePrefixTree (f :: k -> Type) (r :: k) = TracePrefixTree
32data TracePrefixTree (f :: k -> Type) (r :: k) = TracePrefixTree
27 { rootItems :: !(ASet (f r))
33 { rootItems :: !(ASet (f r))
28− , snocItems :: !(T.TypeRepMap (AStep f r))
34+ , snocItems :: !(TRM.TypeRepMap (AStep f r))
37+instance (forall a. ToJSON (f a)) => ToJSON (TracePrefixTree f r) where
39+ Object . getMergableObject
40+ . foldWith (\t x -> MergableObject . traceObject t $ toJSON x)
31deriving instance Eq (TracePrefixTree f a)
42deriving instance Eq (TracePrefixTree f a)
33-- Kind of orphan. Treat the map as an infinite tuple of @Maybe (f a)@'s, where
44-- Kind of orphan. Treat the map as an infinite tuple of @Maybe (f a)@'s, where
34-- the components are ordered by the @SomeTypeRep@ of the @a@.
45-- the components are ordered by the @SomeTypeRep@ of the @a@.
36 :: (forall a. Typeable a => Ord (f a))
47 :: (forall a. Typeable a => Ord (f a))
37− => T.TypeRepMap f -> T.TypeRepMap f -> Ordering
48+ => TRM.TypeRepMap f
38−compareTRM s1 s2
51+compareTRM s1 s2 =
39− = foldMap (\k -> compareMaybe compareW (M.lookup k m1) (M.lookup k m2)) mKeys
52+ foldMap (\k -> compareMaybe compareW (M.lookup k m1) (M.lookup k m2)) mKeys
41 (m1, m2) = (toMap s1, toMap s2)
54 (m1, m2) = (toMap s1, toMap s2)
42 mKeys = S.toAscList $ M.keysSet m1 `S.union` M.keysSet m2
55 mKeys = S.toAscList $ M.keysSet m1 `S.union` M.keysSet m2
43− compareMaybe _ Nothing Nothing = EQ
56+ compareMaybe _ Nothing Nothing = EQ
44− compareMaybe _ Nothing (Just _) = LT
57+ compareMaybe _ Nothing (Just _) = LT
45− compareMaybe _ (Just _) Nothing = GT
58+ compareMaybe _ (Just _) Nothing = GT
46 compareMaybe cmp (Just x) (Just y) = cmp x y
59 compareMaybe cmp (Just x) (Just y) = cmp x y
48 :: (forall a. Typeable a => Ord (f a))
61 :: (forall a. Typeable a => Ord (f a))
49− => T.WrapTypeable f -> T.WrapTypeable f -> Ordering
62+ => TRM.WrapTypeable f
63+ -> TRM.WrapTypeable f
50− compareW (T.WrapTypeable (x :: f a)) (T.WrapTypeable (y :: f b))
65+ compareW (TRM.WrapTypeable (x :: f a)) (TRM.WrapTypeable (y :: f b))
51 | Just Refl <- testEquality (typeRep @a) (typeRep @b) = compare x y
66 | Just Refl <- testEquality (typeRep @a) (typeRep @b) = compare x y
52 | otherwise = EQ -- unreachable
67 | otherwise = EQ -- unreachable
53− toMap s = M.fromList
69+ M.fromList
54− [(someTypeRep x, w) | w@(T.WrapTypeable x) <- T.toList s]
70+ [(someTypeRep x, w) | w@(TRM.WrapTypeable x) <- TRM.toList s]
56instance Ord (TracePrefixTree f a) where
72instance Ord (TracePrefixTree f a) where
57− compare (TracePrefixTree r1 s1) (TracePrefixTree r2 s2)
73+ compare (TracePrefixTree r1 s1) (TracePrefixTree r2 s2) =
58− = compare r1 r2 <> compareTRM s1 s2
74+ compare r1 r2 <> compareTRM s1 s2
60data ASet (a :: Type) where
76data ASet (a :: Type) where
61 AnEmptySet :: ASet a
77 AnEmptySet :: ASet a
62 ASet :: Ord a => S.Set a -> ASet a
78 ASet :: Ord a => S.Set a -> ASet a
80+instance ToJSON a => ToJSON (ASet a) where
83+ AnEmptySet -> S.empty
64instance Semigroup (ASet a) where
86instance Semigroup (ASet a) where
65 AnEmptySet <> s = s
87 AnEmptySet <> s = s
66 s <> AnEmptySet = s
88 s <> AnEmptySet = s
67 ASet s1 <> ASet s2 = ASet $ S.union s1 s2
89 ASet s1 <> ASet s2 = ASet $ S.union s1 s2
69deriving instance Eq (ASet a)
91deriving instance Eq (ASet a)
70deriving instance Ord (ASet a)
93deriving instance Ord (ASet a)
72-- type traceprefixset = traceprefixtree proxy
95-- type traceprefixset = traceprefixtree proxy
@@ -76,26 +99,33 @@ instance Monoid (ASet a) where
77data AStep (f :: k -> Type) (r :: k) (a :: k) where
100data AStep (f :: k -> Type) (r :: k) (a :: k) where
79− :: Steppable r a => !(M.Map (Step r a) (TracePrefixTree f a)) -> AStep f r a
103+ !(M.Map (Step r a) (TracePrefixTree f a))
81deriving instance Eq (AStep f r a)
106deriving instance Eq (AStep f r a)
82deriving instance Ord (AStep f r a)
108deriving instance Ord (AStep f r a)
84singleton :: AnItem f r -> TracePrefixTree f r
110singleton :: AnItem f r -> TracePrefixTree f r
85−singleton (AnItem ys v) = go ys $ TracePrefixTree (ASet $ S.singleton v) T.empty
111+singleton (AnItem ys v) = go ys $ TracePrefixTree (ASet $ S.singleton v) TRM.empty
87 go :: Trace r a -> TracePrefixTree f a -> TracePrefixTree f r
113 go :: Trace r a -> TracePrefixTree f a -> TracePrefixTree f r
88 go Root !t = t
114 go Root !t = t
89− go (Snoc xs x) !t = go xs $ TracePrefixTree AnEmptySet $ T.one
117+ TracePrefixTree AnEmptySet $
90− $ AStep $ M.singleton x t
119+ AStep $ M.singleton x t
92instance Semigroup (TracePrefixTree f r) where
121instance Semigroup (TracePrefixTree f r) where
93 TracePrefixTree r1 s1 <> TracePrefixTree r2 s2 =
122 TracePrefixTree r1 s1 <> TracePrefixTree r2 s2 =
94− TracePrefixTree (r1 <> r2) (T.unionWith joinSteps s1 s2)
123+ TracePrefixTree (r1 <> r2) (TRM.unionWith joinSteps s1 s2)
95− where joinSteps (AStep m1) (AStep m2) = AStep $ M.unionWith (<>) m1 m2
125+ joinSteps (AStep m1) (AStep m2) = AStep $ M.unionWith (<>) m1 m2
97instance Monoid (TracePrefixTree f r) where
127instance Monoid (TracePrefixTree f r) where
98− mempty = TracePrefixTree mempty T.empty
128+ mempty = TracePrefixTree mempty TRM.empty
100empty :: TracePrefixTree f r
130empty :: TracePrefixTree f r
101empty = mempty
131empty = mempty
@@ -104,12 +134,15 @@ fromList :: [AnItem f r] -> TracePrefixTree f r
104fromList = foldMap singleton
134fromList = foldMap singleton
106null :: TracePrefixTree f r -> Bool
136null :: TracePrefixTree f r -> Bool
107−null (TracePrefixTree AnEmptySet s) = T.size s == 0
137+null (TracePrefixTree AnEmptySet s) = TRM.size s == 0
108null _ = False
138null _ = False
111− :: forall f m r. Monoid m
141+ :: forall f m r.
112− => (forall a. Ord (f a) => Trace r a -> f a -> m) -> TracePrefixTree f r -> m
143+ => (forall a. Ord (f a) => Trace r a -> f a -> m)
144+ -> TracePrefixTree f r
113foldWith k = goTPT Root
146foldWith k = goTPT Root
115 goTPT :: forall a. Trace r a -> TracePrefixTree f a -> m
148 goTPT :: forall a. Trace r a -> TracePrefixTree f a -> m
@@ -117,17 +150,41 @@ foldWith k = goTPT Root
117 goASet :: forall a. Trace r a -> ASet (f a) -> m
150 goASet :: forall a. Trace r a -> ASet (f a) -> m
118 goASet _ AnEmptySet = mempty
151 goASet _ AnEmptySet = mempty
119 goASet xs (ASet rs) = foldMap (k xs) rs
152 goASet xs (ASet rs) = foldMap (k xs) rs
120− goTRM :: forall a. Trace r a -> T.TypeRepMap (AStep f a) -> m
153+ goTRM :: forall a. Trace r a -> TRM.TypeRepMap (AStep f a) -> m
121− goTRM xs s = foldMap (\(T.WrapTypeable f) -> goAStep xs f) $ T.toList s
154+ goTRM xs s = foldMap (\(TRM.WrapTypeable f) -> goAStep xs f) $ TRM.toList s
122 goAStep :: forall a b. Trace r a -> AStep f a b -> m
155 goAStep :: forall a b. Trace r a -> AStep f a b -> m
123− goAStep xs (AStep m)
156+ goAStep xs (AStep m) =
124− = M.foldrWithKey (\x t -> (goTPT (Snoc xs x) t <>)) mempty m
157+ M.foldrWithKey (\x t -> (goTPT (Snoc xs x) t <>)) mempty m
126toList :: TracePrefixTree f r -> [AnItem f r]
159toList :: TracePrefixTree f r -> [AnItem f r]
127−toList t = appEndo (foldWith (\xs f -> Endo (AnItem xs f:)) t) []
160+toList t = appEndo (foldWith (\xs f -> Endo (AnItem xs f :)) t) []
129-- | Select a subtree by prefix
162-- | Select a subtree by prefix
130filter :: Trace r a -> TracePrefixTree f r -> TracePrefixTree f a
163filter :: Trace r a -> TracePrefixTree f r -> TracePrefixTree f a
131filter Root t = t
164filter Root t = t
165+filter (Snoc xs x) t =
132−filter (Snoc xs x) t = foldMap (\(AStep m) -> fold $ M.lookup x m)
166+ foldMap (\(AStep m) -> fold $ M.lookup x m) $
133− $ T.lookup $ snocItems $ filter xs t
167+ TRM.lookup $ snocItems $ filter xs t
169+newtype MergableObject = MergableObject {getMergableObject :: Object}
171+instance Semigroup MergableObject where
172+ (MergableObject x) <> (MergableObject y) =
173+ MergableObject $ HM.unionWith mergeValue x y
175+ mergeValue :: Value -> Value -> Value
176+ mergeValue (Object a) (Object b) =
177+ Object . getMergableObject $ MergableObject a <> MergableObject b
178+ mergeValue (Array a) (Array b) = Array $ a <> b
179+ mergeValue (Array a) b = Array $ V.snoc a b
180+ mergeValue a (Array b) = Array $ V.cons a b
181+ mergeValue a b = toJSON [a, b]
183+instance Monoid MergableObject where
184+ mempty = MergableObject mempty
186+traceObject :: Trace r a -> Value -> Object
187+traceObject Root (Object o) = o
188+traceObject Root v = HM.singleton "root" v
189+traceObject (root `Snoc` s) v =
190+ traceObject root . Object $ HM.singleton (T.pack . show $ s) v