1 module dpp.runtime.namespace;
2 
3 /**
4    Uses a template mixin hack to "reopen" C++ namespace declarations in D
5  */
6 struct Namespace {
7     static struct Symbol {
8         string namespace;
9         string name;
10     }
11 
12     enum indentationSpaces = "    ";
13     private int _index;
14     private string[] _nestedNamespaces;
15     private Symbol[] _symbols;
16     private string _mixinName;
17 
18     string[] push(in string name) @safe pure {
19         import std.conv: text;
20         string[] lines;
21 
22         if(_nestedNamespaces.length == 0) {
23             _mixinName = text("_CppNamespace", _index);
24             lines ~= text("mixin template ", _mixinName, "() {");
25         }
26 
27         lines ~= indentationSpaces ~ text("extern(C++, ", name, ") {");
28         _nestedNamespaces ~= name;
29 
30         return lines;
31     }
32 
33     string[] pop() @safe pure {
34 
35         _nestedNamespaces = _nestedNamespaces[0 .. $-1];
36         auto lines = [indentationSpaces ~ "}"];
37 
38         if(_nestedNamespaces.length == 0) {
39             lines ~= finish;
40         }
41 
42         return lines;
43     }
44 
45     void addSymbol(in string symbol) @safe pure {
46         import std.array: join;
47         if(symbol != "")
48             _symbols ~= Symbol(_nestedNamespaces.join("."), symbol);
49     }
50 
51     private string[] finish() @safe pure {
52         import std.conv: text;
53         import std.algorithm: map, uniq;
54         import std.array: array;
55 
56         auto lines = ["}", ""];
57 
58         const varName = text("_cppNamespace_", _index);
59         lines ~= text("mixin ", _mixinName, "!() ", varName, ";");
60 
61         string aliasText(in Symbol s) {
62             return text("alias ", s.name, " = ", varName, ".", s.namespace, ".", s.name, `;`);
63         }
64 
65         lines ~= _symbols
66             .uniq!((a, b) => a.name == b.name)
67             .map!(s => `static if(is(typeof({ ` ~ aliasText(s) ~ ` }))) ` ~ aliasText(s) ~ `;`)
68             .array
69             ;
70 
71         reset;
72 
73         return lines;
74     }
75 
76     private void reset() @safe pure {
77         _mixinName = "";
78         _index++;
79         _symbols = [];
80     }
81 }