001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2025–2026 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.construct.element;
015
016import java.lang.constant.ClassDesc;
017import java.lang.constant.Constable;
018import java.lang.constant.DynamicConstantDesc;
019import java.lang.constant.MethodHandleDesc;
020import java.lang.constant.MethodTypeDesc;
021
022import java.util.Objects;
023import java.util.Optional;
024
025import java.util.stream.IntStream;
026
027import javax.lang.model.element.Name;
028
029import static java.lang.constant.ConstantDescs.BSM_INVOKE;
030import static java.lang.constant.ConstantDescs.CD_String;
031
032import static java.lang.constant.MethodHandleDesc.ofConstructor;
033
034import static java.util.Objects.requireNonNull;
035
036/**
037 * A {@link Name} implementation based on {@link String}s.
038 *
039 * <p>This {@link Name} implementation differs from {@link StringName} in that there is no {@link
040 * org.microbean.construct.PrimordialDomain} involved, and therefore no notion of any kind of delegate.</p>
041 *
042 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
043 *
044 * @see Name
045 *
046 * @see StringName
047 */
048public final class SyntheticName implements Constable, Name {
049
050
051  /*
052   * Instance fields.
053   */
054
055
056  private final String value;
057
058
059  /*
060   * Constructors.
061   */
062
063
064  /**
065   * Creates a new {@link SyntheticName}.
066   *
067   * @param value the actual name; must not be {@code null}
068   *
069   * @exception NullPointerException if {@code value} is {@code null}
070   */
071  public SyntheticName(final Name value) {
072    super();
073    this.value = value instanceof SyntheticName sn ? sn.value : value.toString();
074  }
075  
076  /**
077   * Creates a new {@link SyntheticName}.
078   *
079   * @param value the actual name; must not be {@code null}
080   *
081   * @exception NullPointerException if {@code value} is {@code null}
082   */
083  public SyntheticName(final String value) {
084    super();
085    this.value = requireNonNull(value, "value");
086  }
087
088
089  /*
090   * Instance methods.
091   */
092
093
094  @Override // Name (CharSequence)
095  public final char charAt(final int index) {
096    return this.value.charAt(index);
097  }
098
099  @Override // Name (CharSequence)
100  public final IntStream chars() {
101    return this.value.chars();
102  }
103
104  @Override // Name (CharSequence)
105  public final IntStream codePoints() {
106    return this.value.codePoints();
107  }
108
109  @Override // Name
110  public final boolean contentEquals(final CharSequence cs) {
111    return this == cs || cs != null && this.value.contentEquals(cs.toString());
112  }
113
114  @Override // Constable
115  public final Optional<DynamicConstantDesc<SyntheticName>> describeConstable() {
116    return
117      Optional.of(DynamicConstantDesc.ofNamed(BSM_INVOKE,
118                                              this.value,
119                                              this.getClass().describeConstable().orElseThrow(),
120                                              ofConstructor(this.getClass().describeConstable().orElseThrow(),
121                                                            CD_String),
122                                              this.value));
123  }
124
125  @Override // Object
126  public final boolean equals(final Object other) {
127    return this == other || switch (other) {
128    case null -> false;
129    case SyntheticName sn when this.getClass() == sn.getClass() -> Objects.equals(this.value, sn.value);
130    default -> false;
131    };
132  }
133
134  @Override // Object
135  public final int hashCode() {
136    return this.value.hashCode();
137  }
138
139  @Override // Name (CharSequence)
140  public final boolean isEmpty() {
141    return this.value.isEmpty();
142  }
143
144  @Override // Name (CharSequence)
145  public final int length() {
146    return this.value.length();
147  }
148
149  @Override // Name (CharSequence)
150  public final CharSequence subSequence(final int start, final int end) {
151    return this.value.subSequence(start, end);
152  }
153
154  @Override // Name (CharSequence)
155  public final String toString() {
156    return this.value;
157  }
158
159}