/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* This source file is part of the Cangjie project, licensed under Apache-2.0
* with Runtime Library Exception.
*
* See https://cangjie-lang.cn/pages/LICENSE for license information.
*/
package stdx.effect
class FrameBox {
var ref: Option<HandlerFrame>
init() {
this.ref = None
}
}
abstract class HandlerCase {
protected open func tryHandle<R1>(cmd: Command<R1>, box!: FrameBox): Option<R1>
}
// This class represents the possible returns of an immediate handler
enum ImmediateHandlerReturn<T> {
Result(T)
| Exc(Exception)
| Err(Error)
}
abstract class HandlerFrame {
static let ACTIVE_FRAME_KEY = ThreadLocal<FrameBox>()
public static func getActiveFrameBox(): FrameBox {
match (ACTIVE_FRAME_KEY.get()) {
case Some(box) => box
case None =>
let newBox = FrameBox()
ACTIVE_FRAME_KEY.set(newBox)
newBox
}
}
public static func getActiveFrame(): Option<HandlerFrame> {
getActiveFrameBox().ref
}
static func setActiveFrame(f: Option<HandlerFrame>) {
getActiveFrameBox().ref = f
}
var handlers = Array<HandlerCase>()
var parent: Option<HandlerFrame> = None
var finalizer: () -> Unit = {=>}
public func setFinally(finalizer: () -> Unit): Unit {
this.finalizer = finalizer
}
func addHandlerCase(h: HandlerCase) {
this.handlers = Array<HandlerCase>(this.handlers.size + 1) {
i => if (i == 0) {
h
} else {
this.handlers[i - 1]
}
}
}
public func setImmediateHandler<Cmd, Res, Ret>(h: (Cmd) -> ImmediateHandlerReturn<Res>): Unit {
this.addHandlerCase(ImmediateHandlerCase<Cmd, Res, Ret>(this, h))
}
public static func perf<Cmd, Res>(cmd: Cmd): Res where Cmd <: Command<Res> {
let mainBox = getActiveFrameBox()
var maybeFrame = getActiveFrame()
while (let Some(frame) <- maybeFrame) {
for (i in 0..frame.handlers.size) {
if (let Some(result) <- frame.handlers[i].tryHandle(cmd, box: mainBox)) {
return result
}
}
maybeFrame = frame.parent
}
cmd.defaultImpl()
}
}