Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/main/java/net/kyori/option/Option.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of option, licensed under the MIT License.
*
* Copyright (c) 2023 KyoriPowered
* Copyright (c) 2023-2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -47,9 +47,11 @@ public interface Option<V> {
* @param defaultValue the default value
* @return the flag instance
* @since 1.0.0
* @deprecated For removal since 1.1.0, create new options within an {@link OptionSchema} instead
*/
@Deprecated
static Option<Boolean> booleanOption(final String id, final boolean defaultValue) {
return OptionImpl.option(id, Boolean.class, defaultValue);
return OptionSchema.globalSchema().booleanOption(id, defaultValue);
}

/**
Expand All @@ -63,9 +65,11 @@ static Option<Boolean> booleanOption(final String id, final boolean defaultValue
* @param <E> the enum type
* @return the flag instance
* @since 1.0.0
* @deprecated For removal since 1.1.0, create new options within an {@link OptionSchema} instead
*/
@Deprecated
static <E extends Enum<E>> Option<E> enumOption(final String id, final Class<E> enumClazz, final E defaultValue) {
return OptionImpl.option(id, enumClazz, defaultValue);
return OptionSchema.globalSchema().enumOption(id, enumClazz, defaultValue);
}

/**
Expand Down
19 changes: 1 addition & 18 deletions src/main/java/net/kyori/option/OptionImpl.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of option, licensed under the MIT License.
*
* Copyright (c) 2023 KyoriPowered
* Copyright (c) 2023-2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand All @@ -24,15 +24,10 @@
package net.kyori.option;

import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static java.util.Objects.requireNonNull;

final class OptionImpl<V> implements Option<V> {
private static final Set<String> KNOWN_KEYS = ConcurrentHashMap.newKeySet();

private final String id;
private final Class<V> type;
Expand All @@ -44,18 +39,6 @@ final class OptionImpl<V> implements Option<V> {
this.defaultValue = defaultValue;
}

static <T> Option<T> option(final String id, final Class<T> type, final @Nullable T defaultValue) {
if (!KNOWN_KEYS.add(id)) {
throw new IllegalStateException("Key " + id + " has already been used. Option keys must be unique.");
}

return new OptionImpl<>(
requireNonNull(id, "id"),
requireNonNull(type, "type"),
defaultValue
);
}

@Override
public @NotNull String id() {
return this.id;
Expand Down
203 changes: 203 additions & 0 deletions src/main/java/net/kyori/option/OptionSchema.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/*
* This file is part of option, licensed under the MIT License.
*
* Copyright (c) 2025 KyoriPowered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.kyori.option;

import java.util.Set;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static java.util.Objects.requireNonNull;

/**
* Represents a 'universe' of known options.
*
* @since 1.1.0
*/
@ApiStatus.NonExtendable
public interface OptionSchema {
/**
* Retrieve the globally-shared option schema.
*
* <p>This mostly exists for backwards compatibility, and should not be used in new software.</p>
*
* @return the global schema
* @since 1.1.0
*/
static OptionSchema.@NotNull Mutable globalSchema() {
return OptionSchemaImpl.Instances.GLOBAL;
}

/**
* Return a mutable schema that's a child of the specified schema.
*
* <p>This schema will inherit all options defined in the parent schema at the time the child schema is created.</p>
*
* @param schema the parent schema
* @return the mutable child schema
* @since 1.1.0
*/
static OptionSchema.@NotNull Mutable childSchema(final @NotNull OptionSchema schema) {
final OptionSchemaImpl impl;
if (schema instanceof OptionSchemaImpl.MutableImpl) {
impl = (OptionSchemaImpl) ((Mutable) schema).frozenView();
} else {
impl = (OptionSchemaImpl) schema;
}

return new OptionSchemaImpl(requireNonNull(impl, "impl")).new MutableImpl();
}

/**
* Create an empty schema inheriting from nothing but the contents
* of the global schema at invocation time.
*
* @return a mutable schema
* @since 1.1.0
*/
static OptionSchema.@NotNull Mutable emptySchema() {
return new OptionSchemaImpl(null).new MutableImpl();
}

/**
* Return all known options contained within this schema, and recursively through its parents.
*
* @return known options
* @since 1.1.0
*/
@NotNull Set<Option<?>> knownOptions();

/**
* Return whether the provided option is known within this scheam.
*
* @param option the option
* @return whether the option is known
* @since 1.1.0
*/
boolean has(final @NotNull Option<?> option);

/**
* Create a builder for an unversioned option state containing only options within this schema.
*
* @return the builder
* @since 1.1.0
*/
OptionState.@NotNull Builder stateBuilder();

/**
* Create a builder for a versioned option state containing only values for options within this schema.
*
* @return the builder
* @since 1.1.0
*/
OptionState.@NotNull VersionedBuilder versionedStateBuilder();

/**
* Create an empty option state within this schema.
*
* @return the empty state
* @since 1.1.0
*/
OptionState emptyState();

/**
* A mutable view of an option schema that allows registering new options into the schema.
*
* @since 1.1.0
*/
@ApiStatus.NonExtendable
interface Mutable extends OptionSchema {
/**
* Create an option with a string value type.
*
* <p>Flag keys must not be reused within a schema tree.</p>
*
* @param id the flag id
* @param defaultValue the default value
* @return the flag instance
* @since 1.1.0
*/
@NotNull Option<String> stringOption(final @NotNull String id, final @Nullable String defaultValue);

/**
* Create an option with a boolean value type.
*
* <p>Flag keys must not be reused within a schema tree.</p>
*
* @param id the flag id
* @param defaultValue the default value
* @return the flag instance
* @since 1.1.0
*/
@NotNull Option<Boolean> booleanOption(final @NotNull String id, final boolean defaultValue);

/**
* Create an option with an integer value type.
*
* <p>Flag keys must not be reused within a schema tree.</p>
*
* @param id the flag id
* @param defaultValue the default value
* @return the flag instance
* @since 1.1.0
*/
@NotNull Option<Integer> intOption(final @NotNull String id, final int defaultValue);

/**
* Create an option with a double value type.
*
* <p>Flag keys must not be reused within a schema tree.</p>
*
* @param id the flag id
* @param defaultValue the default value
* @return the flag instance
* @since 1.1.0
*/
@NotNull Option<Double> doubleOption(final @NotNull String id, final double defaultValue);

/**
* Create an option with an enum value type.
*
* <p>Flag keys must not be reused within a schema tree.</p>
*
* @param id the flag id
* @param enumClazz the value type
* @param defaultValue the default value
* @param <E> the enum type
* @return the flag instance
* @since 1.1.0
*/
<E extends Enum<E>> @NotNull Option<E> enumOption(final @NotNull String id, final @NotNull Class<E> enumClazz, final @Nullable E defaultValue);

/**
* Return a view of this schema which does not allow consumers to register new options.
*
* <p>This allows exposing known options within a schema without the risk of having values polluted.</p>
*
* @return the frozen view of this schema
* @since 1.1.0
*/
@NotNull OptionSchema frozenView();
}
}
Loading