1 /**
2 License:
3     Boost Software License - Version 1.0 - August 17th, 2003
4 
5     Permission is hereby granted, free of charge, to any person or organization
6     obtaining a copy of the software and accompanying documentation covered by
7     this license (the "Software") to use, reproduce, display, distribute,
8     execute, and transmit the Software, and to prepare derivative works of the
9     Software, and to permit third-parties to whom the Software is furnished to
10     do so, all subject to the following:
11 
12     The copyright notices in the Software and this entire statement, including
13     the above license grant, this restriction and the following disclaimer,
14     must be included in all copies of the Software, in whole or in part, and
15     all derivative works of the Software, unless such copies or derivative
16     works are solely in the form of machine-executable object code generated by
17     a source language processor.
18 
19     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21     FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22     SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23     FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24     ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25     DEALINGS IN THE SOFTWARE.
26 
27 Authors:
28     Alexandru Ermicioi
29 **/
30 module aermicioi.aedi_property_reader.convertor.type_guesser;
31 
32 /**
33 Interface for components that are able to guess the D type of serialized component.
34 **/
35 @safe interface TypeGuesser(SerializedType) {
36 
37     public {
38 
39         /**
40         Guess the D type of serialized based on information available in it.
41 
42         Params:
43             serialized = the component for which guesser will attempt to guess the type.
44 
45         Returns:
46             TypeInfo guessed type
47         **/
48         TypeInfo guess(SerializedType serialized) const;
49     }
50 }
51 
52 /**
53 A guesser that simply doesn't guess anything and just returns the SerializedType
54 **/
55 @safe class SimpleTypeGuesser(SerializedType) : TypeGuesser!SerializedType {
56 
57     public {
58 
59         /**
60         Guess the D type of serialized based on information available in it.
61 
62         Params:
63             serialized = the component for which guesser will attempt to guess the type.
64 
65         Returns:
66             TypeInfo guessed type
67         **/
68         TypeInfo guess(SerializedType serialized) const {
69             return typeid(SerializedType);
70         }
71     }
72 }
73 
74 /**
75 Guesser based on std.conv.to family of functions.
76 
77 Guesser based on std.conv.to family of functions. It will attempt to convert sequentially
78 to all ConvertableTypes until one succeeds, for which the typeinfo will be returned.
79 **/
80 @safe class StdConvTypeGuesser(SerializedType, ConvertableTypes...) : TypeGuesser!SerializedType {
81 
82     public {
83 
84         /**
85         Guess the D type of serialized based on eager attempts to convert serialized to one of ConvertableTypes.
86 
87         Params:
88             serialized = the component for which guesser will attempt to guess the type.
89 
90         Returns:
91             TypeInfo guessed type for which std.conv.to didn't fail.
92         **/
93         TypeInfo guess(SerializedType serialized) const {
94             import std.conv : to, ConvException;
95 
96             foreach (ConvertableType; ConvertableTypes) {
97                 try {
98                     cast(void) serialized.to!ConvertableType;
99                     return typeid(ConvertableType);
100                 } catch (ConvException ex) {
101 
102                 }
103             }
104 
105             bugfix: return typeid(SerializedType); // Well without this magical label flow analysis thinks that code won't reach up to this point, which is untrue.
106         }
107     }
108 }
109 
110 /**
111 A type guesser that will attempt to downcast passed object to a Type from Types list and
112 use particular type guesser on it.
113 **/
114 class DelegatingObjectTypeGuesser(Types...) : TypeGuesser!Object {
115     import std.meta : staticMap;
116     import aermicioi.aedi_property_reader.convertor.placeholder;
117 
118     staticMap!(TypeGuesser, Types) guessers;
119 
120     public {
121 
122         /**
123         Constructor for delegating object type guesser
124 
125         Params:
126             guessers = a list of guessers for this type guesser.
127         **/
128         this(typeof(this.guessers) guessers)
129         in {
130             import std.conv : text;
131             static foreach (guesser; guessers) {
132                 assert(guesser !is null, text("Expected a guesser of type ", typeid(guesser), " not null"));
133             }
134         }
135         do {
136             this.guessers = guessers;
137         }
138 
139         /**
140         Guess the D type of serialized based on eager attempts to convert serialized to one of ConvertableTypes.
141 
142         Params:
143             serialized = the component for which guesser will attempt to guess the type.
144 
145         Returns:
146             TypeInfo guessed type for which std.conv.to didn't fail.
147         **/
148         TypeInfo guess(Object serialized) const {
149             static foreach (index, Type; Types) {
150                 if (serialized.identify is typeid(Type)) {
151 
152                     return guessers[index].guess(serialized.unwrap!Type);
153                 }
154             }
155 
156             return typeid(Object);
157         }
158     }
159 }
160 
161 /**
162 Alias for StdConvTypeGuesser with serialized type as string.
163 **/
164 alias StringStdConvTypeGuesser(ConvertableTypes...) = StdConvTypeGuesser!(string, ConvertableTypes);
165 
166 /**
167 Alias for StringStdConvTypeGuesser with scalar types as convertable types.
168 **/
169 alias StringToScalarConvTypeGuesser = StringStdConvTypeGuesser!(
170     bool,
171     long,
172     double,
173     char,
174     bool[],
175     long[],
176     double[],
177     string[]
178 );