// vim:set ft=cpp: -*- Mode: C++ -*-
/**
 * \file
 * Unique_cap / Unique_del_cap
 */
/*
 * (c) 2017 Alexander Warg <alexander.warg@kernkonzept.com>
 *
 * License: see LICENSE.spdx (in this directory or the directories above)
 */

#pragma once

#include <l4/re/util/cap_alloc>
#include <l4/sys/cxx/smart_capability_1x>

namespace L4Re { namespace Util {

/**
 * Unique capability that implements automatic free and unmap of the
 * capability selector.
 *
 * \tparam T  Type of the object the capability refers to.
 *
 * The ownership of the capability is managed in the same way as unique_ptr.
 *
 * Usage:
 *
 *     {
 *       L4Re::Util::Unique_cap<L4Re::Dataspace>
 *         ds_cap = L4Re::Util::make_unique_cap<L4Re::Dataspace>();
 *
 *       // use the dataspace cap
 *       L4Re::chksys(mem_alloc->alloc(L4_PAGESIZE, ds_cap.get()));
 *
 *       ...
 *
 *       // At the end of the scope ds_cap is unmapped and the capability
 *       // selector is freed.
 *     }
 */
template< typename T >
using Unique_cap = L4::Detail::Unique_cap_impl<T, Smart_cap_auto<L4_FP_ALL_SPACES>>;
/// \copydoc Unique_cap
template< typename T >
using unique_cap = L4::Detail::Unique_cap_impl<T, Smart_cap_auto<L4_FP_ALL_SPACES>>;

/**
 * Allocate a capability slot and wrap it in an Unique_cap.
 *
 * \tparam T  Type of the object the capability refers to.
 */
template< typename T >
Unique_cap<T>
make_unique_cap()
{ return Unique_cap<T>(cap_alloc.alloc<T>()); }

/**
 * Unique capability that implements automatic free and unmap+delete of the
 * capability selector.
 *
 * \tparam T  Type of the object the capability refers to.
 *
 * The main difference to Unique_cap is that the unmap is done with the
 * deletion flag enabled and this leads to the deletion of the object
 * if the current task holds appropriate deletion rights.
 *
 * Usage:
 *
 *     {
 *       L4Re::Util::Unique_del_cap<L4Re::Dataspace>
 *         ds_cap = make_unique_del_cap<L4Re::Dataspace>());
 *
 *       // use the dataspace cap
 *       L4Re::chksys(mem_alloc->alloc(L4_PAGESIZE, ds_cap.get()));
 *
 *       ...
 *
 *       // At the end of the scope ds_cap is unmapped and the capability
 *       // selector is freed. Because the deletion flag is set the data space
 *       // shall also be deleted (even if there are other references to this
 *       // data space).
 *     }
 */
template< typename T >
using Unique_del_cap = L4::Detail::Unique_cap_impl<T, Smart_cap_auto<L4_FP_DELETE_OBJ>>;
template< typename T >
/// \copydoc Unique_del_cap
using unique_del_cap = L4::Detail::Unique_cap_impl<T, Smart_cap_auto<L4_FP_DELETE_OBJ>>;

/**
 * Allocate a capability slot and wrap it in an Unique_del_cap.
 *
 * \tparam T  Type of the object the capability refers to.
 */
template< typename T >
Unique_del_cap<T>
make_unique_del_cap()
{ return Unique_del_cap<T>(cap_alloc.alloc<T>()); }

}}

