
//
// UniquePointer
//
record UniquePointer[T] (ptr: Pointer[T]);

[T]
overload RegularRecord?(static UniquePointer[T]) = false;



//
// newUnique
//
[T]
alias newUnique(x:T) {
    var ptr = allocateRawMemory(T, SizeT(1));
    try {
        ptr^ <-- x;
    } catch (ex) {
        freeRawMemory(ptr);
        throw ex;
    }
    return UniquePointer(ptr);
}



//
// constructors, moveUnsafe, resetUnsafe, assign, destroy
//
[T]
overload UniquePointer[T]() = UniquePointer(null(T));

// no copying
[T]
overload UniquePointer[T](src: UniquePointer[T]);

[T]
overload BitwiseMovedType?(static UniquePointer[T]) = true;

[T]
inline overload resetUnsafe(p: UniquePointer[T]) {
    p.ptr = null(T);
}

// no assign from ref
[T]
inline overload assign(ref dest: UniquePointer[T], ref src: UniquePointer[T]);

[T]
inline overload destroy(p: UniquePointer[T]) {
    if (not null?(p.ptr)) {
        destroy(p.ptr^);
        freeRawMemory(p.ptr);
    }
}



//
// dereference, null?, nullUnique
//
[T]
inline overload dereference(p: UniquePointer[T]) = ref p.ptr^;

[T]
inline overload null?(p: UniquePointer[T]) = null?(p.ptr);

[T]
inline nullUnique(static T) = UniquePointer[T]();



//
// equality
//
[T]
inline overload equals?(p: UniquePointer[T], q: UniquePointer[T])
    = p.ptr == q.ptr;


//
// UniqueValue -- deep-copies on copy or assignment
//

record UniqueValue[T] (ptr: UniquePointer[T]);

[T]
alias overload UniqueValue(x:T) = UniqueValue[T](newUnique(x));

[T]
inline overload UniqueValue[T](x:UniqueValue[T]) =
    if (null?(x))
        nullUniqueValue(T)
    else
        UniqueValue(x^);

[T]
overload assign(ref to:UniqueValue[T], ref from:UniqueValue[T]) {
    if (null?(from)) {
        destroy(to.ptr);
        resetUnsafe(to.ptr);
    } else if (null?(to)) {
        to <-- UniqueValue(from^);
    } else {
        to^ = from^;
    }
}

[T]
inline overload dereference(p: UniqueValue[T]) = ref p.ptr^;

[T]
inline overload null?(p: UniqueValue[T]) = null?(p.ptr);

[T]
inline nullUniqueValue(static T) = UniqueValue[T]();

