1 /* Create classes from their modules and names.
2  *
3  * Copyright: Copyright (C) D Language Foundation 2023
4  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
5  * Authors:   Walter Bright, Steven Schveighoffer
6  * Source:    $(DRUNTIMESRC core/_factory.d)
7  */
8 
9 module core.factory;
10 
11 /**
12  * Create instance of class specified by the module symbol and a string
13  * representing the name of the class.
14  * The class must either have no constructors or have
15  * a default constructor.
16  * Params:
17  *   mod = symbol representing the module that the class is in
18  *   classname = string representing the name of the class
19  * Returns:
20  *   null if failed
21  * Example:
22  * ---
23  * module foo.bar;
24  *
25  * class C
26  * {
27  *     this() { x = 10; }
28  *     int x;
29  * }
30  *
31  * void main()
32  * {
33  *     auto c = cast(C)factory!(foo.bar)("C");
34  *     assert(c !is null && c.x == 10);
35  * }
36  * ---
37  */
38 Object factory(alias mod)(string classname)
39 {
40     foreach(cl; _getModuleClasses!mod)
41     {
42         if (cl.stringof == classname)
43             return cl.classinfo.create();
44     }
45     return null;
46 }
47 
48 @system unittest
49 {
50     Object valid_obj = factory!object("Object");
51     Object invalid_obj = factory!object("__this_class_doesnt_exist__");
52 
53     assert(valid_obj !is null);
54     assert(invalid_obj is null);
55 }
56 
57 /**************************************
58  * Retrieve as a tuple all the types of the top level classes in the module mod.
59  */
60 private template _getModuleClasses(alias mod) {
61    alias result = _AliasSeq!();
62    static foreach(m; __traits(allMembers, mod))
63       static if(is(__traits(getMember, mod, m) == class))
64          result = _AliasSeq!(result, __traits(getMember, mod, m));
65    alias _getModuleClasses = result;
66 }
67 
68 private template _AliasSeq(TList...) { alias _AliasSeq = TList; }