import std.stdio, std.typecons;
import std.conv : to;
template CreateMsg(string msg, string file = __FILE__, size_t line = __LINE__) {
enum CreateMsg = msg ~ " @ " ~ file ~ " in Line " ~ to!(string)(line) ~ ".";
}
string CreateErrorMsg(string msg, string file = __FILE__, size_t line = __LINE__) {
return msg ~ " @ " ~ file ~ " in Line " ~ to!(string)(line) ~ ".";
}
struct Ref(T : Object) {
private:
T _obj;
public:
@disable
this();
@disable
this(typeof(null));
this(T obj) {
assert(obj !is null, CreateMsg!("Object is null!"));
this._obj = obj;
}
@disable
typeof(this) opAssign()(typeof(null));
typeof(this) opAssign(U : T)(Ref!(U) refer) {
this._obj = refer.access;
return this;
}
typeof(this) opAssign(U : T)(U refer) {
assert(refer !is null, CreateMsg!("Object is null"));
this._obj = refer;
return this;
}
@property
inout(T) access() inout {
assert(this._obj !is null, CreateMsg!("Access: Object is null!"));
return this._obj;
}
// DMD Bug: The compiler creates and infinite loop.
// if uncomment, the compiler print "Stackoverflow" or "recursive expansion"
//alias access this;
mixin Proxy!(this._obj);
}
mixin template TRef(T : Object) {
final Ref!(T) getRef(string file = __FILE__, size_t line = __LINE__) in {
assert(this !is null, CreateErrorMsg("Object is null!", file, line));
} body {
return Ref!(T)(this);
}
final Ref!(const T) getRef(string file = __FILE__, size_t line = __LINE__) const in {
assert(this !is null, CreateErrorMsg("Object is null!", file, line));
} body {
return Ref!(const T)(this);
}
// Hack for Bug 8001 (http://forum.dlang.org/thread/bug-8001-3@http.d.puremagic.com%2Fissues%2F)
U opCast(U/* : Object*/)() inout {
writeln(typeid(U));
return *(cast(U*) &this);
}
alias getRef this;
}
class Foo {
public:
void say() const {
writeln("Hallo");
}
mixin TRef!(Foo);
}
void normal_foo(Foo f) {
f.say();
}
void ref_foo(Ref!(Foo) rf) {
rf.say();
}
T const_cast(T : Object)(const T obj) {
return cast(T) obj;
}
void main() {
Foo f1 = new Foo();
normal_foo(f1);
ref_foo(f1);
Ref!(Foo) rf1 = new Foo();
normal_foo(rf1);
ref_foo(rf1);
bool instanceof(T : Object, U : Object)(const Ref!(U) obj) {
const U o = obj.access;
return const_cast(o).toString() == typeid(T).toString();
}
class A {
mixin TRef!(A);
}
class B : A {
mixin TRef!(B);
}
class C : B {
mixin TRef!(C);
}
A a1 = new B();
A a2 = new C();
assert(instanceof!(A)(a1) == false);
assert(instanceof!(B)(a1));
assert(instanceof!(C)(a1) == false);
writeln(a1);
B b1 = cast(B) a1;
assert(instanceof!(A)(b1) == false);
writeln(b1);
writeln("---");
}