-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
inlineimport: implement inlineimport
Signed-off-by: João Lourenço <[email protected]>
- Loading branch information
Showing
1 changed file
with
85 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
module taurus.inlineimport; | ||
|
||
/** | ||
Imports a symbol from a module inline. Useful for module dependencies with little | ||
usage. | ||
Checks are done in every symbol, meaning the sequence will fail on the first | ||
invalid symbol. $(BR) | ||
`From` should be used When compiled in **betterC**. Because `from` checks valid | ||
symbols from the start, the program fails if some module depends on something | ||
that isn't supported in **betterC**. | ||
- The following do not compile under `betterC`: | ||
- **`from.std.traits.isIntegral!byte`** | ||
- **`from.std.isIntegral!byte`** | ||
- **`From!"std".isIntegral!byte`** | ||
- The correct way to import is to specify the starting point with `From`: | ||
- **`From!"std.traits".isIntegral!byte`** | ||
Params: mod = module to search from. | ||
Examples: | ||
--- | ||
assert(from.std.traits.isIntegral!byte); | ||
assert(From!"std.array".split("Hello.World", ".") == ["Hello", "World"]); | ||
assert(!__traits(compiles, from.not.exists)); // fails at 'not' | ||
--- | ||
*/ | ||
enum From(string mod) = FromImpl!mod.init; | ||
enum from = From!null; /// | ||
|
||
version (D_BetterC) {} else | ||
/// | ||
@safe pure nothrow unittest | ||
{ | ||
assert(from.std.array.split("Hello.World", ".") == ["Hello", "World"]); | ||
assert(From!"std.array".split("Hello.World", ".") == ["Hello", "World"]); | ||
|
||
assert(from.std.split("Hello.World", ".") == ["Hello", "World"]); | ||
assert(From!"std".split("Hello.World", ".") == ["Hello", "World"]); | ||
|
||
assert(!__traits(compiles, from._does.not.exist)); | ||
} | ||
|
||
/// | ||
private struct FromImpl(string mod) | ||
{ | ||
template opDispatch(string sym) | ||
{ | ||
/* | ||
order is important: | ||
- mod is empty -> enum FromImpl!sym | ||
- mod.sym is valid -> enum FromImpl!mod.sym | ||
- mod : sym is valid -> alias sym | ||
*/ | ||
|
||
static if (!mod.length) | ||
{ | ||
static if(!isModule!sym) | ||
alias opDispatch = fail!("Unbale to locate module '" ~ sym ~ "'"); | ||
else | ||
enum opDispatch = FromImpl!sym.init; | ||
} | ||
|
||
else static if (isModule!(mod, ".", sym)) | ||
enum opDispatch = FromImpl!(mod ~ "." ~ sym).init; | ||
|
||
else | ||
{ | ||
static if(!inModule) | ||
alias opDispatch = fail!("Symbol '" ~ sym ~ "' not found in module '" ~ mod ~ "'"); | ||
else | ||
mixin("import ", mod, ":", sym, "; alias opDispatch = ", sym, ";"); | ||
} | ||
|
||
private enum isModule(T ...) = __traits(compiles, { mixin("import ", T, ";"); }); | ||
private enum inModule = __traits(compiles, { mixin("import ", mod, ":", sym, ";"); }); | ||
|
||
private template fail(string msg) | ||
{ | ||
noreturn fail(T ...)(auto ref T t) { static assert (false, msg); } | ||
} | ||
} | ||
} |