// Copyright 2025 International Digital Economy Academy
//
// 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.
///|
#cfg(not(platform="windows"))
#borrow(major, minor, fix)
extern "C" fn load_openssl_ffi(
major : Ref[Int],
minor : Ref[Int],
fix : Ref[Int],
) -> Int = "moonbitlang_async_load_openssl"
///|
#cfg(not(platform="windows"))
extern "C" fn init_bio_method(
read : FuncRef[(BIO, @c_buffer.Buffer, Int) -> Int],
write : FuncRef[(BIO, @c_buffer.Buffer, Int) -> Int],
) = "moonbitlang_async_init_bio_method"
///|
/// Lazily load OpenSSL on first use, so a program that never touches TLS pays
/// nothing. Every raw-symbol FFI wrapper calls this first; all other FFI runs on
/// handles those produce, so it is transitively covered. The outcome is cached →
/// success makes repeat calls free, failure re-raises the same error immediately.
#cfg(not(platform="windows"))
let load_openssl_result : Lazy[Result[Unit, Error]] = Lazy(() => {
let major = Ref(0)
let minor = Ref(0)
let fix = Ref(0)
match load_openssl_ffi(major, minor, fix) {
0 => ()
1 => return Err(TlsError("failed to load OpenSSL"))
2 => return Err(TlsError("failed to get OpenSSL version"))
3 =>
return Err(
TlsError(
"unsupported OpenSSL version \{major.val}.\{minor.val}.\{fix.val}",
),
)
4 => return Err(TlsError("failed to load some OpenSSL function"))
_ => panic()
}
init_bio_method((bio, dst, len) => bio.read(dst, len)) <| ((bio, src, len) => {
bio.write(src, len)
})
Ok(())
})
///|
#cfg(not(platform="windows"))
fn load_openssl() -> Unit raise {
load_openssl_result.force().unwrap_or_error()
}