diff options
| author | Hannes Schulze <haschu0103@outlook.de> | 2026-03-08 17:27:51 +0100 |
|---|---|---|
| committer | Hannes Schulze <haschu0103@outlook.de> | 2026-03-08 17:27:51 +0100 |
| commit | 658b74715751cb4b52b2a968325ece9a62a29fc3 (patch) | |
| tree | 9a831619b58a4ea0a56968f4a6a5d1c9a3422f2c | |
| parent | 56c5078463e5f9131dfa073b127e8a9c7c73e05f (diff) | |
display monad
| -rw-r--r-- | lib/Wayland.lean | 1 | ||||
| -rw-r--r-- | lib/Wayland/Display.lean | 115 | ||||
| -rw-r--r-- | src/Waylean.lean | 36 |
3 files changed, 134 insertions, 18 deletions
diff --git a/lib/Wayland.lean b/lib/Wayland.lean index 16f5c4c..8dd49c8 100644 --- a/lib/Wayland.lean +++ b/lib/Wayland.lean @@ -1 +1,2 @@ import Wayland.Native +import Wayland.Display diff --git a/lib/Wayland/Display.lean b/lib/Wayland/Display.lean new file mode 100644 index 0000000..18a05fa --- /dev/null +++ b/lib/Wayland/Display.lean @@ -0,0 +1,115 @@ +import Wayland.Native + +namespace Wayland + +def EventSource := Native.EventSource + +structure PosixSignal where + private signum : UInt32 + deriving Repr, BEq, Inhabited + +def PosixSignal.SIGINT : PosixSignal := ⟨Native.SIGINT⟩ +def PosixSignal.SIGUSR1 : PosixSignal := ⟨Native.SIGUSR1⟩ +def PosixSignal.SIGUSR2 : PosixSignal := ⟨Native.SIGUSR2⟩ + +structure Duration where + private milliseconds : UInt32 + deriving Repr, BEq, Inhabited + +def Duration.ofMilliseconds (val : UInt32) : Duration := ⟨val⟩ +def Duration.ofSeconds (val : UInt32) : Duration := .ofMilliseconds (val * 1000) +def Duration.ofMinutes (val : UInt32) : Duration := .ofSeconds (val * 60) + +def Duration.toMilliseconds (val : Duration) : UInt32 := val.milliseconds +def Duration.toSeconds (val : Duration) : UInt32 := val.toMilliseconds / 1000 +def Duration.toMinutes (val : Duration) : UInt32 := val.toSeconds / 60 + +notation:2000 val "ms" => Duration.ofMilliseconds val +notation:2000 val "sec" => Duration.ofSeconds val +notation:2000 val "min" => Duration.ofMinutes val + +structure Lens (O I : Type) where + get : O → I + set : I → O → O + +macro "mk_lens " field:ident : term => do + let lvalNode := Lean.mkNode `Lean.Parser.Term.structInstLVal #[field.raw, Lean.mkNullNode #[]] + let lval : Lean.TSyntax `Lean.Parser.Term.structInstLVal := ⟨lvalNode⟩ + `({ get := fun x => x.$field, set := fun i x => { x with $lval := i } }) + +abbrev Handler (σ : Type) := StateT σ IO Unit + +structure Display (σ : Type) where + disp : Native.Display + addTimer : (delayMs : UInt32) → (msg : Handler σ) → IO EventSource + addSignal : (signum : UInt32) → (msg : Handler σ) → IO EventSource + remove : (source : EventSource) → IO Unit + quit : IO Unit + +variable {σ α : Type} + +def DisplayM (σ : Type) : Type → Type := + ReaderT (Display σ) (StateT σ IO) + +deriving instance Monad for DisplayM σ +deriving instance MonadState σ for DisplayM σ + +private instance : MonadLift (ReaderT (Display σ) (StateT σ IO)) (DisplayM σ) where + monadLift := id + +partial def DisplayM.run' (setUp : DisplayM σ Unit) (initialState : σ) (name : Option String := .none) : IO σ := do + let disp ← Native.Display.new name + let loop ← Native.EventLoop.new + _ ← loop.addDisplay disp + let global : Display σ := + { disp := disp + addTimer := loop.addTimer + addSignal := loop.addSignal + remove := loop.remove + quit := loop.quit } + let rec inner : StateT σ IO Unit := do + match (← loop.poll) with + | .none => return + | .some msg => msg; inner + let main : StateT σ IO Unit := do + setUp.run global + inner + main.run initialState |>.map Prod.snd + +def DisplayM.run (setUp : DisplayM σ Unit) (initialState : σ) (name : Option String := .none) : IO Unit := + DisplayM.run' setUp initialState (name := name) |> discard + +def DisplayM.liftIO (io : IO α) : DisplayM σ α := + io + +def DisplayM.requestQuit : DisplayM σ Unit := do + (← read).quit + +def DisplayM.registerSignal (signal : PosixSignal) (handler : DisplayM σ Unit) : DisplayM σ EventSource := do + let global ← read + global.addSignal signal.signum (ReaderT.run handler global) + +def DisplayM.registerTimer (timeout : Duration) (handler : DisplayM σ Unit) : DisplayM σ EventSource := do + let global ← read + global.addTimer timeout.toMilliseconds (ReaderT.run handler global) + +def DisplayM.unregister (source : EventSource) : DisplayM σ Unit := do + (← read).remove source + +private def zoomState {σ₁ σ₂ : Type} {m : Type → Type} [Monad m] (lens : Lens σ₁ σ₂) (inner : StateT σ₂ m α) : StateT σ₁ m α := do + let oldOuter ← get + let (res, newInner) ← inner.run (lens.get oldOuter) + set (lens.set newInner oldOuter) + return res + +def DisplayM.zoom {σ₁ σ₂ : Type} (lens : Lens σ₁ σ₂) (inner : DisplayM σ₂ α) : DisplayM σ₁ α := do + let global₁ : Display σ₁ ← read + let global₂ : Display σ₂ := + { disp := global₁.disp + addTimer := fun x y ↦ global₁.addTimer x (zoomState lens y) + addSignal := fun x y ↦ global₁.addSignal x (zoomState lens y) + remove := global₁.remove + quit := global₁.quit } + zoomState lens (ReaderT.run inner global₂) + +end Wayland diff --git a/src/Waylean.lean b/src/Waylean.lean index a13b867..354b609 100644 --- a/src/Waylean.lean +++ b/src/Waylean.lean @@ -1,21 +1,21 @@ import Wayland -open Wayland.Native +open Wayland -partial def mainLoop (loop : EventLoop (IO Unit)) : IO Unit := do - match (← loop.poll) with - | .none => return - | .some msg => msg; mainLoop loop +structure State where + count : Int -partial def main : IO Unit := do - let disp : Display ← Display.new .none - let loop : EventLoop (IO Unit) ← EventLoop.new - _ ← loop.addDisplay disp - _ ← loop.addSignal SIGINT (do - IO.println "Received SIGINT" - loop.quit) - let rec setUpTimer := loop.addTimer 500 (do - IO.println "Timer tick" - _ ← setUpTimer) - _ ← setUpTimer - disp.roundtrip - mainLoop loop +partial def nextTimer : DisplayM Int Unit := do + _ ← DisplayM.registerTimer 16ms do + let newCount := (← get) + 1 + set newCount + DisplayM.liftIO (IO.println s!"Timer tick {newCount}") + nextTimer + +def launch : DisplayM State Unit := do + _ ← DisplayM.registerSignal .SIGINT do + DisplayM.liftIO (IO.println "Received SIGINT") + DisplayM.requestQuit + DisplayM.zoom (mk_lens count) nextTimer + +def main : IO Unit := + DisplayM.run launch { count := 0 } |
