All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aquascape.stack.scala Maven / Gradle / Ivy

/*
 * Copyright 2023 Zainab Ali
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package aquascape

import cats.*
import cats.effect.MonadCancelThrow
import cats.effect.Ref
import cats.syntax.all.*
import fs2.*

type Branch = String

opaque type Stack[F[_]] = Ref[F, Map[Branch, List[Label]]]
extension [F[_]: MonadCancelThrow](stack: Stack[F]) {
  private[aquascape] def bracketF[A](branch: Branch, child: Label)(
      fa: F[A]
  ): F[A] =
    summon[MonadCancelThrow[F]].bracket(
      stack.update { bs =>
        bs.get(branch).fold(bs) { case xs =>
          bs + ((branch, (child :: xs)))
        }
      }
    )(_ => fa)(_ =>
      stack.update { bs =>
        bs.get(branch).fold(bs) { case xs =>
          bs + ((branch, (xs.tail)))
        }
      }
    )
  private[aquascape] def newRoot(root: Branch): F[Unit] = {
    stack.update { bs => bs + ((root, Nil)) }
  }

  private[aquascape] def forkTS(parent: Branch, child: Branch): F[Unit] = {
    val updateOrError = stack.modify { bs =>
      bs.get(parent) match {
        case None => (bs, Some(ParentBranchNotFound(parent, child)))
        case Some(parentLabels) => (bs + ((child, parentLabels)), None)
      }
    }
    updateOrError.flatMap {
      case Some(err) => err.raiseError
      case None      => ().pure
    }
  }

  private[aquascape] def peek(branch: Branch): F[List[Label]] = {
    stack.get.map(_.getOrElse(branch, Nil))
  }

  private[aquascape] def bracket[O, A](branch: Branch, child: Label)(
      fa: Pull[F, O, A]
  ): Pull[F, O, A] =
    Pull.bracketCase(
      acquire = Pull.eval(
        stack.update { bs =>
          bs.get(branch).fold(bs) { case xs =>
            bs + ((branch, (child :: xs)))
          }
        }
      ),
      use = _ => fa,
      release = (_, _) =>
        Pull.eval(
          stack.update { bs =>
            bs.get(branch).fold(bs) { case xs =>
              bs + ((branch, (xs.tail)))
            }
          }
        )
    )
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy