001/*
002 * Configurate
003 * Copyright (C) zml and Configurate contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package ninja.leaping.configurate;
018
019import com.google.common.collect.ImmutableList;
020import com.google.common.collect.Iterables;
021import com.google.common.reflect.TypeToken;
022import ninja.leaping.configurate.loader.ConfigurationLoader;
023import ninja.leaping.configurate.objectmapping.ObjectMappingException;
024import ninja.leaping.configurate.objectmapping.serialize.TypeSerializer;
025import org.checkerframework.checker.nullness.qual.NonNull;
026import org.checkerframework.checker.nullness.qual.Nullable;
027
028import java.util.Collection;
029import java.util.List;
030import java.util.Map;
031import java.util.function.Consumer;
032import java.util.function.Function;
033import java.util.function.Supplier;
034
035import static java.util.Objects.requireNonNull;
036
037/**
038 * A node in the configuration tree.
039 *
040 * <p>All aspects of a configurations structure are represented using instances of
041 * {@link ConfigurationNode}, and the links between them.</p>
042 *
043 * <p>{@link ConfigurationNode}s can hold different types of {@link ValueType values}. They can:</p>
044 *
045 * <ul>
046 *     <li>Hold a single "scalar" value ({@link ValueType#SCALAR})</li>
047 *     <li>Represent a "list" of child {@link ConfigurationNode}s ({@link ValueType#LIST})</li>
048 *     <li>Represent a "map" of child {@link ConfigurationNode}s ({@link ValueType#MAP})</li>
049 *     <li>Hold no value at all ({@link ValueType#NULL})</li>
050 * </ul>
051 *
052 * <p>The overall configuration stems from a single "root" node, which is provided by the
053 * {@link ConfigurationLoader}, or by other means programmatically.</p>
054 *
055 * <p>This is effectively the main class of Configurate.</p>
056 */
057public interface ConfigurationNode {
058    int NUMBER_DEF = 0;
059
060    @NonNull
061    static ConfigurationNode root() {
062        return root(ConfigurationOptions.defaults());
063    }
064
065    @NonNull
066    static ConfigurationNode root(Consumer<ConfigurationNode> action) {
067        return root(ConfigurationOptions.defaults(), action);
068    }
069
070    @NonNull
071    static ConfigurationNode root(@NonNull ConfigurationOptions options) {
072        return new SimpleConfigurationNode(null, null, options);
073    }
074
075    @NonNull
076    static ConfigurationNode root(@NonNull ConfigurationOptions options, Consumer<ConfigurationNode> action) {
077        return new SimpleConfigurationNode(null, null, options).act(action);
078    }
079
080    /**
081     * Gets the "key" of this node.
082     *
083     * <p>The key determines this {@link ConfigurationNode}s position within the overall
084     * configuration structure.</p>
085     *
086     * <p>If this node is currently {@link #isVirtual() virtual}, this method's result may be
087     * inaccurate.</p>
088     *
089     * <p>Note that this method only returns the nearest "link" in the hierarchy, and does not
090     * return a representation of the full path. See {@link #getPath()} for that.</p>
091     *
092     * <p>The {@link ConfigurationNode}s returned as values from {@link #getChildrenMap()} will
093     * have keys derived from their pairing in the map node.</p>
094     *
095     * <p>The {@link ConfigurationNode}s returned from {@link #getChildrenList()} will have keys
096     * derived from their position (index) in the list node.</p>
097     *
098     * @return The key of this node
099     */
100    @Nullable
101    Object getKey();
102
103    /**
104     * Gets the full path of {@link #getKey() keys} from the root node to this node.
105     *
106     * <p>Node implementations may not keep a full path for each node, so this method may be
107     * somewhat complex to calculate. Most uses should not need to calculate the full path unless providing debug information</p>
108     *
109     * @return An array compiled from the keys for each node up the hierarchy
110     * @see #getKey() for this node's key relative to its direct parent
111     */
112    @NonNull
113    Object[] getPath();
114
115    /**
116     * Gets the parent of this node.
117     *
118     * <p>If this node is currently {@link #isVirtual() virtual}, this method's result may be
119     * inaccurate.</p>
120     *
121     * @return The nodes parent
122     */
123    @Nullable
124    ConfigurationNode getParent();
125
126    /**
127     * Gets the node at the given (relative) path, possibly traversing multiple levels of nodes.
128     *
129     * <p>This is the main method used to navigate through the configuration.</p>
130     *
131     * <p>The path parameter effectively consumes an array of keys, which locate the unique position
132     * of a given node within the structure. Each element will navigate one level down in the configration hierarchy</p>
133     *
134     * <p>A node is <b>always</b> returned by this method. If the given node does not exist in the
135     * structure, a {@link #isVirtual() virtual} node will be returned which represents the
136     * position.</p>
137     *
138     * @param path The path to fetch the node at
139     * @return The node at the given path, possibly virtual
140     */
141    @NonNull
142    ConfigurationNode getNode(@NonNull Object @NonNull... path);
143
144    /**
145     * Gets the node at the given (relative) path, possibly traversing multiple levels of nodes.
146     *
147     * <p>This is the main method used to navigate through the configuration.</p>
148     *
149     * <p>The path parameter effectively consumes an iterable of keys, which locate the unique position
150     * of a given node within the structure.</p>
151     *
152     * <p>A node is <b>always</b> returned by this method. If the given node does not exist in the
153     * structure, a {@link #isVirtual() virtual} node will be returned which represents the
154     * position.</p>
155     *
156     * @param path The path to fetch the node at
157     * @return The node at the given path, possibly virtual
158     */
159    @NonNull
160    default ConfigurationNode getNode(@NonNull Iterable<?> path) {
161        return getNode(Iterables.toArray(requireNonNull(path, "path"), Object.class));
162    }
163
164    /**
165     * Gets if this node is virtual.
166     *
167     * <p>Virtual nodes are nodes which are not attached to a wider configuration structure.</p>
168     *
169     * <p>A node is primarily "virtual" when it has no set value.</p>
170     *
171     * @return true if this node is virtual
172     */
173    boolean isVirtual();
174
175    /**
176     * Gets the options that currently apply to this node
177     *
178     * @return The ConfigurationOptions instance that governs the functionality of this node
179     */
180    @NonNull
181    ConfigurationOptions getOptions();
182
183    /**
184     * Gets the value type of this node.
185     *
186     * @return The value type
187     * @deprecated Use {@link ConfigurationNode#isList()} and {@link ConfigurationNode#isMap()} for the same information
188     */
189    @NonNull
190    @Deprecated
191    ValueType getValueType();
192
193    /**
194     * Gets if this node has "list children".
195     *
196     * @return if this node has children in the form of a list
197     */
198    default boolean isList() {
199        return getValueType() == ValueType.LIST;
200    }
201
202    /**
203     * Gets if this node has "map children".
204     *
205     * @return if this node has children in the form of a map
206     */
207    default boolean isMap() {
208        return getValueType() == ValueType.MAP;
209    }
210
211    /**
212     * Gets if this node has "list children".
213     *
214     * @return if this node has children in the form of a list
215     * @deprecated Use {@link #isList()} instead
216     */
217    @Deprecated
218    default boolean hasListChildren() {
219        return isList();
220    }
221
222    /**
223     * Gets if this node has "map children"
224     *
225     * @return if this node has children in the form of a map
226     * @deprecated Use {@link #isMap()} instead
227     */
228    @Deprecated
229    default boolean hasMapChildren() {
230        return isMap();
231    }
232
233    /**
234     * Return true when this node has a null or empty value. Values that may result in this method returning true include:
235     *
236     * <ul>
237     *     <li><code>null</code></li>
238     *     <li>the empty string</li>
239     *     <li>an empty map</li>
240     *     <li>an empty list</li>
241     *     <li>Any other type of empty collection</li>
242     * </ul>
243     *
244     * This is a distinct value from {@link #isVirtual()}. Emptiness refers to the value of this node itself,
245     * while virtuality refers to whether or not this node is attached to its parent and the rest of the configuration
246     * structure.
247     *
248     * @return Whether this node is empty
249     */
250    default boolean isEmpty() { // backwards compat
251        if (isVirtual()) {
252            return true;
253        }
254
255        if (isMap()) {
256            return getChildrenMap().isEmpty();
257        } else if (isList()) {
258            return getChildrenList().isEmpty();
259        } else {
260            return getValue() == null;
261        }
262    }
263
264    /**
265     * Gets the "list children" attached to this node, if it has any.
266     *
267     * <p>If this node does not {@link #isList() have list children}, an empty list is
268     * returned. For example, if the value of this node is a map, this will return an empty result.</p>
269     *
270     * @return The list children currently attached to this node
271     */
272    @NonNull
273    List<? extends ConfigurationNode> getChildrenList();
274
275    /**
276     * Gets the "map children" attached to this node, if it has any.
277     *
278     * <p>If this node does not {@link #isMap() have map children}, an empty map
279     * returned.</p>
280     *
281     * @return The map children currently attached to this node
282     */
283    @NonNull
284    Map<Object, ? extends ConfigurationNode> getChildrenMap();
285
286    /**
287     * Get the current value associated with this node.
288     *
289     * <p>If this node has children, this method will recursively unwrap them to construct a List
290     * or a Map.</p>
291     *
292     * @see #getValue(Object)
293     * @return This configuration's current value, or null if there is none
294     */
295    @Nullable
296    default Object getValue() {
297        return getValue((Object) null);
298    }
299
300    /**
301     * Get the current value associated with this node.
302     *
303     * <p>If this node has children, this method will recursively unwrap them to construct a List
304     * or a Map.</p>
305     *
306     * @param def The default value to return if this node has no set value
307     * @return This configuration's current value, or {@code def} if there is none
308     */
309    Object getValue(@Nullable Object def);
310
311    /**
312     * Get the current value associated with this node.
313     *
314     * <p>If this node has children, this method will recursively unwrap them to construct a List
315     * or a Map.</p>
316     *
317     * @param defSupplier The function that will be called to calculate a default value only if
318     *                    there is no existing value
319     * @return This configuration's current value, or {@code def} if there is none
320     */
321    Object getValue(@NonNull Supplier<Object> defSupplier);
322
323    /**
324     * Gets the appropriately transformed typed version of this node's value from the provided
325     * transformation function.
326     *
327     * @param transformer The transformation function
328     * @param <T> The expected type
329     * @return A transformed value of the correct type, or null either if no value is present or the
330     * value could not be converted
331     */
332    @Nullable
333    default <T> T getValue(@NonNull Function<Object, T> transformer) {
334        return getValue(transformer, (T) null);
335    }
336
337    /**
338     * Gets the appropriately transformed typed version of this node's value from the provided
339     * transformation function.
340     *
341     * @param transformer The transformation function
342     * @param def The default value to return if this node has no set value or is not of a
343     *            convertible type
344     * @param <T> The expected type
345     * @return A transformed value of the correct type, or {@code def} either if no value is present
346     * or the value could not be converted
347     */
348    <T> T getValue(@NonNull Function<Object, T> transformer, @Nullable T def);
349
350    /**
351     * Gets the appropriately transformed typed version of this node's value from the provided
352     * transformation function.
353     *
354     * @param transformer The transformation function
355     * @param defSupplier The function that will be called to calculate a default value only if
356     *                    there is no existing value of the correct type
357     * @param <T> The expected type
358     * @return A transformed value of the correct type, or {@code def} either if no value is present
359     * or the value could not be converted
360     */
361    <T> T getValue(@NonNull Function<Object, T> transformer, @NonNull Supplier<T> defSupplier);
362
363    /**
364     * If this node has list values, this function unwraps them and converts them to an appropriate
365     * type based on the provided function.
366     *
367     * <p>If this node has a scalar value, this function treats it as a list with one value</p>
368     *
369     * @param transformer The transformation function
370     * @param <T> The expected type
371     * @return An immutable copy of the values contained
372     */
373    @NonNull
374    <T> List<T> getList(@NonNull Function<Object, T> transformer);
375
376    /**
377     * If this node has list values, this function unwraps them and converts them to an appropriate
378     * type based on the provided function.
379     *
380     * <p>If this node has a scalar value, this function treats it as a list with one value.</p>
381     *
382     * @param transformer The transformation function
383     * @param def The default value if no appropriate value is set
384     * @param <T> The expected type
385     * @return An immutable copy of the values contained that could be successfully converted, or {@code def} if no
386     * values could be converted
387     */
388    <T> List<T> getList(@NonNull Function<Object, T> transformer, @Nullable List<T> def);
389
390    /**
391     * If this node has list values, this function unwraps them and converts them to an appropriate
392     * type based on the provided function.
393     *
394     * <p>If this node has a scalar value, this function treats it as a list with one value.</p>
395     *
396     * @param transformer The transformation function
397     * @param defSupplier The function that will be called to calculate a default value only if there is no existing
398     *                    value of the correct type
399     * @param <T> The expected type
400     * @return An immutable copy of the values contained that could be successfully converted, or {@code def} if no
401     * values could be converted
402     */
403    <T> List<T> getList(@NonNull Function<Object, T> transformer, @NonNull Supplier<List<T>> defSupplier);
404
405    /**
406     * If this node has list values, this function unwraps them and converts them to an appropriate
407     * type based on the provided function.
408     *
409     * <p>If this node has a scalar value, this function treats it as a list with one value.</p>
410     *
411     * @param type The expected type
412     * @param <T> The expected type
413     * @return An immutable copy of the values contained
414     * @throws ObjectMappingException If any value fails to be converted to the requested type
415     */
416    @NonNull
417    default <T> List<T> getList(@NonNull TypeToken<T> type) throws ObjectMappingException {
418        return getList(type, ImmutableList.of());
419    }
420
421    /**
422     * If this node has list values, this function unwraps them and converts them to an appropriate
423     * type based on the provided function.
424     *
425     * <p>If this node has a scalar value, this function treats it as a list with one value.</p>
426     *
427     * @param type The expected type
428     * @param def The default value if no appropriate value is set
429     * @param <T> The expected type
430     * @return An immutable copy of the values contained that could be successfully converted, or {@code def} if no
431     * values could be converted
432     * @throws ObjectMappingException If any value fails to be converted to the requested type
433     */
434    <T> List<T> getList(@NonNull TypeToken<T> type, @Nullable List<T> def) throws ObjectMappingException;
435
436    /**
437     * If this node has list values, this function unwraps them and converts them to an appropriate
438     * type based on the provided function.
439     *
440     * <p>If this node has a scalar value, this function treats it as a list with one value.</p>
441     *
442     * @param type The expected type
443     * @param defSupplier The function that will be called to calculate a default value only if there is no existing
444     *                    value of the correct type
445     * @param <T> The expected type
446     * @return An immutable copy of the values contained that could be successfully converted, or {@code def} if no
447     * values could be converted
448     * @throws ObjectMappingException If any value fails to be converted to the requested type
449     */
450    <T> List<T> getList(@NonNull TypeToken<T> type, @NonNull Supplier<List<T>> defSupplier) throws ObjectMappingException;
451
452    /**
453     * Gets the value typed using the appropriate type conversion from {@link Types}
454     *
455     * @see #getValue()
456     * @return The appropriate type conversion, null if no appropriate value is available
457     */
458    @Nullable
459    default String getString() {
460        return getString(null);
461    }
462
463    /**
464     * Gets the value typed using the appropriate type conversion from {@link Types}
465     *
466     * @param def The default value if no appropriate value is set
467     * @see #getValue()
468     * @return The appropriate type conversion, {@code def} if no appropriate value is available
469     */
470    default String getString(@Nullable String def) {
471        return getValue(Types::asString, def);
472    }
473
474    /**
475     * Gets the value typed using the appropriate type conversion from {@link Types}
476     *
477     * @see #getValue()
478     * @return The appropriate type conversion, 0 if no appropriate value is available
479     */
480    default float getFloat() {
481        return getFloat(NUMBER_DEF);
482    }
483
484    /**
485     * Gets the value typed using the appropriate type conversion from {@link Types}
486     *
487     * @param def The default value if no appropriate value is set
488     * @see #getValue()
489     * @return The appropriate type conversion, {@code def} if no appropriate value is available
490     */
491    default float getFloat(float def) {
492        return getValue(Types::asFloat, def);
493    }
494
495    /**
496     * Gets the value typed using the appropriate type conversion from {@link Types}
497     *
498     * @see #getValue()
499     * @return The appropriate type conversion, 0 if no appropriate value is available
500     */
501    default double getDouble() {
502        return getDouble(NUMBER_DEF);
503    }
504
505    /**
506     * Gets the value typed using the appropriate type conversion from {@link Types}
507     *
508     * @param def The default value if no appropriate value is set
509     * @see #getValue()
510     * @return The appropriate type conversion, {@code def} if no appropriate value is available
511     */
512    default double getDouble(double def) {
513        return getValue(Types::asDouble, def);
514    }
515
516    /**
517     * Gets the value typed using the appropriate type conversion from {@link Types}
518     *
519     * @see #getValue()
520     * @return The appropriate type conversion, 0 if no appropriate value is available
521     */
522    default int getInt() {
523        return getInt(NUMBER_DEF);
524    }
525
526    /**
527     * Gets the value typed using the appropriate type conversion from {@link Types}
528     *
529     * @param def The default value if no appropriate value is set
530     * @see #getValue()
531     * @return The appropriate type conversion, {@code def} if no appropriate value is available
532     */
533    default int getInt(int def) {
534        return getValue(Types::asInt, def);
535    }
536
537    /**
538     * Gets the value typed using the appropriate type conversion from {@link Types}
539     *
540     * @see #getValue()
541     * @return The appropriate type conversion, 0 if no appropriate value is available
542     */
543    default long getLong() {
544        return getLong(NUMBER_DEF);
545    }
546
547    /**
548     * Gets the value typed using the appropriate type conversion from {@link Types}
549     *
550     * @param def The default value if no appropriate value is set
551     * @see #getValue()
552     * @return The appropriate type conversion, {@code def} if no appropriate value is available
553     */
554    default long getLong(long def) {
555        return getValue(Types::asLong, def);
556    }
557
558    /**
559     * Gets the value typed using the appropriate type conversion from {@link Types}
560     *
561     * @see #getValue()
562     * @return The appropriate type conversion, false if no appropriate value is available
563     */
564    default boolean getBoolean() {
565        return getBoolean(false);
566    }
567
568    /**
569     * Gets the value typed using the appropriate type conversion from {@link Types}
570     *
571     * @param def The default value if no appropriate value is set
572     * @see #getValue()
573     * @return The appropriate type conversion, {@code def} if no appropriate value is available
574     */
575    default boolean getBoolean(boolean def) {
576        return getValue(Types::asBoolean, def);
577    }
578
579    /**
580     * Get the current value associated with this node.
581     *
582     * <p>If this node has children, this method will recursively unwrap them to construct a
583     * List or a Map.</p>
584     *
585     * <p>This method will also perform deserialization using the appropriate TypeSerializer for
586     * the given type, or casting if no type serializer is found.</p>
587     *
588     * @param type The type to deserialize to
589     * @param <T> the type to get
590     * @return the value if present and of the proper type, else null
591     * @throws ObjectMappingException If the value fails to be converted to the requested type
592     */
593    @Nullable
594    default <T> T getValue(@NonNull TypeToken<T> type) throws ObjectMappingException {
595        return getValue(type, (T) null);
596    }
597
598    /**
599     * Get the current value associated with this node.
600     *
601     * <p>If this node has children, this method will recursively unwrap them to construct a
602     * List or a Map.</p>
603     *
604     * <p>This method will also perform deserialization using the appropriate TypeSerializer for
605     * the given type, or casting if no type serializer is found.</p>
606     *
607     * @param type The type to deserialize to
608     * @param def The value to return if no value or value is not of appropriate type
609     * @param <T> the type to get
610     * @return the value if of the proper type, else {@code def}
611     * @throws ObjectMappingException If the value fails to be converted to the requested type
612     */
613    <T> T getValue(@NonNull TypeToken<T> type, T def) throws ObjectMappingException;
614
615    /**
616     * Get the current value associated with this node.
617     *
618     * <p>If this node has children, this method will recursively unwrap them to construct a
619     * List or a Map.</p>
620     *
621     * <p>This method will also perform deserialization using the appropriate TypeSerializer for
622     * the given type, or casting if no type serializer is found.</p>
623     *
624     * @param type The type to deserialize to
625     * @param defSupplier The function that will be called to calculate a default value only if there is no existing
626     *                    value of the correct type
627     * @param <T> the type to get
628     * @return the value if of the proper type, else {@code def}
629     * @throws ObjectMappingException If the value fails to be converted to the requested type
630     */
631    <T> T getValue(@NonNull TypeToken<T> type, @NonNull Supplier<T> defSupplier) throws ObjectMappingException;
632
633    /**
634     * Set this node's value to the given value.
635     *
636     * <p>If the provided value is a {@link Collection} or a {@link Map}, it will be unwrapped into
637     * the appropriate configuration node structure.</p>
638     *
639     * This method only accepts <em>native types</em> as values. If the type of a value is unknown at runtime,
640     * {@link ConfigurationOptions#acceptsType(Class)} will return whether or not it is a native type.
641     *
642     * @param value The value to set
643     * @return this
644     * @see #setValue(TypeToken, Object) to set a value with any type conversion necessary
645     */
646    @NonNull
647    ConfigurationNode setValue(@Nullable Object value);
648
649    /**
650     * Set this node's value to the given value.
651     *
652     * <p>If the provided value is a {@link Collection} or a {@link Map}, it will be unwrapped into
653     * the appropriate configuration node structure.</p>
654     *
655     * <p>This method will also perform serialization using the appropriate TypeSerializer for the
656     * given type, or casting if no type serializer is found.</p>
657     *
658     * @param type The type to use for serialization type information
659     * @param value The value to set
660     * @param <T> The type to serialize to
661     * @return this
662     * @throws ObjectMappingException If the value fails to be converted to the requested type. No change will be made to the node.
663     */
664    @NonNull
665    default <T> ConfigurationNode setValue(@NonNull TypeToken<T> type, @Nullable T value) throws ObjectMappingException {
666        if (value == null) {
667            setValue(null);
668            return this;
669        }
670
671        TypeSerializer<T> serial = getOptions().getSerializers().get(type);
672        if (serial != null) {
673            serial.serialize(type, value, this);
674        } else if (getOptions().acceptsType(value.getClass())) {
675            setValue(value); // Just write if no applicable serializer exists?
676        } else {
677            throw new ObjectMappingException("No serializer available for type " + type);
678        }
679        return this;
680    }
681
682    /**
683     * Set all the values from the given node that are not present in this node
684     * to their values in the provided node.
685     *
686     * <p>Map keys will be merged. Lists and scalar values will be replaced.</p>
687     *
688     * @param other The node to merge values from
689     * @return this
690     */
691    @NonNull
692    ConfigurationNode mergeValuesFrom(@NonNull ConfigurationNode other);
693
694    /**
695     * Removes a direct child of this node
696     *
697     * @param key The key of the node to remove
698     * @return If a node was removed
699     */
700    boolean removeChild(@NonNull Object key);
701
702    /**
703     * Gets a new child node created as the next entry in the list.
704     *
705     * @return A new child created as the next entry in the list when it is attached
706     * @deprecated Use {@link #appendListNode()} instead
707     */
708    @Deprecated
709    @NonNull
710    ConfigurationNode getAppendedNode();
711
712    /**
713     * Gets a new child node created as the next entry in the list.
714     *
715     * @return A new child created as the next entry in the list when it is attached
716     */
717    @NonNull
718    default ConfigurationNode appendListNode() {
719        return getAppendedNode();
720    }
721
722    /**
723     * Creates a deep copy of this node.
724     *
725     * <p>If this node has child nodes (is a list or map), the child nodes will
726     * also be copied. This action is performed recursively.</p>
727     *
728     * <p>The resultant node will (initially) contain the same value(s) as this node,
729     * and will therefore be {@link Object#equals(Object) equal}, however, changes made to
730     * the original will not be reflected in the copy, and vice versa.</p>
731     *
732     * <p>The actual scalar values that back the configuration will
733     * <strong>not</strong> be copied - only the node structure that forms the
734     * configuration. This is not a problem in most cases, as the scalar values
735     * stored in configurations are usually immutable. (e.g. strings, numbers, booleans).</p>
736     *
737     * @return A copy of this node
738     */
739    @NonNull
740    ConfigurationNode copy();
741
742    /**
743     * Execute an action on this node. This allows performing multiple operations
744     * on a single node without having to clutter up the surrounding scope.
745     *
746     * @param action The action to perform on this node
747     * @return this
748     */
749    default ConfigurationNode act(Consumer<? super ConfigurationNode> action) {
750        action.accept(this);
751        return this;
752    }
753
754    /**
755     * Visit this node hierarchy as described in {@link ConfigurationVisitor}
756     *
757     * @param visitor The visitor
758     * @param <S> The state type
759     * @param <T> The terminal type
760     * @param <E> exception type that may be thrown
761     * @throws E when throw by visitor implementation
762     * @return The returned terminal from the visitor
763     */
764    default <S, T, E extends Exception> T visit(ConfigurationVisitor<S, T, E> visitor) throws E {
765        return visit(visitor, visitor.newState());
766    }
767
768    /**
769     * Visit this node hierarchy as described in {@link ConfigurationVisitor}
770     *
771     * @param visitor The visitor
772     * @param state The state to start with
773     * @param <T> The terminal type
774     * @param <S> The state type
775     * @param <E> exception type that may be thrown
776     * @throws E when throw by visitor implementation
777     * @return The returned terminal from the visitor
778     */
779    default <S, T, E extends Exception> T visit(ConfigurationVisitor<S, T, E> visitor, S state) throws E {
780        throw new UnsupportedOperationException("Nodes of type " + getClass() + " do not support visitations!");
781    }
782
783    /**
784     * Visit this node hierarchy as described in {@link ConfigurationVisitor}
785     * This overload will remove the need for exception handling for visitors that do not have any checked exceptions.
786     *
787     * @param visitor The visitor
788     * @param <S> The state type
789     * @param <T> The terminal type
790     * @return The returned terminal from the visitor
791     */
792    default <S, T> T visit(ConfigurationVisitor.Safe<S, T> visitor) {
793        return visit(visitor, visitor.newState());
794    }
795
796    /**
797     * Visit this node hierarchy as described in {@link ConfigurationVisitor}
798     * This overload will remove the need for exception handling for visitors that do not have any checked exceptions.
799     *
800     * @param visitor The visitor
801     * @param state The state to start with
802     * @param <T> The terminal type
803     * @param <S> The state type
804     * @return The returned terminal from the visitor
805     */
806    default <S, T> T visit(ConfigurationVisitor.Safe<S, T> visitor, S state) {
807        throw new UnsupportedOperationException("Nodes of type " + getClass() + " do not support visitations!");
808    }
809
810}