diff --git a/source/tanya/meta/transform.d b/source/tanya/meta/transform.d index c0cfb9d..82eb2a7 100644 --- a/source/tanya/meta/transform.d +++ b/source/tanya/meta/transform.d @@ -18,6 +18,7 @@ */ module tanya.meta.transform; +import tanya.meta.metafunction; import tanya.meta.trait; /** @@ -717,3 +718,186 @@ if (isExpressions!T || __traits(isTemplate, T)) static assert(is(TypeOf!true == bool)); static assert(!is(TypeOf!(tanya.meta))); } + +// e.g. returns int for int**. +private template FinalPointerTarget(T) +{ + static if (isPointer!T) + { + alias FinalPointerTarget = FinalPointerTarget!(PointerTarget!T); + } + else + { + alias FinalPointerTarget = T; + } +} + +// Returns true if T1 is void* and T2 is some pointer. +private template voidAndPointer(T1, T2) +{ + enum bool voidAndPointer = is(Unqual!(PointerTarget!T1) == void) + && isPointer!T2; +} + +// Type returned by the ternary operator. +private alias TernaryType(T, U) = typeof(true ? T.init : U.init); + +/** + * Determines the type all $(D_PARAM Args) can be implicitly converted to. + * + * $(OL + * $(LI If one of the arguments is $(D_KEYWORD void), the common type is + * $(D_KEYWORD void).) + * $(LI The common type of integers with the same sign is the type with a + * larger size. Signed and unsigned integers don't have a common type. + * Type qualifiers are only preserved if all arguments are the same + * type.) + * $(LI The common type of floating point numbers is the type with more + * precision. Type qualifiers are only preserved if all arguments are + * the same type.) + * $(LI The common type of polymorphic objects is the next, more generic type + * both objects inherit from, e.g. $(D_PSYMBOL Object).) + * $(LI `void*` is concerned as a common type of pointers only if one of the + * arguments is a void pointer.) + * $(LI Other types have a common type only if their pointers have a common + * type. It means that for example $(D_KEYWORD bool) and $(D_KEYWORD int) + don't have a common type. If the types fullfill this condition, the + common type is determined with the ternary operator, i.e. + `typeof(true ? T1.init : T2.init)` is evaluated.) + * ) + * + * If $(D_PARAM Args) don't have a common type, $(D_PSYMBOL CommonType) is + * $(D_KEYWORD void). + * + * Params: + * Args = Type list. + * + * Returns: Common type for $(D_PARAM Args) or $(D_KEYWORD void) if + * $(D_PARAM Args) don't have a common type. + */ +template CommonType(Args...) +if (allSatisfy!(isType, Args)) +{ + static if (Args.length == 0 + || is(Unqual!(Args[0]) == void) + || is(Unqual!(Args[1]) == void)) + { + alias CommonType = void; + } + else static if (Args.length == 1) + { + alias CommonType = Args[0]; + } + else + { + private alias Pair = Args[0 .. 2]; + private enum bool sameSigned = allSatisfy!(isIntegral, Pair) + && isSigned!(Args[0]) == isSigned!(Args[1]); + + static if (is(Args[0] == Args[1])) + { + alias CommonType = CommonType!(Args[0], Args[2 .. $]); + } + else static if (sameSigned || allSatisfy!(isFloatingPoint, Pair)) + { + alias CommonType = CommonType!(Unqual!(Largest!Pair), + Args[2 .. $]); + } + else static if (voidAndPointer!Pair + || voidAndPointer!(Args[1], Args[0])) + { + // Workaround for https://issues.dlang.org/show_bug.cgi?id=15557. + // Determine the qualifiers returned by the ternary operator as if + // both pointers were int*. Then copy the qualifiers to void*. + alias P1 = CopyTypeQualifiers!(FinalPointerTarget!(Args[0]), int)*; + alias P2 = CopyTypeQualifiers!(FinalPointerTarget!(Args[1]), int)*; + static if (is(TernaryType!(P1, P2) U)) + { + alias CommonType = CopyTypeQualifiers!(PointerTarget!U, void)*; + } + else + { + alias CommonType = void; + } + } + else static if ((isPointer!(Args[0]) || isPolymorphicType!(Args[0])) + && is(TernaryType!Pair U)) + { + alias CommonType = CommonType!(U, Args[2 .. $]); + } + else static if (is(TernaryType!(Args[0]*, Args[1]*))) + { + alias CommonType = CommonType!(TernaryType!Pair, Args[2 .. $]); + } + else + { + alias CommonType = void; + } + } +} + +/// +@nogc nothrow pure @safe unittest +{ + static assert(is(CommonType!(int, int, int) == int)); + static assert(is(CommonType!(ubyte, ushort, uint) == uint)); + static assert(is(CommonType!(int, uint) == void)); + + static assert(is(CommonType!(int, const int) == int)); + static assert(is(CommonType!(const int, const int) == const int)); + + static assert(is(CommonType!(int[], const(int)[]) == const(int)[])); + static assert(is(CommonType!(string, char[]) == const(char)[])); + + class A + { + } + static assert(is(CommonType!(const A, Object) == const Object)); +} + +@nogc nothrow pure @safe unittest +{ + static assert(is(CommonType!(void*, int*) == void*)); + static assert(is(CommonType!(void*, const(int)*) == const(void)*)); + static assert(is(CommonType!(void*, const(void)*) == const(void)*)); + static assert(is(CommonType!(int*, void*) == void*)); + static assert(is(CommonType!(const(int)*, void*) == const(void)*)); + static assert(is(CommonType!(const(void)*, void*) == const(void)*)); + + static assert(is(CommonType!() == void)); + static assert(is(CommonType!(int*, const(int)*) == const(int)*)); + static assert(is(CommonType!(int**, const(int)**) == const(int*)*)); + + static assert(is(CommonType!(float, double) == double)); + static assert(is(CommonType!(float, int) == void)); + + static assert(is(CommonType!(bool, const bool) == bool)); + static assert(is(CommonType!(int, bool) == void)); + static assert(is(CommonType!(int, void) == void)); + static assert(is(CommonType!(Object, void*) == void)); + + class A + { + } + static assert(is(CommonType!(A, Object) == Object)); + static assert(is(CommonType!(const(A)*, Object*) == const(Object)*)); + static assert(is(CommonType!(A, typeof(null)) == A)); + + class B : A + { + } + class C : A + { + } + static assert(is(CommonType!(B, C) == A)); + + static struct S + { + int opCast(T : int)() + { + return 1; + } + } + static assert(is(CommonType!(S, int) == void)); + static assert(is(CommonType!(const S, S) == const S)); +} diff --git a/source/tanya/network/socket.d b/source/tanya/network/socket.d index d5492c8..d68378b 100644 --- a/source/tanya/network/socket.d +++ b/source/tanya/network/socket.d @@ -21,6 +21,7 @@ public import std.socket : SocketOption, SocketOptionLevel; import std.traits; import std.typecons; import tanya.memory; +import tanya.os.error; /// Value returned by socket operations on error. enum int socketError = -1; @@ -44,10 +45,8 @@ version (Posix) } else version (Windows) { - import core.sys.windows.winbase : ERROR_IO_INCOMPLETE, - ERROR_IO_PENDING, - GetModuleHandle, - GetProcAddress; + import core.sys.windows.winbase; + import core.sys.windows.winerror; import core.sys.windows.winsock2 : accept, addrinfo, bind, @@ -581,9 +580,7 @@ enum AddressFamily : int inet6 = 10, /// IP version 6. } -/** - * Error codes for $(D_PSYMBOL Socket). - */ +deprecated("Use tanya.os.error.ErrorCode.ErrorNo instead") enum SocketError : int { /// Unknown error. @@ -621,7 +618,7 @@ enum SocketError : int */ class SocketException : Exception { - const SocketError error = SocketError.unknown; + const ErrorCode.ErrorNo error = ErrorCode.ErrorNo.success; /** * Params: @@ -637,7 +634,7 @@ class SocketException : Exception { super(msg, file, line, next); - foreach (member; EnumMembers!SocketError) + foreach (member; EnumMembers!(ErrorCode.ErrorNo)) { if (member == lastError) { @@ -647,24 +644,24 @@ class SocketException : Exception } if (lastError == ENOMEM) { - error = SocketError.noBufferSpaceAvailable; + error = ErrorCode.ErrorNo.noBufferSpace; } else if (lastError == EMFILE) { - error = SocketError.tooManyOpenSockets; + error = ErrorCode.ErrorNo.tooManyDescriptors; } else version (linux) { if (lastError == ENOSR) { - error = SocketError.networkDown; + error = ErrorCode.ErrorNo.networkDown; } } else version (Posix) { if (lastError == EPROTO) { - error = SocketError.networkDown; + error = ErrorCode.ErrorNo.networkDown; } } } diff --git a/source/tanya/sys/windows/error.d b/source/tanya/sys/windows/error.d index 0b8c9e9..3f6e71c 100644 --- a/source/tanya/sys/windows/error.d +++ b/source/tanya/sys/windows/error.d @@ -10,6 +10,7 @@ * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/error.d, * tanya/sys/windows/error.d) */ + deprecated("Use core.sys.windows.winerror instead") module tanya.sys.windows.error; version (Windows): @@ -77,7 +78,7 @@ enum WSA_E_NO_MORE = WSABASEERR + 110, WSA_E_CANCELLED = WSABASEERR + 111, WSAEREFUSED = WSABASEERR + 112, - + WSAHOST_NOT_FOUND = WSABASEERR + 1001, WSATRY_AGAIN = WSABASEERR + 1002, WSANO_RECOVERY = WSABASEERR + 1003, @@ -111,4 +112,4 @@ enum WSA_QOS_ESDMODEOBJ = WSABASEERR + 1029, WSA_QOS_ESHAPERATEOBJ = WSABASEERR + 1030, WSA_QOS_RESERVED_PETYPE = WSABASEERR + 1031, -} \ No newline at end of file +}