module Unison.UnconflictedLocalDefnsView
  ( UnconflictedLocalDefnsView (..),
    Unison.UnconflictedLocalDefnsView.empty,
    fromDefns,
  )
where

import Data.Map.Strict qualified as Map
import Unison.Name (Name)
import Unison.NameSegment (NameSegment)
import Unison.Names (Names (..))
import Unison.Names qualified as Names
import Unison.Prelude
import Unison.Reference (TypeReference)
import Unison.Referent (Referent)
import Unison.Util.BiMultimap (BiMultimap)
import Unison.Util.BiMultimap qualified as BiMultimap
import Unison.Util.Defns (Defns (..), DefnsF)
import Unison.Util.Nametree (Nametree (..), unflattenNametrees)

-- | A view of a namespace's dsefinition (everything outside of `lib`) that is unconflicted: each name refers to one
-- thing. The data contained within is all just different expressions of the same contents, for various use cases. The
-- intention is to use laziness to avoid recomputing data structures whenever possible.
data UnconflictedLocalDefnsView = UnconflictedLocalDefnsView
  { UnconflictedLocalDefnsView
-> Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)
defns :: Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name),
    UnconflictedLocalDefnsView
-> Nametree (DefnsF (Map NameSegment) Referent TypeReference)
nametree :: Nametree (DefnsF (Map NameSegment) Referent TypeReference),
    UnconflictedLocalDefnsView -> Names
names :: Names
  }
  deriving stock ((forall x.
 UnconflictedLocalDefnsView -> Rep UnconflictedLocalDefnsView x)
-> (forall x.
    Rep UnconflictedLocalDefnsView x -> UnconflictedLocalDefnsView)
-> Generic UnconflictedLocalDefnsView
forall x.
Rep UnconflictedLocalDefnsView x -> UnconflictedLocalDefnsView
forall x.
UnconflictedLocalDefnsView -> Rep UnconflictedLocalDefnsView x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x.
UnconflictedLocalDefnsView -> Rep UnconflictedLocalDefnsView x
from :: forall x.
UnconflictedLocalDefnsView -> Rep UnconflictedLocalDefnsView x
$cto :: forall x.
Rep UnconflictedLocalDefnsView x -> UnconflictedLocalDefnsView
to :: forall x.
Rep UnconflictedLocalDefnsView x -> UnconflictedLocalDefnsView
Generic, Int -> UnconflictedLocalDefnsView -> ShowS
[UnconflictedLocalDefnsView] -> ShowS
UnconflictedLocalDefnsView -> String
(Int -> UnconflictedLocalDefnsView -> ShowS)
-> (UnconflictedLocalDefnsView -> String)
-> ([UnconflictedLocalDefnsView] -> ShowS)
-> Show UnconflictedLocalDefnsView
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> UnconflictedLocalDefnsView -> ShowS
showsPrec :: Int -> UnconflictedLocalDefnsView -> ShowS
$cshow :: UnconflictedLocalDefnsView -> String
show :: UnconflictedLocalDefnsView -> String
$cshowList :: [UnconflictedLocalDefnsView] -> ShowS
showList :: [UnconflictedLocalDefnsView] -> ShowS
Show)

empty :: UnconflictedLocalDefnsView
empty :: UnconflictedLocalDefnsView
empty =
  UnconflictedLocalDefnsView
    { $sel:defns:UnconflictedLocalDefnsView :: Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)
defns = BiMultimap Referent Name
-> BiMultimap TypeReference Name
-> Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)
forall terms types. terms -> types -> Defns terms types
Defns BiMultimap Referent Name
forall a b. (Ord a, Ord b) => BiMultimap a b
BiMultimap.empty BiMultimap TypeReference Name
forall a b. (Ord a, Ord b) => BiMultimap a b
BiMultimap.empty,
      $sel:nametree:UnconflictedLocalDefnsView :: Nametree (DefnsF (Map NameSegment) Referent TypeReference)
nametree = DefnsF (Map NameSegment) Referent TypeReference
-> Map
     NameSegment
     (Nametree (DefnsF (Map NameSegment) Referent TypeReference))
-> Nametree (DefnsF (Map NameSegment) Referent TypeReference)
forall a. a -> Map NameSegment (Nametree a) -> Nametree a
Nametree (Map NameSegment Referent
-> Map NameSegment TypeReference
-> DefnsF (Map NameSegment) Referent TypeReference
forall terms types. terms -> types -> Defns terms types
Defns Map NameSegment Referent
forall k a. Map k a
Map.empty Map NameSegment TypeReference
forall k a. Map k a
Map.empty) Map
  NameSegment
  (Nametree (DefnsF (Map NameSegment) Referent TypeReference))
forall k a. Map k a
Map.empty,
      $sel:names:UnconflictedLocalDefnsView :: Names
names = Names
Names.empty
    }

fromDefns :: DefnsF (Map Name) Referent TypeReference -> UnconflictedLocalDefnsView
fromDefns :: DefnsF (Map Name) Referent TypeReference
-> UnconflictedLocalDefnsView
fromDefns DefnsF (Map Name) Referent TypeReference
defns0 =
  UnconflictedLocalDefnsView
    { $sel:defns:UnconflictedLocalDefnsView :: Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)
defns = (Map Name Referent -> BiMultimap Referent Name)
-> (Map Name TypeReference -> BiMultimap TypeReference Name)
-> DefnsF (Map Name) Referent TypeReference
-> Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)
forall a b c d. (a -> b) -> (c -> d) -> Defns a c -> Defns b d
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap Map Name Referent -> BiMultimap Referent Name
forall a b. (Ord a, Ord b) => Map b a -> BiMultimap a b
BiMultimap.fromRange Map Name TypeReference -> BiMultimap TypeReference Name
forall a b. (Ord a, Ord b) => Map b a -> BiMultimap a b
BiMultimap.fromRange DefnsF (Map Name) Referent TypeReference
defns0,
      $sel:nametree:UnconflictedLocalDefnsView :: Nametree (DefnsF (Map NameSegment) Referent TypeReference)
nametree = DefnsF (Map Name) Referent TypeReference
-> Nametree (DefnsF (Map NameSegment) Referent TypeReference)
forall term typ.
(Ord term, Ord typ) =>
DefnsF (Map Name) term typ
-> Nametree (DefnsF (Map NameSegment) term typ)
unflattenNametrees DefnsF (Map Name) Referent TypeReference
defns0,
      $sel:names:UnconflictedLocalDefnsView :: Names
names = Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)
-> Names
Names.fromUnconflictedRelation Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)
defns
    }
  where
    defns :: Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)
    defns :: Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)
defns =
      (Map Name Referent -> BiMultimap Referent Name)
-> (Map Name TypeReference -> BiMultimap TypeReference Name)
-> DefnsF (Map Name) Referent TypeReference
-> Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)
forall a b c d. (a -> b) -> (c -> d) -> Defns a c -> Defns b d
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap Map Name Referent -> BiMultimap Referent Name
forall a b. (Ord a, Ord b) => Map b a -> BiMultimap a b
BiMultimap.fromRange Map Name TypeReference -> BiMultimap TypeReference Name
forall a b. (Ord a, Ord b) => Map b a -> BiMultimap a b
BiMultimap.fromRange DefnsF (Map Name) Referent TypeReference
defns0