package nova.monadic_sfx.util import monix.bio.Task import monix.bio.UIO import monix.catnap.MVar /** * Synchronization wrapper for a mutable object * * @param obj the mutable object * @param lock lock for synchronization */ class SynchedObject[A](obj: A, lock: MLock) { def modify(f: A => Task[Unit]): Task[Unit] = lock.greenLight(f(obj)) def get: Task[A] = lock.greenLight(Task(obj)) } object SynchedObject { def apply[A](obj: A) = MVar[Task] .of(()) .map(m => new MLock(m)) .flatMap(lock => Task(new SynchedObject(obj, lock))) } final class MLock(mvar: MVar[Task, Unit]) { def acquire: Task[Unit] = mvar.take def release: Task[Unit] = mvar.put(()) def greenLight[A](fa: Task[A]): Task[A] = for { _ <- acquire a <- fa.doOnCancel( release.onErrorHandleWith(ex => UIO(println(ex.getMessage()))) ) _ <- release } yield a }