1 /* 2 __ 3 / _| 4 __ _ _ _ _ __ ___ _ __ __ _ | |_ ___ ___ ___ 5 / _` | | | | '__/ _ \| '__/ _` | | _/ _ \/ __/ __| 6 | (_| | |_| | | | (_) | | | (_| | | || (_) \__ \__ \ 7 \__,_|\__,_|_| \___/|_| \__,_| |_| \___/|___/___/ 8 9 Copyright (C) 2018-2020 Aurora Free Open Source Software. 10 Copyright (C) 2018-2020 Luís Ferreira <luis@aurorafoss.org> 11 12 This file is part of the Aurora Free Open Source Software. This 13 organization promote free and open source software that you can 14 redistribute and/or modify under the terms of the GNU Lesser General 15 Public License Version 3 as published by the Free Software Foundation or 16 (at your option) any later version approved by the Aurora Free Open Source 17 Software Organization. The license is available in the package root path 18 as 'LICENSE' file. Please review the following information to ensure the 19 GNU Lesser General Public License version 3 requirements will be met: 20 https://www.gnu.org/licenses/lgpl.html . 21 22 Alternatively, this file may be used under the terms of the GNU General 23 Public License version 3 or later as published by the Free Software 24 Foundation. Please review the following information to ensure the GNU 25 General Public License requirements will be met: 26 http://www.gnu.org/licenses/gpl-3.0.html. 27 28 NOTE: All products, services or anything associated to trademarks and 29 service marks used or referenced on this file are the property of their 30 respective companies/owners or its subsidiaries. Other names and brands 31 may be claimed as the property of others. 32 33 For more info about intellectual property visit: aurorafoss.org or 34 directly send an email to: contact (at) aurorafoss.org . 35 36 This file has code parts from 'bolts' package. 37 Check out the project here: https://github.com/aliak00/bolts/ . 38 */ 39 40 /++ 41 Extras to std.traits 42 43 This file defines extra functions to std.traits. 44 45 Authors: Luís Ferreira <luis@aurorafoss.org> 46 Copyright: All rights reserved, Aurora Free Open Source Software 47 License: GNU Lesser General Public License (Version 3, 29 June 2007) 48 Date: 2018-2019 49 +/ 50 module aurorafw.stdx.traits; 51 52 public import std.traits; 53 54 import std.format; 55 import std.meta; 56 57 version (unittest) import aurorafw.unit.assertion; 58 59 /** 60 * Detect version identifiers 61 * 62 * This is a template to check if a version 63 * identifier is available. 64 * 65 * Examples: 66 * -------------------- 67 * static if(isVersion!"unittest") 68 * { 69 * // code with version unittest ... 70 * } 71 * -------------------- 72 */ 73 template isVersion(string ver) 74 { 75 mixin(format(q{ 76 version(%s) { 77 enum isVersion = true; 78 } 79 else { 80 enum isVersion = false; 81 } 82 }, ver)); 83 } 84 85 /// 86 @safe pure 87 @("Traits: isVersion") 88 unittest 89 { 90 assertTrue(isVersion!"unittest"); 91 assertFalse(isVersion!"this_shouldnt_be_a_version_identifier"); 92 } 93 94 /** 95 * Match functions return type 96 * 97 * This template match the return type of the passed functions 98 * and fail if there's more than one type (except typeof(null)) 99 */ 100 template MatchReturnType(funcs...) if (allSatisfy!(isSomeFunction, funcs)) 101 { 102 alias types = NoDuplicates!(staticMap!(Unqual, staticMap!(ReturnType, funcs))); 103 static assert(types.length == 1 || (types.length == 2 && is(types[1] == typeof( 104 null)))); 105 106 alias MatchReturnType = types[0]; 107 } 108 109 /// 110 @safe pure 111 @("Traits: MatchReturnType") 112 unittest 113 { 114 alias TL_1 = MatchReturnType!(void delegate(), void function(), void function( 115 string foo)); 116 assertTrue(is(TL_1 == void)); 117 assertFalse(is(TL_1 == string)); 118 119 alias TL_2 = MatchReturnType!(string delegate(), string function(), string function( 120 int foo), () => null); 121 assertTrue(is(TL_2 == string)); 122 assertTrue(is(MatchReturnType!(() => "atum") == string)); 123 } 124 125 version (unittest) 126 { 127 private interface IUnittestTestClass 128 { 129 } 130 131 private class UnittestTestClass 132 { 133 } 134 135 private struct UnittestTestStruct 136 { 137 } 138 } 139 140 /** 141 * Checks if type is typeof(null) 142 * Params: 143 * T = type or typeof a variable for null check 144 */ 145 template isNullType(alias T) 146 { 147 enum isNullType = is(typeof(T) == typeof(null)); 148 } 149 150 /// 151 @safe pure 152 @("Traits: isNullType") 153 unittest 154 { 155 int a; 156 int* b = null; 157 UnittestTestStruct c; 158 void f() 159 { 160 } 161 162 assertTrue(isNullType!null); 163 164 assertFalse(isNullType!a); 165 assertFalse(isNullType!b); 166 assertFalse(isNullType!c); 167 assertFalse(isNullType!f); 168 } 169 170 /** 171 * Checks if type is null testable 172 * 173 * Params: 174 * T = type or typeof a variable 175 */ 176 template isNullTestable(alias T) 177 { 178 enum isNullTestable = __traits(compiles, { 179 if (T.init is null) 180 { 181 } 182 }); 183 } 184 185 /// 186 @safe pure 187 @("Traits: isNullTestable") 188 unittest 189 { 190 class Class1 191 { 192 } 193 194 struct Struct1 195 { 196 void opAssign(int*) 197 { 198 } 199 } 200 201 assertFalse(isNullTestable!Struct1); 202 assertTrue(isNullTestable!Class1); 203 assertTrue(isNullTestable!(int*)); 204 205 assertFalse(isNullTestable!UnittestTestStruct); 206 assertFalse(isNullTestable!int); 207 208 class Class2 209 { 210 @disable this(); 211 } 212 213 assertTrue(isNullTestable!Class2); 214 } 215 216 /** 217 * Checks if type is settable to null 218 * Params: 219 * T = type or typeof a variable 220 */ 221 template isNullSettable(alias T) 222 { 223 enum isNullSettable = __traits(compiles, { typeof(T.init) t = T.init; t = null; }); 224 } 225 226 /// 227 @safe pure 228 @("Traits: isNullSettable") 229 unittest 230 { 231 assertTrue(isNullSettable!IUnittestTestClass); 232 assertTrue(isNullSettable!UnittestTestClass); 233 assertTrue(isNullSettable!(int[])); 234 assertTrue(isNullSettable!(int[string])); 235 assertTrue(isNullSettable!(typeof(null))); 236 assertTrue(isNullSettable!(int*)); 237 assertTrue(isNullSettable!(void function())); 238 assertTrue(isNullSettable!(void delegate())); 239 240 assertFalse(isNullSettable!int); 241 assertFalse(isNullSettable!float); 242 assertFalse(isNullSettable!double); 243 assertFalse(isNullSettable!bool); 244 assertFalse(isNullSettable!real); 245 assertFalse(isNullSettable!UnittestTestStruct); 246 247 struct Struct1 248 { 249 void opAssign(int*) 250 { 251 } 252 } 253 254 assertTrue(isNullSettable!Struct1); 255 256 struct Struct3 257 { 258 @disable this(); 259 void opAssign(int*) 260 { 261 } 262 } 263 264 assertTrue(isNullSettable!Struct3); 265 } 266 267 /** 268 * Get's an AliasSeq of types from the given arguments 269 */ 270 template TypesOf(Symbols...) 271 { 272 import std.meta : AliasSeq; 273 274 static if (Symbols.length) 275 { 276 static if (isFunction!(Symbols[0]) && is(typeof(&Symbols[0]) F)) 277 { 278 alias T = F; 279 } 280 else static if (is(typeof(Symbols[0]))) 281 { 282 alias T = typeof(Symbols[0]); 283 } 284 else 285 { 286 alias T = Symbols[0]; 287 } 288 alias TypesOf = AliasSeq!(T, TypesOf!(Symbols[1 .. $])); 289 } 290 else 291 { 292 alias TypesOf = AliasSeq!(); 293 } 294 } 295 296 /// 297 @safe pure 298 @("Traits: TypesOf") 299 unittest 300 { 301 assertTrue(is(TypesOf!("foo", 42U, 24, 123.0, float) == AliasSeq!(string, uint, int, double, float))); 302 assertTrue(is(TypesOf!(null) == AliasSeq!(typeof(null)))); 303 assertTrue(is(TypesOf!("foobar") == AliasSeq!(string))); 304 305 // check for static eval 306 static assert(is(TypesOf!("foobar") == AliasSeq!(string))); 307 } 308 309 /** 310 * Trait to verify if a module can be imported 311 * 312 * Params: 313 * moduleName = module to validate import 314 */ 315 template CanImport(string moduleName) 316 { 317 enum CanImport = __traits(compiles, { mixin("import " ~ moduleName ~ ";"); }); 318 } 319 320 /// 321 @safe pure 322 @("Traits: CanImport") 323 unittest 324 { 325 assertTrue(CanImport!"std.stdio"); 326 // check for static eval 327 static assert(CanImport!"std.stdio"); 328 329 assertFalse(CanImport!"this.module.doesnt.exists.dont.create.it"); 330 } 331 332 /** 333 * Check if module contains a symbol 334 * 335 * Params: 336 * moduleName = module to be imported 337 * symbolName = symbol to be checked 338 */ 339 template ModuleContainsSymbol(string moduleName, string symbolName) 340 { 341 enum ModuleContainsSymbol = CanImport!moduleName && __traits(compiles, { 342 mixin("import " ~ moduleName ~ ":" ~ symbolName ~ ";"); 343 }); 344 } 345 346 /// 347 @safe pure 348 @("Traits: ModuleContainsSymbol") 349 unittest 350 { 351 assertTrue(ModuleContainsSymbol!("std.stdio", "writeln")); 352 assertFalse(ModuleContainsSymbol!("std.stdio", "thissymboldoesntactuallyexist")); 353 354 // check for static eval 355 static assert(ModuleContainsSymbol!("std.stdio", "writeln")); 356 } 357 358 /** 359 * Checks if a certain literal or function return type is equal. 360 * Basically the same as is(... == ...) but resolves the function 361 * return type. 362 */ 363 template isOf(ab...) if (ab.length == 2) 364 { 365 alias Ts = TypesOf!ab; 366 template resolve(T) 367 { 368 import std.traits : isCallable, ReturnType; 369 370 static if (isCallable!T) 371 { 372 alias resolve = ReturnType!T; 373 } 374 else 375 { 376 alias resolve = T; 377 } 378 } 379 380 enum isOf = is(resolve!(Ts[0]) == resolve!(Ts[1])); 381 } 382 383 /// 384 @safe pure 385 @("Traits: isOf") 386 unittest 387 { 388 assertTrue(isOf!(int, 3)); 389 assertTrue(isOf!(7, 3)); 390 assertTrue(isOf!(3, int)); 391 assertFalse(isOf!(float, 3)); 392 assertFalse(isOf!(float, string)); 393 assertFalse(isOf!(string, 3)); 394 395 string foobar() 396 { 397 return ""; 398 } 399 400 assertTrue(isOf!(string, foobar)); 401 // cover foobar() 402 assertEquals("", foobar()); 403 404 // check static eval 405 static assert(isOf!(string, foobar)); 406 } 407 408 /** 409 * Checks if two symbols are the same in compile-time 410 * 411 * Params: 412 * lhs = left-hand symbol to compare 413 * rhs = right-hand symbol to compare 414 */ 415 template isSame(alias lhs, alias rhs) 416 { 417 418 // this should test if the type is bool easily with 419 // compiles trait 420 private static template expectBool(bool b) 421 { 422 } 423 424 // check if its a type or a value 425 static if (!__traits(compiles, typeof(lhs)) && !__traits(compiles, typeof(rhs))) 426 { 427 enum isSame = is(lhs == rhs); 428 // check if its comparable 429 } 430 else static if (__traits(compiles, typeof(lhs)) 431 && __traits(compiles, typeof(rhs)) 432 && __traits(compiles, expectBool!(lhs == rhs)) 433 ) 434 { 435 // check if its a rvalue 436 static if (!__traits(compiles, &lhs) || !__traits(compiles, &rhs)) 437 438 enum isSame = (lhs == rhs); 439 else // literal comparable 440 enum isSame = __traits(isSame, lhs, rhs); 441 } 442 else 443 { 444 // if none of this, fallback to isSame trait 445 enum isSame = __traits(isSame, lhs, rhs); 446 } 447 } 448 449 /// 450 @safe pure 451 @("Traits: isSame") 452 unittest 453 { 454 assertTrue(isSame!(int, int)); 455 assertFalse(isSame!(int, short)); 456 457 enum a = 1, b = 1, c = 2, s = "a", t = "a"; 458 assertTrue(isSame!(1, 1)); 459 assertTrue(isSame!(a, 1)); 460 assertTrue(isSame!(a, b)); 461 assertFalse(isSame!(b, c)); 462 assertTrue(isSame!("a", "a")); 463 assertTrue(isSame!(s, "a")); 464 assertTrue(isSame!(s, t)); 465 assertFalse(isSame!(s, "g")); 466 assertFalse(isSame!(1, "1")); 467 assertFalse(isSame!(a, "a")); 468 assertTrue(isSame!(isSame, isSame)); 469 assertFalse(isSame!(isSame, a)); 470 471 assertFalse(isSame!(byte, a)); 472 assertFalse(isSame!(short, isSame)); 473 assertFalse(isSame!(a, int)); 474 assertFalse(isSame!(long, isSame)); 475 476 static immutable X = 1, Y = 1, Z = 2; 477 assertTrue(isSame!(X, X)); 478 assertFalse(isSame!(X, Y)); 479 assertFalse(isSame!(Y, Z)); 480 481 int foo(); 482 int bar(); 483 real baz(int); 484 assertTrue(isSame!(foo, foo)); 485 assertFalse(isSame!(foo, bar)); 486 assertFalse(isSame!(bar, baz)); 487 assertTrue(isSame!(baz, baz)); 488 assertFalse(isSame!(foo, 0)); 489 490 int x, y; 491 real z; 492 assertTrue(isSame!(x, x)); 493 assertFalse(isSame!(x, y)); 494 assertFalse(isSame!(y, z)); 495 assertTrue(isSame!(z, z)); 496 assertFalse(isSame!(x, 0)); 497 }