001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2025 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
006 * the License. You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
012 * specific language governing permissions and limitations under the License.
013 */
014package org.microbean.attributes;
015
016import java.lang.constant.ClassDesc;
017import java.lang.constant.DynamicConstantDesc;
018import java.lang.constant.MethodHandleDesc;
019import java.lang.constant.MethodTypeDesc;
020
021import java.util.Objects;
022import java.util.Optional;
023
024import static java.lang.constant.ConstantDescs.BSM_INVOKE;
025import static java.lang.constant.ConstantDescs.CD_Enum;
026import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC;
027
028/**
029 * A {@link Value} whose value is an {@code Enum}.
030 *
031 * @param <E> the type of the {@link Enum}
032 *
033 * @param value the value
034 *
035 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
036 */
037public final record EnumValue<E extends Enum<E>>(E value) implements Value<EnumValue<E>> {
038
039  /**
040   * Creates a new {@link EnumValue}.
041   *
042   * @param value the value; must not be {@code null}
043   *
044   * @exception NullPointerException if {@code value} is {@code null}
045   */
046  public EnumValue {
047    Objects.requireNonNull(value, "value");
048  }
049
050  @Override // Comparable<EnumValue>
051  public final int compareTo(final EnumValue<E> other) {
052    return
053      other == null ? -1 :
054      this.equals(other) ? 0 :
055      this.value().compareTo(other.value());
056  }
057
058  @Override // Constable
059  public final Optional<DynamicConstantDesc<EnumValue<E>>> describeConstable() {
060    final ClassDesc cd = ClassDesc.of(this.getClass().getName());
061    return
062      Optional.of(DynamicConstantDesc.of(BSM_INVOKE,
063                                         MethodHandleDesc.ofMethod(STATIC,
064                                                                   cd,
065                                                                   "of",
066                                                                   MethodTypeDesc.of(cd,
067                                                                                     CD_Enum)),
068                                         this.value().describeConstable().orElseThrow()));
069  }
070
071  @Override // Record
072  public final boolean equals(final Object other) {
073    return
074      other == this ||
075      // Follow java.lang.annotation.Annotation requirements.
076      other != null && other.getClass() == this.getClass() && this.value().equals(((EnumValue<?>)other).value());
077  }
078
079  @Override // Record
080  public final int hashCode() {
081    // Follow java.lang.annotation.Annotation requirements.
082    return this.value().hashCode();
083  }
084
085  @Override // Record
086  public final String toString() {
087    return this.value().toString();
088  }
089
090  /**
091   * Returns an {@link EnumValue} suitable for the supplied arguments.
092   *
093   * @param <E> the type of the {@link Enum}
094   *
095   * @param e a non-{@code null} {@code Enum}
096   *
097   * @return a non-{@code null} {@link EnumValue}
098   *
099   * @exception NullPointerException if {@code e} is {@code null}
100   */
101  public static final <E extends Enum<E>> EnumValue<E> of(final E e) {
102    return new EnumValue<>(e);
103  }
104
105}