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.util.List; 017 018import java.lang.constant.ClassDesc; 019import java.lang.constant.DynamicConstantDesc; 020import java.lang.constant.MethodHandleDesc; 021import java.lang.constant.MethodTypeDesc; 022 023import java.util.Optional; 024 025import org.microbean.constant.Constables; 026 027import static java.lang.constant.ConstantDescs.BSM_INVOKE; 028import static java.lang.constant.ConstantDescs.CD_List; 029import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC; 030 031/** 032 * A {@link Value} holding other {@link Value}s. 033 * 034 * @param <T> the type of the {@link Value}s 035 * 036 * @param value a non-{@code null} {@link List} of {@link Value}s 037 * 038 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 039 */ 040public final record ListValue<T extends Value<T>>(List<T> value) implements Value<ListValue<T>> { 041 042 /** 043 * Creates a new {@link ListValue}. 044 * 045 * @param value a non-{@code null} {@link List} of {@link Value}s 046 * 047 * @exception NullPointerException if {@code value} is {@code null} 048 */ 049 public ListValue { 050 value = List.copyOf(value); 051 } 052 053 @Override // Comparable<ListValue<T>> 054 public final int compareTo(final ListValue<T> other) { 055 if (other == null) { 056 return -1; 057 } else if (this.equals(other)) { 058 return 0; 059 } 060 return this.toString().compareTo(other.toString()); 061 } 062 063 @Override // Constable 064 public final Optional<DynamicConstantDesc<ListValue<T>>> describeConstable() { 065 final ClassDesc me = ClassDesc.of(this.getClass().getName()); 066 return Constables.describeConstable(this.value()) 067 .map(valueDesc -> DynamicConstantDesc.of(BSM_INVOKE, 068 MethodHandleDesc.ofMethod(STATIC, 069 me, 070 "of", 071 MethodTypeDesc.of(me, 072 CD_List)), 073 valueDesc)); 074 } 075 076 @Override // Record 077 public final boolean equals(final Object other) { 078 return 079 other == this || 080 // Follow java.lang.annotation.Annotation requirements. 081 other != null && other.getClass() == this.getClass() && this.value().equals(((ListValue<?>)other).value()); 082 } 083 084 @Override // Record 085 public final int hashCode() { 086 // Follow java.lang.annotation.Annotation requirements. 087 return this.value().hashCode(); 088 } 089 090 @Override // Record 091 public final String toString() { 092 return this.value().toString(); 093 } 094 095 /** 096 * Returns a {@link ListValue} suitable for the supplied argument. 097 * 098 * @param <T> the type of {@link Value} held by the returned {@link ListValue} 099 * 100 * @param value a non-{@code null} {@link List} of suitably-typed {@link Value}s 101 * 102 * @return a non-{@code null} {@link ListValue} 103 * 104 * @exception NullPointerException if {@code value} is {@code null} 105 */ 106 @SuppressWarnings("unchecked") 107 // Called by #describeConstable() 108 public static final <T extends Value<T>> ListValue<T> of(final List<T> value) { 109 return new ListValue<>(value); 110 } 111 112}