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.DirectMethodHandleDesc.Kind.STATIC;
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 String value) {
072    super();
073    this.value = requireNonNull(value, "value");
074  }
075
076
077  /*
078   * Instance methods.
079   */
080
081
082  @Override // Name (CharSequence)
083  public final char charAt(final int index) {
084    return this.value.charAt(index);
085  }
086
087  @Override // Name (CharSequence)
088  public final IntStream chars() {
089    return this.value.chars();
090  }
091
092  @Override // Name (CharSequence)
093  public final IntStream codePoints() {
094    return this.value.codePoints();
095  }
096
097  @Override // Name
098  public final boolean contentEquals(final CharSequence cs) {
099    return this == cs || cs != null && this.value.contentEquals(cs.toString());
100  }
101
102  @Override // Constable
103  public final Optional<DynamicConstantDesc<SyntheticName>> describeConstable() {
104    return
105      Optional.of(DynamicConstantDesc.of(BSM_INVOKE,
106                                         MethodHandleDesc.ofMethod(STATIC,
107                                                                   ClassDesc.of(this.getClass().getName()),
108                                                                   "of",
109                                                                   MethodTypeDesc.of(CD_String)),
110                                         this.value));
111  }
112
113  @Override // Object
114  public final boolean equals(final Object other) {
115    return this == other || switch (other) {
116    case null -> false;
117    case SyntheticName sn when this.getClass() == sn.getClass() -> Objects.equals(this.value, sn.value);
118    default -> false;
119    };
120  }
121
122  @Override // Object
123  public final int hashCode() {
124    return this.value.hashCode();
125  }
126
127  @Override // Name (CharSequence)
128  public final boolean isEmpty() {
129    return this.value.isEmpty();
130  }
131
132  @Override // Name (CharSequence)
133  public final int length() {
134    return this.value.length();
135  }
136
137  @Override // Name (CharSequence)
138  public final CharSequence subSequence(final int start, final int end) {
139    return this.value.subSequence(start, end);
140  }
141
142  @Override // Name (CharSequence)
143  public final String toString() {
144    return this.value;
145  }
146
147}