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.impl.backend.memory; 018 019import ca.stellardrift.permissionsex.context.ContextValue; 020import ca.stellardrift.permissionsex.impl.util.PCollections; 021import ca.stellardrift.permissionsex.subject.ImmutableSubjectData; 022import ca.stellardrift.permissionsex.subject.Segment; 023import ca.stellardrift.permissionsex.subject.SubjectRef; 024import org.checkerframework.checker.nullness.qual.Nullable; 025import org.pcollections.PMap; 026import org.pcollections.PSet; 027import org.pcollections.PVector; 028import org.spongepowered.configurate.objectmapping.ObjectMapper; 029import org.spongepowered.configurate.serialize.SerializationException; 030import org.spongepowered.configurate.objectmapping.ConfigSerializable; 031import org.spongepowered.configurate.objectmapping.meta.Setting; 032 033import java.util.List; 034import java.util.Map; 035import java.util.Set; 036import java.util.function.BiFunction; 037import java.util.function.Function; 038import java.util.function.UnaryOperator; 039 040import static java.util.Objects.requireNonNull; 041 042public class MemorySubjectData implements ImmutableSubjectData { 043 protected static final ObjectMapper<MemorySegment> MAPPER; 044 static { 045 try { 046 MAPPER = ObjectMapper.factory().get(MemorySegment.class); 047 } catch (SerializationException e) { 048 throw new ExceptionInInitializerError(e); // This debug indicates a programming issue 049 } 050 } 051 052 053 protected final PMap<PSet<ContextValue<?>>, MemorySegment> segments; 054 055 protected MemorySubjectData() { 056 this.segments = PCollections.map(); 057 } 058 059 protected MemorySubjectData(final Map<PSet<ContextValue<?>>, MemorySegment> segments) { 060 this.segments = PCollections.asMap(segments); 061 } 062 063 protected MemorySubjectData newData(final PMap<PSet<ContextValue<?>>, MemorySegment> contexts) { 064 if (contexts == this.segments) { 065 return this; 066 } 067 return new MemorySubjectData(contexts); 068 } 069 070 @Override 071 @SuppressWarnings({"unchecked", "rawtypes"}) 072 public Map<Set<ContextValue<?>>, Segment> segments() { 073 return (Map) this.segments; 074 } 075 076 @Override 077 public ImmutableSubjectData withSegments(final BiFunction<Set<ContextValue<?>>, Segment, Segment> transformer) { 078 PMap<PSet<ContextValue<?>>, MemorySegment> output = this.segments; 079 for (final Map.Entry<PSet<ContextValue<?>>, MemorySegment> entry : this.segments.entrySet()) { 080 final MemorySegment mapped = MemorySegment.from(transformer.apply(entry.getKey(), entry.getValue())); 081 if (mapped != entry.getValue()) { 082 if (mapped.empty()) { 083 output = output.minus(entry.getKey()); 084 } else { 085 output = output.plus(entry.getKey(), mapped); 086 } 087 } 088 } 089 return newData(output); 090 } 091 092 @Override 093 public ImmutableSubjectData withSegment(final Set<ContextValue<?>> contexts, final UnaryOperator<Segment> operation) { 094 final PSet<ContextValue<?>> pContexts = PCollections.asSet(contexts); 095 final Segment original = this.segments.get(pContexts); 096 final MemorySegment mapped = MemorySegment.from(operation.apply(original == null ? MemorySegment.create() : original)); 097 if (original != mapped) { 098 return newData(mapped.empty() ? this.segments.minus(pContexts) : this.segments.plus(pContexts, mapped)); 099 } else { 100 return this; 101 } 102 } 103 104 @Override 105 public <V> Map<Set<ContextValue<?>>, V> mapSegmentValues(final Function<Segment, V> mapper) { 106 requireNonNull(mapper, "mapper"); 107 return PCollections.asMap(this.segments, (k, v) -> k, (k, v) -> mapper.apply(v)); 108 } 109 110 @Override 111 public <V> @Nullable V mapSegment(final Set<ContextValue<?>> contexts, final Function<Segment, V> mapper) { 112 requireNonNull(mapper, "mapper"); 113 final MemorySegment segment = this.segments.get(PCollections.asSet(requireNonNull(contexts, "contexts"))); 114 if (segment != null) { 115 return mapper.apply(segment); 116 } 117 return null; 118 } 119 120 @Override 121 public MemorySegment segment(final Set<ContextValue<?>> contexts) { 122 MemorySegment res = this.segments.get(PCollections.asSet(contexts)); 123 if (res == null) { 124 res = MemorySegment.create(); 125 } 126 return res; 127 } 128 129 @Override 130 public ImmutableSubjectData withSegment(final Set<ContextValue<?>> contexts, final Segment segment) { 131 PMap<PSet<ContextValue<?>>, MemorySegment> segments; 132 if (segment.empty()) { 133 segments = this.segments.minus(PCollections.asSet(contexts)); 134 } else { 135 segments = this.segments.plus(PCollections.asSet(contexts), MemorySegment.from(segment)); 136 } 137 return segments == this.segments ? this : newData(segments); 138 } 139 140 @Override 141 public Set<PSet<ContextValue<?>>> activeContexts() { 142 return this.segments.keySet(); 143 } 144 145 @Override 146 public String toString() { 147 return "MemorySubjectData{" + 148 "segments=" + this.segments + 149 '}'; 150 } 151 152 @ConfigSerializable 153 protected static class MemorySegment implements Segment { 154 @Setting private PMap<String, Integer> permissions; 155 @Setting private PMap<String, String> options; 156 @Setting private PVector<SubjectRef<?>> parents; 157 @Nullable @Setting("permissions-default") private Integer defaultValue; 158 159 static MemorySegment create() { 160 return new MemorySegment( 161 PCollections.map(), 162 PCollections.map(), 163 PCollections.vector(), 164 null 165 ); 166 } 167 168 static MemorySegment from(final Segment other) { 169 if (other instanceof MemorySegment) { 170 return (MemorySegment) other; 171 } else { 172 return new MemorySegment( 173 PCollections.asMap(other.permissions()), 174 PCollections.asMap(other.options()), 175 PCollections.narrow(PCollections.asVector(other.parents())), 176 other.fallbackPermission() 177 ); 178 } 179 } 180 181 MemorySegment(final PMap<String, Integer> permissions, final PMap<String, String> options, final PVector<SubjectRef<?>> parents, final @Nullable Integer defaultValue) { 182 this.permissions = permissions; 183 this.options = options; 184 this.parents = parents; 185 this.defaultValue = defaultValue; 186 } 187 188 189 private MemorySegment() { // Objectmapper constructor 190 } 191 192 @Override 193 public Map<String, String> options() { 194 return this.options; 195 } 196 197 @Override 198 public MemorySegment withOption(final String key, final String value) { 199 return new MemorySegment(this.permissions, this.options.plus(key, value), this.parents, this.defaultValue); 200 } 201 202 @Override 203 public MemorySegment withoutOption(final String key) { 204 if (!this.options.containsKey(key)) { 205 return this; 206 } 207 return new MemorySegment(this.permissions, this.options.minus(key), this.parents, this.defaultValue); 208 209 } 210 211 @Override 212 public MemorySegment withOptions(final Map<String, String> values) { 213 return new MemorySegment(this.permissions, PCollections.asMap(values), this.parents, this.defaultValue); 214 } 215 216 @Override 217 public MemorySegment withoutOptions() { 218 return new MemorySegment(this.permissions, PCollections.map(), this.parents, this.defaultValue); 219 } 220 221 @Override 222 public Map<String, Integer> permissions() { 223 return this.permissions; 224 } 225 226 @Override 227 public MemorySegment withPermission(final String permission, final int value) { 228 return new MemorySegment( 229 value == 0 ? this.permissions.minus(permission) : this.permissions.plus(permission, value), 230 this.options, 231 this.parents, 232 this.defaultValue); 233 234 } 235 236 @Override 237 public MemorySegment withPermissions(final Map<String, Integer> values) { 238 return new MemorySegment(PCollections.asMap(values), this.options, this.parents, this.defaultValue); 239 } 240 241 @Override 242 public MemorySegment withoutPermissions() { 243 return new MemorySegment(PCollections.map(), this.options, this.parents, this.defaultValue); 244 } 245 246 @Override 247 public List<SubjectRef<?>> parents() { 248 return this.parents; 249 } 250 251 @Override 252 public <I> MemorySegment plusParent(final SubjectRef<I> parent) { 253 return new MemorySegment(this.permissions, this.options, this.parents.plus(0, SubjectRef.mapKeySafe(parent)), this.defaultValue); 254 } 255 256 @Override 257 public <I> MemorySegment minusParent(final SubjectRef<I> parent) { 258 if (this.parents.isEmpty()) { 259 return this; 260 } 261 262 return new MemorySegment(this.permissions, this.options, this.parents.minus(SubjectRef.mapKeySafe(parent)), this.defaultValue); 263 } 264 265 @Override 266 public MemorySegment withParents(List<SubjectRef<?>> parents) { 267 return new MemorySegment(this.permissions, this.options, PCollections.asVector(parents), this.defaultValue); 268 } 269 270 @Override 271 public MemorySegment withoutParents() { 272 return new MemorySegment(this.permissions, this.options, PCollections.vector(), this.defaultValue); 273 } 274 275 @Override 276 public int fallbackPermission() { 277 return this.defaultValue == null ? 0 : this.defaultValue; 278 } 279 280 @Override 281 public Segment withFallbackPermission(int defaultValue) { 282 return new MemorySegment(this.permissions, this.options, this.parents, defaultValue); 283 } 284 285 @Override 286 public Segment cleared() { 287 return new MemorySegment(PCollections.map(), PCollections.map(), PCollections.vector(), null); 288 } 289 290 @Override 291 public String toString() { 292 return "DataEntry{" + 293 "permissions=" + this.permissions + 294 ", options=" + this.options + 295 ", parents=" + this.parents + 296 ", defaultValue=" + this.defaultValue + 297 '}'; 298 } 299 300 @Override 301 public boolean empty() { 302 return this.permissions.isEmpty() 303 && this.options.isEmpty() 304 && this.parents.isEmpty() 305 && this.defaultValue == null; 306 } 307 } 308}