1 module lwdr.unique;
2 
3 import lwdr.util.traits;
4 import lwdr : LWDR;
5 
6 /++ Check if T is suitable for a unique pointer. 
7 	T must be a class, interface, pointer or dynamic array. ++/
8 enum isSuitableForUnique(T) = 
9 	is(T == class) ||
10 	is(T == interface) ||
11 	is(T == U*, U) ||
12 	is(T == U[], U);
13 
14 /++ A unique pointer. Only one pointer to a target may exist at a time.
15 	Pointers can be explicitly moved, but not copied. ++/
16 struct Unique(T)
17 	if(isSuitableForUnique!T)
18 {
19 	@disable this(this); /// Disable copy semantics
20 
21 	private T payload; /// Payload
22 	alias payload this;
23 
24 	/// Assign a payload to this unique pointer
25 	this(T t)
26 	{
27 		payload = t;
28 	}
29 
30 	/// Allocate the payload
31 	this(Args...)(auto ref Args args)
32 	{
33         static if(is(T == class))
34             payload = new T(args);
35         static if(is(T == U*, U))
36         {
37             alias root = rootType!T;
38             static if(is(root == struct) || is(root == union))
39                 payload = new root(args);
40             else
41             {
42                 payload = new root;
43                 *payload = args[0];
44             }
45         }
46         static if(is(T == U[], U))
47         {
48             alias root = rootType!T;
49             payload = [args];
50         }
51 	}
52 
53 	~this()
54 	{
55 		if(payload !is null)
56 		{
57 			LWDR.free(payload);
58 			payload = null;
59 		}
60 	}
61 
62 	/// Move to a new instance
63 	Unique move() 
64 	{
65 		Unique ret;
66 		ret.payload = this.payload;
67 		this.payload = null;
68 		return ret;
69 	}
70 
71 	/// Borrow the pointer
72 	inout auto borrow() @system { return payload; }
73 
74 	/// Check if this unique instance has a payload
75 	@property auto bool hasPayload() const 
76 	{ return payload !is null; }
77 
78 	/// ditto.
79 	auto opCast(CastTarget)() if(is(CastTarget == bool))
80 	{ return hasPayload; }
81 }