net.diversionmc.d3.StorageView Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of D3 Show documentation
Show all versions of D3 Show documentation
Diversion Network Data v3 (D3) standard using Parser API.
The newest version!
package net.diversionmc.d3;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import static java.lang.System.arraycopy;
import static java.util.Arrays.copyOf;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.joining;
import static java.util.stream.IntStream.range;
/**
* Storage Path structure gives convenient access to Storage manipulation of levels and values.
*
* Paths are strings separated by dots. Usually they are combined from objects converted to strings.
*/
public record StorageView(Storage storage, Object... path) implements Storage {
public StorageView(Storage storage, Object... path) {
if (storage instanceof StorageView view) {
this.storage = view.storage;
this.path = combine(view.path, path);
} else {
this.storage = storage;
this.path = path;
}
}
public boolean equals(Object obj) {
return obj instanceof StorageView view
&& storage.equals(view.storage)
&& Arrays.equals(path, view.path);
}
public int hashCode() {
return storage.hashCode() ^ Arrays.hashCode(path);
}
/**
* Turn the view into a string representation.
*
* @return Basically, key().
*/
public String toString() {
return key();
}
/**
* Combine two Object arrays.
*
* @param a Preceding array
* @param b Succeeding array
* @return Combined array
*/
public static Object[] combine(Object[] a, Object[] b) {
var res = new Object[a.length + b.length];
arraycopy(a, 0, res, 0, a.length);
arraycopy(b, 0, res, a.length, b.length);
return res;
}
//
// StorageView-only features
//
/**
* Check if this view directly points to its storage.
*
* @return True if this path is empty.
*/
public boolean direct() {
return path.length == 0;
}
/**
* Check if this view includes a different view.
*
* @param view View to check.
* @return True if other view path starts with this view path.
*/
public boolean parentOf(StorageView view) {
return storage.equals(view.storage)
&& path.length < view.path.length
&& range(0, path.length)
.allMatch(i -> Objects.equals(path[i], view.path[i]));
}
/**
* Get parent of this view.
*
* @return Parent view or itself if direct.
*/
public StorageView parent() {
return direct()
? this
: new StorageView(storage, copyOf(path, path.length - 1));
}
/**
* Turn the path object array into readable dot notation.
*
* @return Path parts in their string representations separated by a dot.
*/
public String key() {
return stream(path)
.map(Objects::toString)
.collect(joining("."));
}
/**
* Get last part of the path.
*
* @return Last part of the path.
*/
public Object last() {
return direct() ? "" : path[path.length - 1];
}
/**
* Go through all sublevels of the level given by this path.
*
* @param level Action to perform on a sublevel.
*/
public void forEachLevel(Consumer level) {
levels().forEach(level);
}
/**
* Go through all values in the level given by this path.
*
* @param values Action to perform on the values.
*/
public void forEachValue(BiConsumer values) {
values().forEach(values);
}
/**
* Go through all values in the level given by this path recursively.
*
* @param values Action to perform on the values.
*/
public void forEachValueDeep(BiConsumer values) {
valuesDeep().forEach(values);
}
//
// Overrides
//
public Map values(Object... path) {
return storage.values(combine(this.path, path));
}
public Map valuesDeep(Object... path) {
return storage.valuesDeep(combine(this.path, path));
}
public boolean existsLevel(Object... path) {
return storage.existsLevel(path);
}
public List levels(Object... path) {
return storage.levels(combine(this.path, path));
}
public StorageView set(Object... pathAndValue) {
storage.set(combine(path, pathAndValue));
return this;
}
public StorageView remove(Object... path) {
storage.remove(combine(this.path, path));
return this;
}
public StorageView removeLevel(Object... path) {
storage.removeLevel(combine(this.path, path));
return this;
}
public Optional find(Object... path) {
return storage.find(combine(this.path, path));
}
}