// Copyright 2026 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.

///|
/// Unsafely extracts a pointer from any value.
///
/// **Warning**: This is an unsafe operation that should be used with extreme caution.
/// The value is not consumed, and using the pointer may lead to undefined behavior
/// if the value is moved or deallocated.
///
/// Parameters:
///
/// - `value`: The value to extract a pointer from
///
/// Returns a `Pointer[Unit]` pointing to the value's memory location.
#as_free_fn
pub fn[T] Pointer::unsafe_from(value : T) -> Pointer[Unit] = "%identity"

///|
/// Extracts a pointer from a reference.
///
/// Parameters:
///
/// - `value`: The reference to extract a pointer from
///
/// Returns a `Pointer[T]` pointing to the referenced value.
#as_free_fn
pub fn[T] Pointer::unsafe_from_ref(value : Ref[T]) -> Pointer[T] = "%identity"

///|
/// Extracts a pointer from a fixed array.
///
/// Parameters:
///
/// - `value`: The fixed array to extract a pointer from
///
/// Returns a `Pointer[T]` pointing to the first element of the array.
#as_free_fn
pub fn[T] Pointer::unsafe_from_array(value : FixedArray[T]) -> Pointer[T] = "%identity"

///|
/// Extracts a pointer from a bytes buffer.
///
/// Parameters:
///
/// - `value`: The bytes buffer to extract a pointer from
///
/// Returns a `Pointer[Byte]` pointing to the first byte of the buffer.
#as_free_fn
pub fn Pointer::unsafe_from_bytes(value : Bytes) -> Pointer[Byte] = "%identity"

///|
/// Unsafely converts a pointer back into a value.
///
/// **Warning**: This is an unsafe operation that should be used with extreme caution.
/// The pointer must point to valid memory of type `T`, or undefined behavior will occur.
///
/// Parameters:
///
/// - `pointer`: The pointer to convert
///
/// Returns a value of type `T`.
#as_free_fn
pub fn[T] Pointer::unsafe_into(ptr : Pointer[Unit]) -> T = "%identity"

///|
/// Converts a pointer into a reference.
///
/// Parameters:
///
/// - `pointer`: The pointer to convert
///
/// Returns a `Ref[T]` referencing the memory location.
#as_free_fn
pub fn[T] Pointer::unsafe_into_ref(ptr : Pointer[T]) -> Ref[T] = "%identity"

///|
/// Converts a pointer into a fixed array.
///
/// Parameters:
///
/// - `pointer`: The pointer to convert
///
/// Returns a `FixedArray[T]` starting at the pointer's memory location.
#as_free_fn
pub fn[T] Pointer::unsafe_into_array(ptr : Pointer[T]) -> FixedArray[T] = "%identity"

///|
/// Converts a pointer into a bytes buffer.
///
/// Parameters:
///
/// - `pointer`: The pointer to convert
///
/// Returns a `Bytes` buffer starting at the pointer's memory location.
#as_free_fn
pub fn Pointer::unsafe_into_bytes(ptr : Pointer[Byte]) -> Bytes = "%identity"

///|
/// Borrows a pointer from a reference for the duration of a function call.
///
/// The reference is temporarily converted to a pointer, passed to the function,
/// and then restored. This ensures the reference remains valid after the operation.
///
/// Parameters:
///
/// - `ref_`: The reference to borrow from
/// - `f`: The function to call with the borrowed pointer
///
/// Returns the result of calling `f`.
pub fn[T, R] borrow_ref(
  ref_ : Ref[T],
  f : (Pointer[T]) -> R raise?,
) -> R raise? {
  let ptr = unsafe_from_ref(ref_)
  let val : R = f(ptr)
  let _ : Ref[T] = unsafe_into_ref(ptr)
  val
}

///|
/// Borrows a pointer from a fixed array for the duration of a function call.
///
/// The array is temporarily converted to a pointer, passed to the function,
/// and then restored. This ensures the array remains valid after the operation.
///
/// Parameters:
///
/// - `array`: The fixed array to borrow from
/// - `f`: The function to call with the borrowed pointer
///
/// Returns the result of calling `f`.
pub fn[T, R] borrow_array(
  array : FixedArray[T],
  f : (Pointer[T]) -> R raise?,
) -> R raise? {
  let ptr = unsafe_from_array(array)
  let val : R = f(ptr)
  let _ : FixedArray[T] = unsafe_into_array(ptr)
  val
}

///|
/// Borrows a pointer from a bytes buffer for the duration of a function call.
///
/// The bytes buffer is temporarily converted to a pointer, passed to the function,
/// and then restored. This ensures the buffer remains valid after the operation.
///
/// Parameters:
///
/// - `bytes`: The bytes buffer to borrow from
/// - `f`: The function to call with the borrowed pointer
///
/// Returns the result of calling `f`.
pub fn[R] borrow_bytes(
  bytes : Bytes,
  f : (Pointer[Byte]) -> R raise?,
) -> R raise? {
  let ptr = unsafe_from_bytes(bytes)
  let val : R = f(ptr)
  let _ : Bytes = unsafe_into_bytes(ptr)
  val
}

///|
/// Unsafely borrows a pointer from any value for the duration of a function call.
///
/// **Warning**: This is an unsafe operation. The value is temporarily converted
/// to a pointer and restored after the function call, but this may lead to
/// undefined behavior if not used carefully.
///
/// Parameters:
///
/// - `value`: The value to borrow from
/// - `f`: The function to call with the borrowed pointer
///
/// Returns the result of calling `f`.
#locals(f)
pub fn[T, R] unsafe_borrow(
  value : T,
  f : (Pointer[Unit]) -> R raise?,
) -> R raise? {
  let ptr = unsafe_from(value)
  let val : R = for ;; {
    break f(ptr)
  }
  let _ : T = unsafe_into(ptr)
  val
}

///|
/// Trait for types that support safe borrowing as pointers.
///
/// Types implementing this trait can be safely converted to and from pointers,
/// enabling temporary pointer access to their internal data.
trait Borrow {
  unsafe_from(Self) -> Pointer[Unit]
  unsafe_into(Pointer[Unit]) -> Self
}

///|
/// Borrows a pointer from a value that implements the `Borrow` trait.
///
/// The value is temporarily converted to a pointer, passed to the function,
/// and then restored. This ensures the value remains valid after the operation.
///
/// Parameters:
///
/// - `value`: The value to borrow from (must implement `Borrow`)
/// - `f`: The function to call with the borrowed pointer
///
/// Returns the result of calling `f`.
#locals(f)
pub fn[T : Borrow, R] borrow(
  value : T,
  f : (Pointer[Unit]) -> R raise?,
) -> R raise? {
  let ptr = T::unsafe_from(value)
  let val : R = for ;; {
    break f(ptr)
  }
  let _ : T = T::unsafe_into(ptr)
  val
}

///|
pub fn[A : Borrow, B : Borrow, R] borrow_2(
  a : A,
  b : B,
  f : (Pointer[Unit], Pointer[Unit]) -> R raise?,
) -> R raise? {
  let ptr_a = A::unsafe_from(a)
  let ptr_b = B::unsafe_from(b)
  let val : R = for ;; {
    break f(ptr_a, ptr_b)
  }
  let _ : A = A::unsafe_into(ptr_a)
  let _ : B = B::unsafe_into(ptr_b)
  val
}

///|
/// Implements `Borrow` for `Bytes` to extract a pointer.
pub impl Borrow for Bytes with unsafe_from(self : Bytes) -> Pointer[Unit] {
  unsafe_from_bytes(self).cast()
}

///|
/// Implements `Borrow` for `Bytes` to restore from a pointer.
pub impl Borrow for Bytes with unsafe_into(ptr : Pointer[Unit]) -> Bytes {
  unsafe_into_bytes(ptr.cast())
}

///|
/// Implements `Borrow` for `Pointer[T]` to cast to `Pointer[Unit]`.
pub impl[T] Borrow for Pointer[T] with unsafe_from(self : Pointer[T]) -> Pointer[
  Unit,
] {
  self.cast()
}

///|
/// Implements `Borrow` for `Pointer[T]` to cast from `Pointer[Unit]`.
pub impl[T] Borrow for Pointer[T] with unsafe_into(ptr : Pointer[Unit]) -> Pointer[
  T,
] {
  ptr.cast()
}

///|
/// Implements `Borrow` for `FixedArray[T]` to extract a pointer.
pub impl[T] Borrow for FixedArray[T] with unsafe_from(self : FixedArray[T]) -> Pointer[
  Unit,
] {
  unsafe_from_array(self).cast()
}

///|
/// Implements `Borrow` for `FixedArray[T]` to restore from a pointer.
pub impl[T] Borrow for FixedArray[T] with unsafe_into(ptr : Pointer[Unit]) -> FixedArray[
  T,
] {
  unsafe_into_array(ptr.cast())
}

///|
pub impl[T] Borrow for Ref[T] with unsafe_from(self : Ref[T]) -> Pointer[Unit] {
  unsafe_from_ref(self).cast()
}

///|
pub impl[T] Borrow for Ref[T] with unsafe_into(ptr : Pointer[Unit]) -> Ref[T] {
  unsafe_into_ref(ptr.cast())
}

///|
/// Decrements the reference count of a value.
///
/// This function manipulates the internal reference count by converting the value
/// to a pointer and back twice, effectively decrementing its reference count.
///
/// **Warning**: This is a low-level operation that should be used with caution.
///
/// Parameters:
///
/// - `value`: The value whose reference count should be decremented
pub fn[T] unsafe_decref(value : T) -> Unit {
  let pointer = unsafe_from(value)
  let _ : T = unsafe_into(pointer)
  let _ : T = unsafe_into(pointer)
  ()
}