1 /**
2     Lazy import symbols
3 */
4 module bolts.from;
5 
6 /**
7     Encompases the from import idiom in an opDispatch version
8 
9     Since:
10         - 0.12.0
11 
12     See_Also:
13         <li> https://dlang.org/blog/2017/02/13/a-new-import-idiom/
14         <li> https://forum.dlang.org/thread/gdipbdsoqdywuabnpzpe@forum.dlang.org
15 */
16 enum from = FromImpl!null();
17 
18 ///
19 unittest {
20     // Call a function
21     auto _0 = from.std.algorithm.map!"a"([1, 2, 3]);
22     // Assign an object
23     auto _1 = from.std.datetime.stopwatch.AutoStart.yes;
24 
25     // compile-time constraints
26     auto length(R)(R range) if (from.std.range.isInputRange!R) {
27         return from.std.range.walkLength(range);
28     }
29 
30     assert(length([1, 2]) == 2);
31 }
32 
33 private template CanImport(string moduleName) {
34     enum CanImport = __traits(compiles, { mixin("import ", moduleName, ";"); });
35 }
36 
37 private template ModuleContainsSymbol(string moduleName, string symbolName) {
38     enum ModuleContainsSymbol = CanImport!moduleName && __traits(compiles, {
39         mixin("import ", moduleName, ":", symbolName, ";");
40     });
41 }
42 
43 private struct FromImpl(string moduleName) {
44     template opDispatch(string symbolName) {
45         static if (ModuleContainsSymbol!(moduleName, symbolName)) {
46             mixin("import ", moduleName,";");
47             mixin("alias opDispatch = ", symbolName, ";");
48         } else {
49             static if (moduleName.length == 0) {
50                 enum opDispatch = FromImpl!(symbolName)();
51             } else {
52                 enum importString = moduleName ~ "." ~ symbolName;
53                 static assert(
54                     CanImport!importString,
55                     "Symbol \"" ~ symbolName ~ "\" not found in " ~ modueName
56                 );
57                 enum opDispatch = FromImpl!importString();
58             }
59         }
60     }
61 }
62 
63 unittest {
64     static assert(!__traits(compiles, { from.std.stdio.thisFunctionDoesNotExist(42); }));
65 }