Coverage for greyhorse / app / resources / scoped.py: 100%
35 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-19 00:48 +0300
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-19 00:48 +0300
1from __future__ import annotations
3from collections.abc import Callable
5from greyhorse.monads.effect import ExitCase
6from greyhorse.monads.io import IO
7from greyhorse.monads.resource import Resource
8from greyhorse.result import Result
10from .slot import ConsumerSlot, ProviderAccessError, ProviderMutAccessError
13class SlotBackedScopedProvider[T]:
14 __slots__ = ('_slot',)
16 def __init__(self, slot: ConsumerSlot[T]) -> None:
17 self._slot = slot
19 def open(self) -> Resource[IO, Result[T, ProviderAccessError]]:
20 slot = self._slot
22 def acquire() -> Result[T, ProviderAccessError]:
23 return slot.try_enter_shared()
25 def release(result: Result[T, ProviderAccessError], ec: ExitCase) -> None:
26 if result.is_ok():
27 slot.exit_shared()
29 return Resource[IO, Result[T, ProviderAccessError]].make_case(
30 acquire=IO(acquire), release=lambda v, ec: IO(lambda: release(v, ec))
31 )
33 def use[R](self, fn: Callable[[T], R]) -> IO[Result[R, ProviderAccessError]]:
34 return self.open().use(lambda result: IO.pure(result.map(fn)))
37class SlotBackedScopedMutProvider[T]:
38 __slots__ = ('_slot',)
40 def __init__(self, slot: ConsumerSlot[T]) -> None:
41 self._slot = slot
43 def open_mut(self) -> Resource[IO, Result[T, ProviderMutAccessError]]:
44 slot = self._slot
46 def acquire() -> Result[T, ProviderMutAccessError]:
47 return slot.try_enter_mut()
49 def release(result: Result[T, ProviderMutAccessError], ec: ExitCase) -> None:
50 if result.is_ok():
51 slot.exit_mut()
53 return Resource[IO, Result[T, ProviderMutAccessError]].make_case(
54 acquire=IO(acquire), release=lambda v, ec: IO(lambda: release(v, ec))
55 )
57 def use_mut[R](self, fn: Callable[[T], R]) -> IO[Result[R, ProviderMutAccessError]]:
58 return self.open_mut().use(lambda result: IO.pure(result.map(fn)))