View difference between Paste ID: J1MvgVch and SU0BMXsn
SHOW: | | - or go back to the newest paste.
1
/*
2
This module is based on code in the std.typecons module in the standard library of the D programming language. The authors of std.typecons deserve credit and thanks, and are listed at the top of the source code for the module, which is available here:
3
4
https://github.com/D-Programming-Language/phobos/blob/master/std/typecons.d
5
6
Copyright (c) 2013, w0rp <moebiuspersona@gmail.com>
7
All rights reserved.
8
9
Redistribution and use in source and binary forms, with or without
10
modification, are permitted provided that the following conditions are met:
11
12
1. Redistributions of source code must retain the above copyright notice, this
13
   list of conditions and the following disclaimer.
14
2. Redistributions in binary form must reproduce the above copyright notice,
15
   this list of conditions and the following disclaimer in the documentation
16
   and/or other materials provided with the distribution.
17
18
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
*/
29
30
module option;
31
32
import std.exception;
33
import std.typecons;
34
import std.stdio;
35
36
struct Option(T) if(is(T == class)) {
37
    private T _value;
38
39
    this(T value) {
40
        _value = value;
41
    }
42
43
    this(Nullable!T value) {
44
        if (!value.isNull)
45
        {
46
            _value = value;
47
        }
48
    }
49
50
    @property @safe const pure nothrow
51
    bool isNull() {
52
        return _value is null;
53
    }
54
55
    @safe pure nothrow
56
    void opAssign(T value) {
57
        _value = value;
58
    }
59
60
    @safe pure
61
    void opAssign(Nullable!T value) {
62
        if (!value.isNull)
63
        {
64
            _value = value;
65
        }
66
    }
67
68
    @safe pure nothrow nullify() {
69
        _value = null;
70
    }
71
72
    @property @safe pure nothrow inout(T) get() inout {
73
        enum message = "Called `get' on null Option!" ~ T.stringof ~ ".";
74
        assert(_value !is null, message);
75
        return _value;
76
    }
77
78
    alias get this;
79
}
80
81
struct Option(T) if(!is(T == class)) {
82
    private T _value;
83
    private bool _isNull = true;
84
85
    this(T value) {
86
        _value = value;
87
        _isNull = false;
88
    }
89
90
    // The defaults work here.
91
    this(typeof(null) value) {}
92
93
    this(Nullable!T value) {
94
        if (!value.isNull) {
95
            _value = value;
96
            _isNull = false;
97
        }
98
    }
99
100
    @property @safe const pure nothrow
101
    bool isNull() {
102
        return _isNull;
103
    }
104
105
    @safe pure nothrow
106
    void opAssign(T value) {
107
        _value = value;
108
        _isNull = false;
109
    }
110
111
    @safe pure nothrow
112
    void opAssign(typeof(null) value) {
113
        nullify();
114
    }
115
116
    @safe pure
117
    void opAssign(Nullable!T value) {
118
        if (!value.isNull) {
119
            _value = value;
120
            _isNull = false;
121
        }
122
    }
123
124
    @safe pure nothrow nullify() {
125
        _value = T.init;
126
        _isNull = true;
127
    }
128
129
    @property @safe pure nothrow
130
    inout(T) get() inout {
131
        enum message = "Called `get' on null Option!" ~ T.stringof ~ ".";
132
        assert(!_isNull, message);
133
        return _value;
134
    }
135
136
    alias get this;
137
}
138
139
// Test that Option works for classes.
140
unittest {
141
    class MyClass { }
142
143
    Option!MyClass test = null;
144
    assert(test.isNull);
145
    assertThrown!Throwable(test.get);
146
}
147
148
unittest {
149
    class MyClass { }
150
151
    Option!MyClass test = new MyClass();
152
    test = null;
153
154
    assert(test.isNull);
155
    assertThrown!Throwable(test.get);
156
}
157
158
unittest {
159
    class MyClass { }
160
161
    Option!MyClass test = new MyClass();
162
    assert(!test.isNull);
163
    assertNotThrown!Throwable(test.get);
164
}
165
166
unittest {
167
    class MyClass { }
168
169
    Option!MyClass test;
170
    test = new MyClass();
171
    assert(!test.isNull);
172
    assertNotThrown!Throwable(test.get);
173
}
174
175
// Test that option works for primitives.
176
unittest {
177
    Option!int test;
178
    assert(test.isNull);
179
    assertThrown!Throwable(test.get);
180
}
181
182
unittest {
183
    Option!int test = 3;
184
    test.nullify();
185
    assert(test.isNull);
186
    assertThrown!Throwable(test.get);
187
}
188
189
unittest {
190
    Option!int test = 4;
191
    assert(!test.isNull);
192
    assertNotThrown!Throwable(test.get);
193
}
194
195
unittest {
196
    Option!int test;
197
    test = 4;
198
    assert(!test.isNull);
199
    assertNotThrown!Throwable(test.get);
200
}
201
202
// Test the hook for assigning null to primitives.
203
204
unittest {
205
    Option!int test = null;
206
}
207
208
unittest {
209
    Option!int test;
210
    test = null;
211
}
212
213
// Test that option supports Nullable for classes.
214
unittest {
215
    class MyClass { }
216
217
    Nullable!MyClass nullableInstance;
218
    Option!MyClass optInstance = nullableInstance;
219
220
    assert(optInstance.isNull);
221
    assertThrown!Throwable(optInstance.get);
222
}
223
224
unittest {
225
    class MyClass { }
226
227
    MyClass instance = new MyClass();
228
229
    Nullable!MyClass nullableInstance = instance;
230
    Option!MyClass optInstance = nullableInstance;
231
232
    assert(!optInstance.isNull);
233
    assertNotThrown!Throwable(optInstance.get);
234
    assert(optInstance == instance);
235
}
236
237
// Test that option supports Nullable for primitives.
238
unittest {
239
    Nullable!int nullableInt;
240
    Option!int optInt = nullableInt;
241
242
    assert(optInt.isNull);
243
    assertThrown!Throwable(optInt.get);
244
}
245
246
unittest {
247
    Nullable!int nullableInt = 3;
248
    Option!int optInt = nullableInt;
249
250
    assert(!optInt.isNull);
251
    assertNotThrown!Throwable(optInt.get);
252
    assert(optInt == 3);
253
}