Skip to content

Instantly share code, notes, and snippets.

@vitalfadeev
Last active December 15, 2022 05:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vitalfadeev/2d25724d083a768ae63ab183211c5edc to your computer and use it in GitHub Desktop.
Save vitalfadeev/2d25724d083a768ae63ab183211c5edc to your computer and use it in GitHub Desktop.
Safe HANDLE for DLang
module safehandle;
import core.sys.windows.windows;
import std.format;
import std.typecons;
// Unique_ptr wrapper for WinAPI handles.
struct Unique( T, alias DTOR )
{
/** Represents a reference to `T`. Resolves to `T*` if `T` is a value type. */
static if (is(T == class) || is(T == interface))
alias RefT = T;
else
alias RefT = T*;
public:
// Deferred in case we get some language support for checking uniqueness.
version (None)
/**
Allows safe construction of `Unique`. It creates the resource and
guarantees unique ownership of it (unless `T` publishes aliases of
`this`).
Note: Nested structs/classes cannot be created.
Params:
args = Arguments to pass to `T`'s constructor.
---
static class C {}
auto u = Unique!(C).create();
---
*/
static Unique!T create(A...)(auto ref A args)
if (__traits(compiles, new T(args)))
{
Unique!T u;
u._p = new T(args);
return u;
}
/**
Constructor that takes an rvalue.
It will ensure uniqueness, as long as the rvalue
isn't just a view on an lvalue (e.g., a cast).
Typical usage:
----
Unique!Foo f = new Foo;
----
*/
this(RefT p)
{
_p = p;
}
/**
Constructor that takes an lvalue. It nulls its source.
The nulling will ensure uniqueness as long as there
are no previous aliases to the source.
*/
this(ref RefT p)
{
_p = p;
p = null;
assert(p is null);
}
/**
Constructor that takes a `Unique` of a type that is convertible to our type.
Typically used to transfer a `Unique` rvalue of derived type to
a `Unique` of base type.
Example:
---
class C : Object {}
Unique!C uc = new C;
Unique!Object uo = uc.release;
---
*/
this(U)(Unique!U u)
if (is(u.RefT:RefT))
{
_p = u._p;
u._p = null;
}
/// Transfer ownership from a `Unique` of a type that is convertible to our type.
void opAssign(U)(Unique!U u)
if (is(u.RefT:RefT))
{
// first delete any resource we own
destroy(this);
_p = u._p;
u._p = null;
}
~this()
{
if (_p !is null)
{
DTOR( _p );
destroy(_p);
_p = null;
}
}
/** Returns whether the resource exists. */
@property bool isEmpty() const
{
return _p is null;
}
/** Transfer ownership to a `Unique` rvalue. Nullifies the current contents.
Same as calling std.algorithm.move on it.
*/
Unique release()
{
import std.algorithm.mutation : move;
return this.move;
}
/** Forwards member access to contents. */
mixin Proxy!_p;
/**
Postblit operator is undefined to prevent the cloning of `Unique` objects.
*/
@disable this(this);
private:
RefT _p;
}
auto CloseHandleWrapper( ref HANDLE h )
{
auto res = CloseHandle( h );
if ( res != 0 )
h = null; // OK
if ( res == 0 )
throw new Exception( format!"ERR: %d"( GetLastError() ) );
return res;
}
//alias SafeHandle = Unique!(void,CloseHandleWrapper);
alias SafeHandle = Unique!(void,CloseHandle);
// alias SafeHandle = Unique!(void,CloseHandle)
// alias Safe_SDL_Window = Unique!(SDL_Window,SDL_DestroyWindow)
// alias Safe_SDL_Surface = Unique!(SDL_Surface,SDL_FreeSurface)
// alias Safe_SDL_Texture = Unique!(SDL_Texture,SDL_DestroyTexture)
// alias Safe_SDL_Renderer = Unique!(SDL_Renderer,SDL_DestroyRenderer)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment