module Unison.HashQualified where

import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Data.Set.NonEmpty qualified as Set.NonEmpty
import Data.Text qualified as Text
import Unison.ConstructorReference (ConstructorReference)
import Unison.ConstructorReference qualified as ConstructorReference
import Unison.Name (Name)
import Unison.Name qualified as Name
import Unison.Prelude hiding (fromString)
import Unison.Reference (Reference)
import Unison.Reference qualified as Reference
import Unison.Referent (Referent)
import Unison.Referent qualified as Referent
import Unison.ShortHash (ShortHash)
import Unison.ShortHash qualified as SH
import Unison.Util.Relation (Relation)
import Unison.Util.Relation qualified as Relation
import Prelude hiding (take)

data HashQualified n
  = NameOnly n
  | HashOnly ShortHash
  | HashQualified n ShortHash
  deriving stock (HashQualified n -> HashQualified n -> Bool
(HashQualified n -> HashQualified n -> Bool)
-> (HashQualified n -> HashQualified n -> Bool)
-> Eq (HashQualified n)
forall n. Eq n => HashQualified n -> HashQualified n -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall n. Eq n => HashQualified n -> HashQualified n -> Bool
== :: HashQualified n -> HashQualified n -> Bool
$c/= :: forall n. Eq n => HashQualified n -> HashQualified n -> Bool
/= :: HashQualified n -> HashQualified n -> Bool
Eq, (forall m. Monoid m => HashQualified m -> m)
-> (forall m a. Monoid m => (a -> m) -> HashQualified a -> m)
-> (forall m a. Monoid m => (a -> m) -> HashQualified a -> m)
-> (forall a b. (a -> b -> b) -> b -> HashQualified a -> b)
-> (forall a b. (a -> b -> b) -> b -> HashQualified a -> b)
-> (forall b a. (b -> a -> b) -> b -> HashQualified a -> b)
-> (forall b a. (b -> a -> b) -> b -> HashQualified a -> b)
-> (forall a. (a -> a -> a) -> HashQualified a -> a)
-> (forall a. (a -> a -> a) -> HashQualified a -> a)
-> (forall a. HashQualified a -> [a])
-> (forall a. HashQualified a -> Bool)
-> (forall a. HashQualified a -> Int)
-> (forall a. Eq a => a -> HashQualified a -> Bool)
-> (forall a. Ord a => HashQualified a -> a)
-> (forall a. Ord a => HashQualified a -> a)
-> (forall a. Num a => HashQualified a -> a)
-> (forall a. Num a => HashQualified a -> a)
-> Foldable HashQualified
forall a. Eq a => a -> HashQualified a -> Bool
forall a. Num a => HashQualified a -> a
forall a. Ord a => HashQualified a -> a
forall m. Monoid m => HashQualified m -> m
forall a. HashQualified a -> Bool
forall a. HashQualified a -> Int
forall a. HashQualified a -> [a]
forall a. (a -> a -> a) -> HashQualified a -> a
forall m a. Monoid m => (a -> m) -> HashQualified a -> m
forall b a. (b -> a -> b) -> b -> HashQualified a -> b
forall a b. (a -> b -> b) -> b -> HashQualified a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
$cfold :: forall m. Monoid m => HashQualified m -> m
fold :: forall m. Monoid m => HashQualified m -> m
$cfoldMap :: forall m a. Monoid m => (a -> m) -> HashQualified a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> HashQualified a -> m
$cfoldMap' :: forall m a. Monoid m => (a -> m) -> HashQualified a -> m
foldMap' :: forall m a. Monoid m => (a -> m) -> HashQualified a -> m
$cfoldr :: forall a b. (a -> b -> b) -> b -> HashQualified a -> b
foldr :: forall a b. (a -> b -> b) -> b -> HashQualified a -> b
$cfoldr' :: forall a b. (a -> b -> b) -> b -> HashQualified a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> HashQualified a -> b
$cfoldl :: forall b a. (b -> a -> b) -> b -> HashQualified a -> b
foldl :: forall b a. (b -> a -> b) -> b -> HashQualified a -> b
$cfoldl' :: forall b a. (b -> a -> b) -> b -> HashQualified a -> b
foldl' :: forall b a. (b -> a -> b) -> b -> HashQualified a -> b
$cfoldr1 :: forall a. (a -> a -> a) -> HashQualified a -> a
foldr1 :: forall a. (a -> a -> a) -> HashQualified a -> a
$cfoldl1 :: forall a. (a -> a -> a) -> HashQualified a -> a
foldl1 :: forall a. (a -> a -> a) -> HashQualified a -> a
$ctoList :: forall a. HashQualified a -> [a]
toList :: forall a. HashQualified a -> [a]
$cnull :: forall a. HashQualified a -> Bool
null :: forall a. HashQualified a -> Bool
$clength :: forall a. HashQualified a -> Int
length :: forall a. HashQualified a -> Int
$celem :: forall a. Eq a => a -> HashQualified a -> Bool
elem :: forall a. Eq a => a -> HashQualified a -> Bool
$cmaximum :: forall a. Ord a => HashQualified a -> a
maximum :: forall a. Ord a => HashQualified a -> a
$cminimum :: forall a. Ord a => HashQualified a -> a
minimum :: forall a. Ord a => HashQualified a -> a
$csum :: forall a. Num a => HashQualified a -> a
sum :: forall a. Num a => HashQualified a -> a
$cproduct :: forall a. Num a => HashQualified a -> a
product :: forall a. Num a => HashQualified a -> a
Foldable, Eq (HashQualified n)
Eq (HashQualified n) =>
(HashQualified n -> HashQualified n -> Ordering)
-> (HashQualified n -> HashQualified n -> Bool)
-> (HashQualified n -> HashQualified n -> Bool)
-> (HashQualified n -> HashQualified n -> Bool)
-> (HashQualified n -> HashQualified n -> Bool)
-> (HashQualified n -> HashQualified n -> HashQualified n)
-> (HashQualified n -> HashQualified n -> HashQualified n)
-> Ord (HashQualified n)
HashQualified n -> HashQualified n -> Bool
HashQualified n -> HashQualified n -> Ordering
HashQualified n -> HashQualified n -> HashQualified n
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall n. Ord n => Eq (HashQualified n)
forall n. Ord n => HashQualified n -> HashQualified n -> Bool
forall n. Ord n => HashQualified n -> HashQualified n -> Ordering
forall n.
Ord n =>
HashQualified n -> HashQualified n -> HashQualified n
$ccompare :: forall n. Ord n => HashQualified n -> HashQualified n -> Ordering
compare :: HashQualified n -> HashQualified n -> Ordering
$c< :: forall n. Ord n => HashQualified n -> HashQualified n -> Bool
< :: HashQualified n -> HashQualified n -> Bool
$c<= :: forall n. Ord n => HashQualified n -> HashQualified n -> Bool
<= :: HashQualified n -> HashQualified n -> Bool
$c> :: forall n. Ord n => HashQualified n -> HashQualified n -> Bool
> :: HashQualified n -> HashQualified n -> Bool
$c>= :: forall n. Ord n => HashQualified n -> HashQualified n -> Bool
>= :: HashQualified n -> HashQualified n -> Bool
$cmax :: forall n.
Ord n =>
HashQualified n -> HashQualified n -> HashQualified n
max :: HashQualified n -> HashQualified n -> HashQualified n
$cmin :: forall n.
Ord n =>
HashQualified n -> HashQualified n -> HashQualified n
min :: HashQualified n -> HashQualified n -> HashQualified n
Ord, Functor HashQualified
Foldable HashQualified
(Functor HashQualified, Foldable HashQualified) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> HashQualified a -> f (HashQualified b))
-> (forall (f :: * -> *) a.
    Applicative f =>
    HashQualified (f a) -> f (HashQualified a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> HashQualified a -> m (HashQualified b))
-> (forall (m :: * -> *) a.
    Monad m =>
    HashQualified (m a) -> m (HashQualified a))
-> Traversable HashQualified
forall (t :: * -> *).
(Functor t, Foldable t) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> t a -> f (t b))
-> (forall (f :: * -> *) a. Applicative f => t (f a) -> f (t a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> t a -> m (t b))
-> (forall (m :: * -> *) a. Monad m => t (m a) -> m (t a))
-> Traversable t
forall (m :: * -> *) a.
Monad m =>
HashQualified (m a) -> m (HashQualified a)
forall (f :: * -> *) a.
Applicative f =>
HashQualified (f a) -> f (HashQualified a)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> HashQualified a -> m (HashQualified b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> HashQualified a -> f (HashQualified b)
$ctraverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> HashQualified a -> f (HashQualified b)
traverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> HashQualified a -> f (HashQualified b)
$csequenceA :: forall (f :: * -> *) a.
Applicative f =>
HashQualified (f a) -> f (HashQualified a)
sequenceA :: forall (f :: * -> *) a.
Applicative f =>
HashQualified (f a) -> f (HashQualified a)
$cmapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> HashQualified a -> m (HashQualified b)
mapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> HashQualified a -> m (HashQualified b)
$csequence :: forall (m :: * -> *) a.
Monad m =>
HashQualified (m a) -> m (HashQualified a)
sequence :: forall (m :: * -> *) a.
Monad m =>
HashQualified (m a) -> m (HashQualified a)
Traversable, (forall a b. (a -> b) -> HashQualified a -> HashQualified b)
-> (forall a b. a -> HashQualified b -> HashQualified a)
-> Functor HashQualified
forall a b. a -> HashQualified b -> HashQualified a
forall a b. (a -> b) -> HashQualified a -> HashQualified b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> HashQualified a -> HashQualified b
fmap :: forall a b. (a -> b) -> HashQualified a -> HashQualified b
$c<$ :: forall a b. a -> HashQualified b -> HashQualified a
<$ :: forall a b. a -> HashQualified b -> HashQualified a
Functor, Int -> HashQualified n -> ShowS
[HashQualified n] -> ShowS
HashQualified n -> String
(Int -> HashQualified n -> ShowS)
-> (HashQualified n -> String)
-> ([HashQualified n] -> ShowS)
-> Show (HashQualified n)
forall n. Show n => Int -> HashQualified n -> ShowS
forall n. Show n => [HashQualified n] -> ShowS
forall n. Show n => HashQualified n -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall n. Show n => Int -> HashQualified n -> ShowS
showsPrec :: Int -> HashQualified n -> ShowS
$cshow :: forall n. Show n => HashQualified n -> String
show :: HashQualified n -> String
$cshowList :: forall n. Show n => [HashQualified n] -> ShowS
showList :: [HashQualified n] -> ShowS
Show, (forall x. HashQualified n -> Rep (HashQualified n) x)
-> (forall x. Rep (HashQualified n) x -> HashQualified n)
-> Generic (HashQualified n)
forall x. Rep (HashQualified n) x -> HashQualified n
forall x. HashQualified n -> Rep (HashQualified n) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall n x. Rep (HashQualified n) x -> HashQualified n
forall n x. HashQualified n -> Rep (HashQualified n) x
$cfrom :: forall n x. HashQualified n -> Rep (HashQualified n) x
from :: forall x. HashQualified n -> Rep (HashQualified n) x
$cto :: forall n x. Rep (HashQualified n) x -> HashQualified n
to :: forall x. Rep (HashQualified n) x -> HashQualified n
Generic)

asNameOnly :: HashQualified n -> Maybe n
asNameOnly :: forall n. HashQualified n -> Maybe n
asNameOnly = \case
  NameOnly n
n -> n -> Maybe n
forall a. a -> Maybe a
Just n
n
  HashQualified n
_ -> Maybe n
forall a. Maybe a
Nothing

stripNamespace :: Name -> HashQualified Name -> HashQualified Name
stripNamespace :: Name -> HashQualified Name -> HashQualified Name
stripNamespace Name
namespace HashQualified Name
hq = case HashQualified Name
hq of
  NameOnly Name
name -> Name -> HashQualified Name
forall n. n -> HashQualified n
NameOnly (Name -> HashQualified Name) -> Name -> HashQualified Name
forall a b. (a -> b) -> a -> b
$ Name -> Name
strip Name
name
  HashQualified Name
name ShortHash
sh -> Name -> ShortHash -> HashQualified Name
forall n. n -> ShortHash -> HashQualified n
HashQualified (Name -> Name
strip Name
name) ShortHash
sh
  HashQualified Name
ho -> HashQualified Name
ho
  where
    strip :: Name -> Name
strip Name
name =
      Name -> Maybe Name -> Name
forall a. a -> Maybe a -> a
fromMaybe Name
name (Maybe Name -> Name) -> Maybe Name -> Name
forall a b. (a -> b) -> a -> b
$ Name -> Name -> Maybe Name
Name.stripNamePrefix Name
namespace Name
name

toName :: HashQualified n -> Maybe n
toName :: forall n. HashQualified n -> Maybe n
toName = \case
  NameOnly n
name -> n -> Maybe n
forall a. a -> Maybe a
Just n
name
  HashQualified n
name ShortHash
_ -> n -> Maybe n
forall a. a -> Maybe a
Just n
name
  HashOnly ShortHash
_ -> Maybe n
forall a. Maybe a
Nothing

-- Sort the list of names by length of segments: smaller number of
-- segments is listed first. NameOnly < Hash qualified < Hash only
--
-- Examples:
--   [foo.bar.baz, bar.baz] -> [bar.baz, foo.bar.baz]
--   [#a29dj2k91, foo.bar.baz] -> [foo.bar.baz, #a29dj2k91]
--   [foo.bar#abc, foo.bar] -> [foo.bar, foo.bar#abc]
--   [.foo.bar, foo.bar] -> [foo.bar, .foo.bar]
sortByLength :: [HashQualified Name] -> [HashQualified Name]
sortByLength :: [HashQualified Name] -> [HashQualified Name]
sortByLength [HashQualified Name]
hs = (HashQualified Name -> (Int, Int))
-> [HashQualified Name] -> [HashQualified Name]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn HashQualified Name -> (Int, Int)
f [HashQualified Name]
hs
  where
    f :: HashQualified Name -> (Int, Int)
    f :: HashQualified Name -> (Int, Int)
f (NameOnly Name
n) = (NonEmpty NameSegment -> Int
forall a. NonEmpty a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Name -> NonEmpty NameSegment
Name.reverseSegments Name
n), Int
0)
    f (HashQualified Name
n ShortHash
_h) = (NonEmpty NameSegment -> Int
forall a. NonEmpty a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Name -> NonEmpty NameSegment
Name.reverseSegments Name
n), Int
1)
    f (HashOnly ShortHash
_h) = (Int
forall a. Bounded a => a
maxBound, Int
0)

hasName, hasHash :: HashQualified Name -> Bool
hasName :: HashQualified Name -> Bool
hasName = Maybe Name -> Bool
forall a. Maybe a -> Bool
isJust (Maybe Name -> Bool)
-> (HashQualified Name -> Maybe Name) -> HashQualified Name -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashQualified Name -> Maybe Name
forall n. HashQualified n -> Maybe n
toName
hasHash :: HashQualified Name -> Bool
hasHash = Maybe ShortHash -> Bool
forall a. Maybe a -> Bool
isJust (Maybe ShortHash -> Bool)
-> (HashQualified Name -> Maybe ShortHash)
-> HashQualified Name
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashQualified Name -> Maybe ShortHash
forall n. HashQualified n -> Maybe ShortHash
toHash

toHash :: HashQualified n -> Maybe ShortHash
toHash :: forall n. HashQualified n -> Maybe ShortHash
toHash = \case
  NameOnly n
_ -> Maybe ShortHash
forall a. Maybe a
Nothing
  HashQualified n
_ ShortHash
sh -> ShortHash -> Maybe ShortHash
forall a. a -> Maybe a
Just ShortHash
sh
  HashOnly ShortHash
sh -> ShortHash -> Maybe ShortHash
forall a. a -> Maybe a
Just ShortHash
sh

-- partial: assumes either a name or hash is provided (or both)
fromNameHash :: Maybe Name -> Maybe ShortHash -> HashQualified Name
fromNameHash :: Maybe Name -> Maybe ShortHash -> HashQualified Name
fromNameHash Maybe Name
n Maybe ShortHash
h = case Maybe Name
n of
  Just Name
name -> case Maybe ShortHash
h of
    Just ShortHash
hash -> Name -> ShortHash -> HashQualified Name
forall n. n -> ShortHash -> HashQualified n
HashQualified Name
name ShortHash
hash
    Maybe ShortHash
Nothing -> Name -> HashQualified Name
forall n. n -> HashQualified n
NameOnly Name
name
  Maybe Name
Nothing -> case Maybe ShortHash
h of
    Just ShortHash
hash -> ShortHash -> HashQualified Name
forall n. ShortHash -> HashQualified n
HashOnly ShortHash
hash
    Maybe ShortHash
Nothing -> String -> HashQualified Name
forall a. HasCallStack => String -> a
error String
"bad HQ construction"

take :: Int -> HashQualified n -> HashQualified n
take :: forall n. Int -> HashQualified n -> HashQualified n
take Int
i = \case
  n :: HashQualified n
n@(NameOnly n
_) -> HashQualified n
n
  HashOnly ShortHash
s -> ShortHash -> HashQualified n
forall n. ShortHash -> HashQualified n
HashOnly (Int -> ShortHash -> ShortHash
SH.shortenTo Int
i ShortHash
s)
  HashQualified n
n ShortHash
s -> if Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then n -> HashQualified n
forall n. n -> HashQualified n
NameOnly n
n else n -> ShortHash -> HashQualified n
forall n. n -> ShortHash -> HashQualified n
HashQualified n
n (Int -> ShortHash -> ShortHash
SH.shortenTo Int
i ShortHash
s)

toStringWith :: (n -> String) -> HashQualified n -> String
toStringWith :: forall n. (n -> String) -> HashQualified n -> String
toStringWith n -> String
f = Text -> String
Text.unpack (Text -> String)
-> (HashQualified n -> Text) -> HashQualified n -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n -> Text) -> HashQualified n -> Text
forall n. (n -> Text) -> HashQualified n -> Text
toTextWith (String -> Text
Text.pack (String -> Text) -> (n -> String) -> n -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. n -> String
f)

toTextWith :: (n -> Text) -> HashQualified n -> Text
toTextWith :: forall n. (n -> Text) -> HashQualified n -> Text
toTextWith n -> Text
f = \case
  NameOnly n
name -> n -> Text
f n
name
  HashQualified n
name ShortHash
hash -> n -> Text
f n
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ShortHash -> Text
SH.toText ShortHash
hash
  HashOnly ShortHash
hash -> ShortHash -> Text
SH.toText ShortHash
hash

-- Returns the full referent in the hash.  Use HQ.take to just get a prefix
fromNamedReferent :: n -> Referent -> HashQualified n
fromNamedReferent :: forall n. n -> Referent -> HashQualified n
fromNamedReferent n
n Referent
r = n -> ShortHash -> HashQualified n
forall n. n -> ShortHash -> HashQualified n
HashQualified n
n (Referent -> ShortHash
Referent.toShortHash Referent
r)

-- Returns the full reference in the hash.  Use HQ.take to just get a prefix
fromNamedReference :: n -> Reference -> HashQualified n
fromNamedReference :: forall n. n -> Reference -> HashQualified n
fromNamedReference n
n Reference
r = n -> ShortHash -> HashQualified n
forall n. n -> ShortHash -> HashQualified n
HashQualified n
n (Reference -> ShortHash
Reference.toShortHash Reference
r)

fromReferent :: Referent -> HashQualified Name
fromReferent :: Referent -> HashQualified Name
fromReferent = ShortHash -> HashQualified Name
forall n. ShortHash -> HashQualified n
HashOnly (ShortHash -> HashQualified Name)
-> (Referent -> ShortHash) -> Referent -> HashQualified Name
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Referent -> ShortHash
Referent.toShortHash

fromReference :: Reference -> HashQualified Name
fromReference :: Reference -> HashQualified Name
fromReference = ShortHash -> HashQualified Name
forall n. ShortHash -> HashQualified n
HashOnly (ShortHash -> HashQualified Name)
-> (Reference -> ShortHash) -> Reference -> HashQualified Name
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Reference -> ShortHash
Reference.toShortHash

fromPattern :: ConstructorReference -> HashQualified Name
fromPattern :: ConstructorReference -> HashQualified Name
fromPattern ConstructorReference
r = ShortHash -> HashQualified Name
forall n. ShortHash -> HashQualified n
HashOnly (ShortHash -> HashQualified Name)
-> ShortHash -> HashQualified Name
forall a b. (a -> b) -> a -> b
$ ConstructorReference -> ShortHash
ConstructorReference.toShortHash ConstructorReference
r

fromName :: n -> HashQualified n
fromName :: forall n. n -> HashQualified n
fromName = n -> HashQualified n
forall n. n -> HashQualified n
NameOnly

-- todo: find this logic elsewhere and replace with call to this
matchesNamedReferent :: Name -> Referent -> HashQualified Name -> Bool
matchesNamedReferent :: Name -> Referent -> HashQualified Name -> Bool
matchesNamedReferent Name
n Referent
r = \case
  NameOnly Name
n' -> Name
n' Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name
n
  HashOnly ShortHash
sh -> ShortHash
sh ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` Referent -> ShortHash
Referent.toShortHash Referent
r
  HashQualified Name
n' ShortHash
sh -> Name
n' Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name
n Bool -> Bool -> Bool
&& ShortHash
sh ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` Referent -> ShortHash
Referent.toShortHash Referent
r

matchesNamedReference :: Name -> Reference -> HashQualified Name -> Bool
matchesNamedReference :: Name -> Reference -> HashQualified Name -> Bool
matchesNamedReference Name
n Reference
r = \case
  NameOnly Name
n' -> Name
n' Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name
n
  HashOnly ShortHash
sh -> ShortHash
sh ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` Reference -> ShortHash
Reference.toShortHash Reference
r
  HashQualified Name
n' ShortHash
sh -> Name
n' Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name
n Bool -> Bool -> Bool
&& ShortHash
sh ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` Reference -> ShortHash
Reference.toShortHash Reference
r

-- Use `requalify hq . Referent.Ref` if you want to pass in a `Reference`.
requalify :: HashQualified Name -> Referent -> HashQualified Name
requalify :: HashQualified Name -> Referent -> HashQualified Name
requalify HashQualified Name
hq Referent
r = case HashQualified Name
hq of
  NameOnly Name
n -> Name -> Referent -> HashQualified Name
forall n. n -> Referent -> HashQualified n
fromNamedReferent Name
n Referent
r
  HashQualified Name
n ShortHash
_ -> Name -> Referent -> HashQualified Name
forall n. n -> Referent -> HashQualified n
fromNamedReferent Name
n Referent
r
  HashOnly ShortHash
_ -> Referent -> HashQualified Name
fromReferent Referent
r

-- | Like 'Name.searchBySuffix', but uses a hash-qualified name to search instead.
--
-- The name *and* the hash are used to determine whether something is an exact match. For example, in namespace
-- {foo#foo, hello.foo#bar}, searching for foo#bar will return the singleton set {hello.foo#bar}, because even though
-- there is an exact name match on foo, its hash doesn't match so we fall back to "suffix" matches. This probably isn't
-- a very important detail in practice, but the other possible implementation (do name-only search, *then* filter result
-- down to matching hashes) seems worse.
searchBySuffix :: forall ref. (Ord ref) => (ref -> ShortHash) -> HashQualified Name -> Relation Name ref -> Set ref
searchBySuffix :: forall ref.
Ord ref =>
(ref -> ShortHash)
-> HashQualified Name -> Relation Name ref -> Set ref
searchBySuffix ref -> ShortHash
refHash HashQualified Name
name0 Relation Name ref
rel =
  case HashQualified Name
name0 of
    NameOnly Name
name -> Name -> Relation Name ref -> Set ref
forall r. Ord r => Name -> Relation Name r -> Set r
Name.searchBySuffix Name
name Relation Name ref
rel
    HashQualified Name
name ShortHash
hash
      | Set ref -> Bool
forall a. Set a -> Bool
Set.null Set ref
exactMatches -> Set ref
suffixMatches
      | Bool
otherwise -> Set ref
exactMatches
      where
        exactMatches :: Set ref
        exactMatches :: Set ref
exactMatches =
          Set ref -> Set ref
keepMatchingHashes (Name -> Relation Name ref -> Set ref
forall a b. Ord a => a -> Relation a b -> Set b
Relation.lookupDom Name
name Relation Name ref
rel)

        suffixMatches :: Set ref
        suffixMatches :: Set ref
suffixMatches =
          Set ref -> Set ref
keepMatchingHashes ((Name -> Ordering) -> Relation Name ref -> Set ref
forall a b.
(Ord a, Ord b) =>
(a -> Ordering) -> Relation a b -> Set b
Relation.searchDom (Name -> Name -> Ordering
Name.compareSuffix Name
name) Relation Name ref
rel)

        keepMatchingHashes :: Set ref -> Set ref
        keepMatchingHashes :: Set ref -> Set ref
keepMatchingHashes =
          (ref -> Bool) -> Set ref -> Set ref
forall a. (a -> Bool) -> Set a -> Set a
Set.filter \ref
ref -> ShortHash
hash ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` ref -> ShortHash
refHash ref
ref
    HashOnly ShortHash
hash ->
      (Set ref -> ref -> Set Name -> Set ref)
-> Set ref -> Map ref (Set Name) -> Set ref
forall a k b. (a -> k -> b -> a) -> a -> Map k b -> a
Map.foldlWithKey'
        (\Set ref
acc ref
ref Set Name
_ -> if ShortHash
hash ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` ref -> ShortHash
refHash ref
ref then ref -> Set ref -> Set ref
forall a. Ord a => a -> Set a -> Set a
Set.insert ref
ref Set ref
acc else Set ref
acc)
        Set ref
forall a. Set a
Set.empty
        (Relation Name ref -> Map ref (Set Name)
forall a b. Relation a b -> Map b (Set a)
Relation.range Relation Name ref
rel)

-- | Like 'searchBySuffix', but also keeps the names around.
filterBySuffix ::
  forall ref.
  (Ord ref) =>
  (ref -> ShortHash) ->
  HashQualified Name ->
  Relation Name ref ->
  Relation Name ref
filterBySuffix :: forall ref.
Ord ref =>
(ref -> ShortHash)
-> HashQualified Name -> Relation Name ref -> Relation Name ref
filterBySuffix ref -> ShortHash
refHash HashQualified Name
name0 Relation Name ref
rel =
  case HashQualified Name
name0 of
    NameOnly Name
name -> Name -> Relation Name ref -> Relation Name ref
forall r. Ord r => Name -> Relation Name r -> Relation Name r
Name.filterBySuffix Name
name Relation Name ref
rel
    HashQualified Name
name ShortHash
hash
      | Relation Name ref -> Bool
forall a b. Relation a b -> Bool
Relation.null Relation Name ref
exactMatches -> Relation Name ref
suffixMatches
      | Bool
otherwise -> Relation Name ref
exactMatches
      where
        exactMatches :: Relation Name ref
        exactMatches :: Relation Name ref
exactMatches =
          Name -> Set ref -> Relation Name ref
matches Name
name (Name -> Relation Name ref -> Set ref
forall a b. Ord a => a -> Relation a b -> Set b
Relation.lookupDom Name
name Relation Name ref
rel)

        suffixMatches :: Relation Name ref
        suffixMatches :: Relation Name ref
suffixMatches =
          (Name -> Set ref -> Relation Name ref)
-> (Name -> Ordering) -> Relation Name ref -> Relation Name ref
forall a c b.
(Ord a, Monoid c) =>
(a -> Set b -> c) -> (a -> Ordering) -> Relation a b -> c
Relation.searchDomG Name -> Set ref -> Relation Name ref
matches (Name -> Name -> Ordering
Name.compareSuffix Name
name) Relation Name ref
rel

        matches :: Name -> Set ref -> Relation Name ref
        matches :: Name -> Set ref -> Relation Name ref
matches Name
name =
          (ref -> Bool) -> Set ref -> Set ref
forall a. (a -> Bool) -> Set a -> Set a
Set.filter (ShortHash -> ref -> Bool
hashMatches ShortHash
hash)
            (Set ref -> Set ref)
-> (Set ref -> Relation Name ref) -> Set ref -> Relation Name ref
forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Set ref -> Maybe (NESet ref)
forall a. Set a -> Maybe (NESet a)
Set.NonEmpty.nonEmptySet
            (Set ref -> Maybe (NESet ref))
-> (Maybe (NESet ref) -> Relation Name ref)
-> Set ref
-> Relation Name ref
forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Relation Name ref
-> (NESet ref -> Relation Name ref)
-> Maybe (NESet ref)
-> Relation Name ref
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Relation Name ref
forall a b. Relation a b
Relation.empty (Name -> NESet ref -> Relation Name ref
forall a b. a -> NESet b -> Relation a b
Relation.singletonSet Name
name)
    HashOnly ShortHash
hash ->
      (ref -> Bool) -> Relation Name ref -> Relation Name ref
forall a b.
(Ord a, Ord b) =>
(b -> Bool) -> Relation a b -> Relation a b
Relation.filterRan (ShortHash -> ref -> Bool
hashMatches ShortHash
hash) Relation Name ref
rel
  where
    hashMatches :: ShortHash -> ref -> Bool
    hashMatches :: ShortHash -> ref -> Bool
hashMatches ShortHash
hash ref
ref =
      ShortHash
hash ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` ref -> ShortHash
refHash ref
ref

instance (Name.Alphabetical n) => Name.Alphabetical (HashQualified n) where
  -- Ordered alphabetically, based on the name. Hashes come last.
  compareAlphabetical :: HashQualified n -> HashQualified n -> Ordering
compareAlphabetical HashQualified n
a HashQualified n
b =
    case (HashQualified n -> Maybe n
forall n. HashQualified n -> Maybe n
toName HashQualified n
a, HashQualified n -> Maybe n
forall n. HashQualified n -> Maybe n
toName HashQualified n
b) of
      (Just n
n, Just n
n2) -> n -> n -> Ordering
forall n. Alphabetical n => n -> n -> Ordering
Name.compareAlphabetical n
n n
n2
      (Maybe n
Nothing, Just n
_) -> Ordering
GT
      (Just n
_, Maybe n
Nothing) -> Ordering
LT
      (Maybe n
Nothing, Maybe n
Nothing) -> Ordering
EQ
      Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> case (HashQualified n -> Maybe ShortHash
forall n. HashQualified n -> Maybe ShortHash
toHash HashQualified n
a, HashQualified n -> Maybe ShortHash
forall n. HashQualified n -> Maybe ShortHash
toHash HashQualified n
b) of
        (Maybe ShortHash
Nothing, Maybe ShortHash
Nothing) -> Ordering
EQ
        (Maybe ShortHash
Nothing, Just ShortHash
_) -> Ordering
LT -- prefer NameOnly to HashQualified
        (Just ShortHash
_, Maybe ShortHash
Nothing) -> Ordering
GT
        (Just ShortHash
sh, Just ShortHash
sh2) -> ShortHash -> ShortHash -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ShortHash
sh ShortHash
sh2