{-# LANGUAGE
- DoAndIfThenElse
- , ExistentialQuantification
+ ExistentialQuantification
+ , FlexibleContexts
, FlexibleInstances
, GeneralizedNewtypeDeriving
, OverlappingInstances
, MultiParamTypeClasses
- , RecordWildCards
- , ScopedTypeVariables
, TemplateHaskell
, UndecidableInstances
, UnicodeSyntax
#-}
-{-# OPTIONS_GHC -fno-warn-missing-methods #-}
module Network.HTTP.Lucu.Dispatcher.Internal
( SchemeMapper(..)
, SchemeMap
, ResourceMap
, ResourceTree
, ResourceNode
+ , greedy
+ , nonGreedy
, dispatch
)
data ResourceMap = ∀α. ResourceMapper α ⇒ RMap α
-- |FIXME: doc
-newtype ResourceTree = Root ResourceNode
- deriving (Monoid, Show)
+newtype ResourceTree = Tree (M.Map PathSegments ResourceNode)
+ deriving Monoid
--- |FIXME: docs
+-- |FIXME: doc
data ResourceNode
- = Greedy !Resource !SubTree
- | NonGreedy !Resource !SubTree
- | Branch !SubTree
+ = Greedy { nResource ∷ !Resource }
+ | NonGreedy { nResource ∷ !Resource }
-type SubTree
- = M.Map PathSegment ResourceNode
+-- |FIXME: doc
+greedy ∷ Resource → ResourceNode
+{-# INLINE CONLIKE greedy #-}
+greedy = Greedy
+
+-- |FIXME: doc
+nonGreedy ∷ Resource → ResourceNode
+{-# INLINE CONLIKE nonGreedy #-}
+nonGreedy = NonGreedy
-- Instances of SchemeMapper --------------------------------------------------
instance SchemeMapper SchemeMap where
-- Instances of ResourceTree --------------------------------------------------
instance Unfoldable ResourceTree (PathSegments, ResourceNode) where
{-# INLINEABLE insert #-}
- insert (p, a) (Root b) = Root $ insertNodeAt (canonPath p) a b
+ insert (p, n) (Tree m) = Tree $ insert (canonPath p, n) m
{-# INLINE empty #-}
- empty = Root $ Branch (∅)
+ empty = Tree (∅)
+ {-# INLINE singleton #-}
+ singleton = Tree ∘ singleton
canonPath ∷ (Collection c f, Foldable f e) ⇒ c → c
{-# INLINEABLE canonPath #-}
canonPath = filter ((¬) ∘ null)
-insertNodeAt ∷ PathSegments → ResourceNode → ResourceNode → ResourceNode
-{-# INLINEABLE insertNodeAt #-}
-insertNodeAt p a b
- = case front p of
- Nothing → a ⊕ b
- Just (x, xs)
- | null xs → Branch (singleton (x, a)) ⊕ b
- | otherwise → insertNodeAt xs a (∅) ⊕ b
-
-instance Foldable ResourceTree (PathSegments, ResourceNode) where
- foldMap f (Root n) = go (∅) n
- where
- go p (Greedy r m) = go' p m ⊕ f (p, Greedy r (∅))
- go p (NonGreedy r m) = go' p m ⊕ f (p, NonGreedy r (∅))
- go p (Branch m) = go' p m
-
- go' p = foldMap $ \(s, n') → go (p `snoc` s) n'
-
- null (Root (Greedy _ _)) = False
- null (Root (NonGreedy _ _)) = False
- null (Root (Branch m)) = null m
-
-instance Collection ResourceTree (PathSegments, ResourceNode) where
- {-# INLINE filter #-}
- filter f = fromList ∘ filter f ∘ fromFoldable
-
-
--- Instances of ResourceNode --------------------------------------------------
-instance Show ResourceNode where
- show (Greedy _ m) = "Greedy _ " ⊕ show m
- show (NonGreedy _ m) = "NonGreedy _ " ⊕ show m
- show (Branch m) = "Branch " ⊕ show m
-
-instance Monoid ResourceNode where
- {-# INLINE mempty #-}
- mempty = Branch (∅)
- {-# INLINEABLE mappend #-}
- mappend (Greedy r m) _ = Greedy r m
- mappend (NonGreedy r m) (Greedy _ n) = NonGreedy r (m ⊕ n)
- mappend (NonGreedy r m) (NonGreedy _ n) = NonGreedy r (m ⊕ n)
- mappend (NonGreedy r m) (Branch n) = NonGreedy r (m ⊕ n)
- mappend (Branch m) (Greedy r n) = Greedy r (m ⊕ n)
- mappend (Branch m) (NonGreedy r n) = NonGreedy r (m ⊕ n)
- mappend (Branch m) (Branch n) = Branch (m ⊕ n)
+-- |'findResource' performs the longest prefix match on the tree,
+-- finding the most specific one.
+instance ResourceMapper ResourceTree where
+ {-# INLINEABLE findResource #-}
+ findResource p (Tree m)
+ = case lookup p m of
+ Just n → return (p, nResource n)
+ Nothing → findGreedyResource p m
+
+findGreedyResource ∷ (Monad m, Map α PathSegments ResourceNode)
+ ⇒ PathSegments
+ → α
+ → MaybeT m (PathSegments, Resource)
+findGreedyResource p m
+ = case back p of
+ Nothing → fail (⊥)
+ Just (p', _) → case lookup p' m of
+ Just (Greedy r)
+ → return (p', r)
+ _ → findGreedyResource p' m
-- dispatch -------------------------------------------------------------------
dispatch ∷ SchemeMapper α ⇒ URI → α → MaybeT IO (PathSegments, Resource)