/* This program is free software. It comes without any warranty, to * the extent permitted by applicable law. You can redistribute it * and/or modify it under the terms of the Do What The Fuck You Want * To Public License, Version 2, as published by Sam Hocevar. See * http://sam.zoy.org/wtfpl/COPYING for more details. */ import std.exception : enforce; version ( unittest ) { import std.exception : assertThrown, assertNotThrown; import core.exception : AssertError; } /** * A pointer or reference that can never be null. * Does not allow implicit conversion from nullable to NotNull. **/ struct NotNull( T ) if ( isNullable!T ) { private T payload; @disable this( ); @disable this( T ); static @property @disable NotNull init(); @property inout(T) get( ) inout { return payload; } alias get this; } unittest { class A { int n; } assert( !is( NotNull!(int) ) ); assert( is( NotNull!(A) ) ); assert( is( NotNull!(int*) ) ); assert( !is( NotNull!(int[]) ) ); assert( !__traits( compiles, { NotNull!int a; } ) ); assert( !__traits( compiles, { NotNull!(int*) a; } ) ); assert( !__traits( compiles, { NotNull!(int*) a = null; } ) ); assert( !__traits( compiles, { NotNull!(int*) a = new int; } ) ); assert( __traits( compiles, { NotNull!(int*) a = void; } ) ); assert( __traits( compiles, { NotNull!(int*) a = void; *a = 3; } ) ); assert( __traits( compiles, { NotNull!(A) a = void; a.n = 3; } ) ); //assert( !__traits( compiles, { NotNull!(A)[] a; a.length = 3; } ) ); // Bug 8457 } /** * Takes the value through the back door into NotNull land. * This function should have zero overhead in release mode. **/ NotNull!T assumeNotNull( T )( T value ) if ( isNullable!T ) { assert( value !is null ); NotNull!T result = void; result.payload = value; return result; } unittest { assert( __traits( compiles, { NotNull!(int*) a = assumeNotNull(new int); } ) ); assert( !__traits( compiles, { NotNull!(int*) a = assumeNotNull(new string); } ) ); assertThrown!AssertError( assumeNotNull!(int*)( null ) ); } /** * Checks that the passed value is not null. * Throws an exception if it is. **/ NotNull!T enforceNotNull( T )( T value ) if ( isNullable!T ) { enforce( value !is null ); NotNull!T result = void; result.payload = value; return result; } unittest { assert( __traits( compiles, { NotNull!(int*) a = enforceNotNull(new int); } ) ); assert( !__traits( compiles, { NotNull!(int*) a = enforceNotNull(new string); } ) ); assertThrown( enforceNotNull!(int*)( null ) ); } /** * Checks if a type is nullable. Left out arrays because null arrays * actually do make a twisted sort of sense. **/ template isNullable( T ) { static if ( is( T U : U* ) ) { enum isNullable = true; } else { enum isNullable = is( T == class ); } } unittest { class A {} assert( isNullable!A ); assert( isNullable!(int*) ); assert( !isNullable!(int[]) ); assert( !isNullable!int ); }