/*
* 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.net.tls
import std.sync.*
import stdx.net.tls.common.TlsException
/**
* Simple concurrent-safe lazy impl. The provided builder in "configure" may
* be invoked multiple times but it is guaranteed that only one instance wins.
*/
struct Lazy<T> {
private let holder: AtomicReference<LazyState<T>>
init(producer: () -> T) {
holder = AtomicReference(Producer<T>(producer))
}
init() {
holder = AtomicReference(Uninitialized<T>())
}
prop value: T {
get() {
compute()
}
}
func set(v: T): Unit {
holder.store(HasValue<T>(v))
}
func configure(producer: () -> T) {
match (holder.load()) {
case empty: Uninitialized<T> =>
if (holder.compareAndSwap(empty, Producer<T>(producer))) {
return
}
case _ => ()
}
throw TlsException("Lazy is already configured")
}
private func compute(): T {
do {
match (holder.load()) {
case box: HasValue<T> => return box.value
case start: Producer<T> =>
let box = start.create()
if (holder.compareAndSwap(start, box)) {
return box.value
}
case _: Uninitialized<T> => throw TlsException(
"This lazy is not yet initialized. Invoke configure first.")
case _ => break // workaround compiler bug
}
} while (true)
throw TlsException("should never reach here.")
}
}
abstract class LazyState<T> {}
class Uninitialized<T> <: LazyState<T> {}
class Producer<T> <: LazyState<T> {
Producer(private let producer: () -> T) {}
func create(): HasValue<T> {
HasValue<T>(producer())
}
}
class HasValue<T> <: LazyState<T> {
HasValue(let value: T) {}
}