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.yaml.accessor;
31 
32 import dyaml;
33 import aermicioi.aedi_property_reader.core.accessor;
34 import aermicioi.aedi.exception.not_found_exception : NotFoundException;
35 import std.exception;
36 import std.experimental.logger;
37 import aermicioi.aedi_property_reader.core.traits : n;
38 
39 /**
40 An accessor allowing access to child yaml nodes of a parent yaml node by their name
41 **/
42 class YamlNodePropertyAccessor : PropertyAccessor!(Node, Node) {
43 
44     /**
45      Get a property out of component
46 
47      Params:
48          component = a component which has some properties identified by property.
49      Throws:
50          NotFoundException in case when no requested property is available.
51          InvalidArgumentException in case when passed arguments are somehow invalid for use.
52      Returns:
53          FieldType accessed property.
54      **/
55     Node access(Node component, in string property) const {
56 
57         if (this.has(component, property)) {
58             return component[property];
59         }
60 
61         throw new NotFoundException("yaml tag " ~ component.tag ~ " doesn't have child " ~ property);
62     }
63 
64     /**
65      Check if requested property is present in component.
66 
67      Check if requested property is present in component.
68      The method could have allocation side effects due to the fact that
69      it is not restricted in calling access method of the accessor.
70 
71      Params:
72          component = component which is supposed to have property
73          property = speculated property that is to be tested if it is present in component
74      Returns:
75          true if property is in component
76      **/
77     bool has(in Node component, in string property) const nothrow {
78         try {
79             return component.isMapping && component.containsKey(property);
80         } catch (Exception e) {
81 
82             debug(trace) error("Failed to check property ", property, " existence due to ", e).n;
83         }
84 
85         return false;
86     }
87 
88     /**
89      Identify the type of supported component.
90 
91      Identify the type of supported component. It returns type info of component
92      if it is supported by accessor, otherwise it will return typeid(void) denoting that
93      the type isn't supported by accessor. The accessor is not limited to returning the type
94      info of passed component, it can actually return type info of super type or any type
95      given the returned type is implicitly convertible or castable to ComponentType.
96 
97      Params:
98          component = the component for which accessor should identify the underlying type
99 
100      Returns:
101          TypeInfo type information about passed component, or typeid(void) if component is not supported.
102      **/
103     TypeInfo componentType(Node component) const nothrow {
104         return typeid(Node);
105     }
106 }
107 
108 /**
109 An accessor allowing access to child yaml nodes of a parent yaml node by their index
110 **/
111 class YamlIntegerIndexAccessor : PropertyAccessor!(Node, Node) {
112 
113     /**
114      Get a property out of component
115 
116      Params:
117          component = a component which has some properties identified by property.
118      Throws:
119          NotFoundException in case when no requested property is available.
120          InvalidArgumentException in case when passed arguments are somehow invalid for use.
121      Returns:
122          FieldType accessed property.
123      **/
124     Node access(Node component, in string property) const {
125 
126         if (this.has(component, property)) {
127             import std.conv : to;
128 
129             return component[property.to!size_t];
130         }
131 
132         throw new NotFoundException("yaml tag " ~ component.tag ~ " doesn't have child on index " ~ property);
133     }
134 
135     /**
136      Check if requested property is present in component.
137 
138      Check if requested property is present in component.
139      The method could have allocation side effects due to the fact that
140      it is not restricted in calling access method of the accessor.
141 
142      Params:
143          component = component which is supposed to have property
144          property = speculated property that is to be tested if it is present in component
145      Returns:
146          true if property is in component
147      **/
148     bool has(in Node component, in string property) const nothrow {
149         try {
150             import std.string;
151             import std.conv;
152 
153             return property.isNumeric && component.isSequence && (property.to!size_t < component.length);
154         } catch (Exception e) {
155 
156             debug(trace) error("Failed to check property ", property, " existence due to ", e).n;
157         }
158 
159         return false;
160     }
161 
162     /**
163      Identify the type of supported component.
164 
165      Identify the type of supported component. It returns type info of component
166      if it is supported by accessor, otherwise it will return typeid(void) denoting that
167      the type isn't supported by accessor. The accessor is not limited to returning the type
168      info of passed component, it can actually return type info of super type or any type
169      given the returned type is implicitly convertible or castable to ComponentType.
170 
171      Params:
172          component = the component for which accessor should identify the underlying type
173 
174      Returns:
175          TypeInfo type information about passed component, or typeid(void) if component is not supported.
176      **/
177     TypeInfo componentType(Node component) const nothrow {
178         return typeid(Node);
179     }
180 
181 }