From 25f00dfbf4655b53ba99c6bba74e6c8ad28d8b50 Mon Sep 17 00:00:00 2001
From: Jens Nolte <git@queezle.net>
Date: Wed, 15 Dec 2021 06:27:29 +0100
Subject: [PATCH] Implement object lookup

---
 src/Quasar/Wayland/Protocol/Core.hs | 42 ++++++++++++++++++++++++++---
 1 file changed, 38 insertions(+), 4 deletions(-)

diff --git a/src/Quasar/Wayland/Protocol/Core.hs b/src/Quasar/Wayland/Protocol/Core.hs
index 509cf03..2650d89 100644
--- a/src/Quasar/Wayland/Protocol/Core.hs
+++ b/src/Quasar/Wayland/Protocol/Core.hs
@@ -41,6 +41,7 @@ module Quasar.Wayland.Protocol.Core (
   newObject,
   newObjectFromId,
   getObject,
+  lookupObject,
 
   -- * Protocol exceptions
   WireCallbackFailed(..),
@@ -70,6 +71,7 @@ import Data.HashMap.Strict (HashMap)
 import Data.HashMap.Strict qualified as HM
 import Data.Proxy
 import Data.String (IsString(..))
+import Data.Typeable (Typeable, cast)
 import Data.Void (absurd)
 import GHC.Conc (unsafeIOToSTM)
 import GHC.TypeLits
@@ -183,7 +185,8 @@ instance WireFormat Void where
 class (
     IsMessage (WireRequest i),
     IsMessage (WireEvent i),
-    KnownSymbol (InterfaceName i)
+    KnownSymbol (InterfaceName i),
+    Typeable i
   )
   => IsInterface i where
   type RequestHandler i
@@ -195,7 +198,7 @@ class (
 interfaceName :: forall i. IsInterface i => String
 interfaceName = symbolVal @(InterfaceName i) Proxy
 
-class IsSide (s :: Side) where
+class Typeable s => IsSide (s :: Side) where
   type MessageHandler s i
   type WireUp s i
   type WireDown s i
@@ -241,6 +244,7 @@ class IsInterfaceSide s i => IsInterfaceHandler s i a where
 
 -- | Data kind
 data Side = Client | Server
+  deriving stock (Eq, Show, Typeable)
 
 
 -- | An object belonging to a wayland connection.
@@ -249,6 +253,8 @@ data Object s i = IsInterfaceSide s i => Object {
   objectId :: ObjectId (InterfaceName i),
   messageHandler :: TVar (Maybe (MessageHandler s i))
 }
+  deriving stock Typeable
+
 
 getMessageHandler :: Object s i -> STM (MessageHandler s i)
 getMessageHandler object = maybe retry pure =<< readTVar object.messageHandler
@@ -359,6 +365,10 @@ data ServerError = ServerError Word32 String
   deriving stock Show
   deriving anyclass Exception
 
+data InvalidObject = InvalidObject String
+  deriving stock Show
+  deriving anyclass Exception
+
 -- * Protocol state and monad plumbing
 
 -- | Top-level protocol handle (used e.g. to send/receive data)
@@ -550,11 +560,35 @@ newObjectFromId messageHandler (NewId oId) = do
   pure object
 
 
+fromSomeObject
+  :: forall s i m. IsInterfaceSide s i
+  => SomeObject s -> Either String (Object s i)
+fromSomeObject (UnknownObject interface _) =
+  Left $ mconcat ["Object is of unknown interface ", interface]
+fromSomeObject (SomeObject someObject) =
+  case cast someObject of
+    Nothing -> Left $ mconcat ["Expected object for interface ", interfaceName @i, ", but object is ", objectInterfaceName someObject]
+    Just object -> pure object
+
+
+lookupObject
+  :: forall s i. IsInterfaceSide s i
+  => ObjectId (InterfaceName i)
+  -> ProtocolM s (Either String (Object s i))
+lookupObject oId = do
+  objects <- readProtocolVar (.objectsVar)
+  pure case HM.lookup (toGenericObjectId oId) objects of
+    Nothing -> Left $ mconcat ["No object with id ", show oId, " is registered"]
+    Just someObject ->
+      case fromSomeObject someObject of
+        Left err -> Left err
+        Right object -> pure object
+
 getObject
-  :: IsInterfaceSide s i
+  :: forall s i. IsInterfaceSide s i
   => ObjectId (InterfaceName i)
   -> ProtocolM s (Object s i)
-getObject = undefined
+getObject oId = either (throwM . InvalidObject) pure =<< lookupObject oId
 
 
 
-- 
GitLab