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