#pragma once
#include <memory>

namespace myapp::utils {

template<class T, class U>
std::unique_ptr<T> static_unique_pointer_cast(std::unique_ptr<U>& r) noexcept
{
    return std::unique_ptr<T>(static_cast<typename std::unique_ptr<T>::element_type*>(r.release()));
}

template<class T, class U>
std::unique_ptr<T> dynamic_unique_pointer_cast(std::unique_ptr<U>& r) noexcept
{
    if (auto p = dynamic_cast<typename std::unique_ptr<T>::element_type*>(r.get())) {
        return r.release(), std::unique_ptr<T>(p);
    }
    else {
        return std::unique_ptr<T>();
    }
}

template<class T, class U>
std::unique_ptr<T> const_unique_pointer_cast(std::unique_ptr<U>& r) noexcept
{
    return std::unique_ptr<T>(const_cast<typename std::unique_ptr<T>::element_type*>(r.release()));
}

template<class T, class U>
std::unique_ptr<T> reinterpret_unique_pointer_cast(std::unique_ptr<U>& r) noexcept
{
    return std::unique_ptr<T>(reinterpret_cast<typename std::unique_ptr<T>::element_type*>(r.release()));
}

} /* namespace myapp::utils */
