#pragma once
#include <concepts>
#include <memory>
#include <type_traits>
#include <utility>
template <class Value>
class renderive_Owner {
public:
    using element_type = Value;
    renderive_Owner() = default;
    renderive_Owner(std::nullptr_t) noexcept {}
    explicit renderive_Owner(std::shared_ptr<Value> owner) noexcept : owner_(std::move(owner)) {}
    template <class Other>
    requires std::convertible_to<Other*, Value*>
    renderive_Owner(const renderive_Owner<Other>& other) noexcept : owner_(other.owner_) {}
    template <class Other>
    requires std::convertible_to<Other*, Value*>
    renderive_Owner(renderive_Owner<Other>&& other) noexcept : owner_(std::move(other.owner_)) {}
    template <class... Args>
    static renderive_Owner make(Args&&... args) {
        return renderive_Owner(std::make_shared<Value>(std::forward<Args>(args)...));
    }
    [[nodiscard]] Value* get() const noexcept {
        return owner_.get();
    }
    [[nodiscard]] std::shared_ptr<Value> share() const noexcept {
        return owner_;
    }
    Value& operator*() const noexcept {
        return *owner_;
    }
    Value* operator->() const noexcept {
        return owner_.get();
    }
    explicit operator bool() const noexcept {
        return static_cast<bool>(owner_);
    }
    void reset() noexcept {
        owner_.reset();
    }
    friend bool operator==(const renderive_Owner&, const renderive_Owner&) = default;
    friend bool operator==(const renderive_Owner& owner, std::nullptr_t) noexcept {
        return !owner;
    }
    friend bool operator==(std::nullptr_t, const renderive_Owner& owner) noexcept {
        return !owner;
    }
private:
    template <class>
    friend class renderive_Owner;
    std::shared_ptr<Value> owner_;
};
template <class Target, class Source>
renderive_Owner<Target> renderive_dynamic_owner_cast(const renderive_Owner<Source>& source) noexcept {
    return renderive_Owner<Target>(std::dynamic_pointer_cast<Target>(source.share()));
}
template <class Target, class Source>
renderive_Owner<Target> renderive_static_owner_cast(const renderive_Owner<Source>& source) noexcept {
    return renderive_Owner<Target>(std::static_pointer_cast<Target>(source.share()));
}
template <class Target, class Source>
renderive_Owner<Target> renderive_const_owner_cast(const renderive_Owner<Source>& source) noexcept {
    return renderive_Owner<Target>(std::const_pointer_cast<Target>(source.share()));
}
