001/* 002 * PermissionsEx 003 * Copyright (C) zml and PermissionsEx 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 ca.stellardrift.permissionsex.context; 018 019import ca.stellardrift.permissionsex.subject.CalculatedSubject; 020import org.checkerframework.checker.nullness.qual.Nullable; 021import org.pcollections.HashTreePSet; 022 023import java.util.Objects; 024import java.util.Set; 025import java.util.function.Consumer; 026 027import static java.util.Objects.requireNonNull; 028 029/** 030 * A specific type of context, for example {@code world}, {@code server-tag}, or {@code until}. 031 * 032 * @since 2.0.0 033 */ 034public abstract class ContextDefinition<V> { 035 private final String name; 036 037 protected ContextDefinition(final String name) { 038 this.name = requireNonNull(name, "name"); 039 } 040 041 /** 042 * Create a new context value based on this definition. 043 * 044 * @param value the value to associate with this definition 045 * @return a new context value holder 046 * @since 2.0.0 047 */ 048 public final ContextValue<V> createValue(final V value) { 049 return new ContextValue<>(this, value); 050 } 051 052 /** 053 * Gets the name for this context definition. 054 * 055 * @return the definition name 056 * @since 2.0.0 057 */ 058 public final String name() { 059 return this.name; 060 } 061 062 /** 063 * Given a parsed value, write data out as a string. 064 * 065 * @param canonicalValue Parsed value 066 * @return serialized form of the value 067 * @since 2.0.0 068 */ 069 public abstract String serialize(V canonicalValue); 070 071 /** 072 * Given a string (which may be in user format), return a parsed object. 073 * 074 * @param userValue the value as a string, such as when provided by user input 075 * @return V a deserialized value, or {@code null if unsuccessful} 076 * @since 2.0.0 077 */ 078 public abstract @Nullable V deserialize(String userValue); 079 080 /** 081 * Given a defined context and the active value (provided by {@link #accumulateCurrentValues(CalculatedSubject, Consumer)}), 082 * return whether the active value matches the defined value. 083 * 084 * @param ctx a defined context 085 * @param activeValue a value to test for membership in {@code ctx} 086 * @return whether a match was found 087 * @since 2.0.0 088 */ 089 public final boolean matches(final ContextValue<V> ctx, final V activeValue) { 090 return matches(ctx.getParsedValue(this), activeValue); 091 } 092 093 /** 094 * Get whether two values match. 095 * 096 * @param ownVal the defined value 097 * @param testVal the value being tested against 098 * @return whether {@code testVal} is an element of {@code ownVal} 099 */ 100 public boolean matches(V ownVal, V testVal) { 101 return Objects.equals(ownVal, testVal); 102 } 103 104 /** 105 * Given a player, calculate active context types 106 * 107 * @param subject The subject active contexts are being calculated for 108 * @param consumer A function that will take the returned value and add it to the active context set 109 * @since 2.0.0 110 */ 111 public abstract void accumulateCurrentValues(CalculatedSubject subject, Consumer<V> consumer); 112 113 /** 114 * Given a subject, suggest a set of values that may be valid for this context. This need not be an exhaustive list, 115 * or could even be an empty list, but allows providing users possible suggestions to what sensible values for a context may be. 116 * 117 * @param subject a subject to query for environment information 118 * @return a set of possible values 119 * @since 2.0.0 120 */ 121 public Set<V> suggestValues(final CalculatedSubject subject) { 122 return HashTreePSet.empty(); 123 } 124 125 @Override 126 public String toString() { 127 return "ContextDefinition{name='" + this.name + "'}"; 128 } 129 130 @Override 131 public boolean equals(final @Nullable Object other) { 132 if (this == other) return true; 133 if (!(other instanceof ContextDefinition<?>)) return false; 134 135 return this.name.equals(((ContextDefinition<?>) other).name); 136 } 137 138 @Override 139 public int hashCode() { 140 return 31 * this.name.hashCode(); 141 } 142} 143 144