001package com.github.dkfellows.notabuilder; 002 003/** 004 * A record that has four fields. 005 * @param foo The foo field. 006 * @param bar The bar field. 007 * @param grill The grill field. 008 * @param quux The quux field. 009 */ 010public record ThingRecord(int foo, int bar, double grill, String quux) { 011 private static final Foo DEFAULT_FOO = new Foo(0); 012 private static final Bar DEFAULT_BAR = new Bar(0); 013 private static final Grill DEFAULT_GRILL = new Grill(0.0); 014 private static final Quux DEFAULT_QUUX = new Quux(""); 015 016 /** Helper because the canonical constructor must be called as the first statement. 017 * @param <T> The type of argument being extracted. 018 * @param args The argument list to extract from. 019 * @param defaultValue The default for the argument being extracted. 020 * Note that <em>this also tells the runtime code what argument to extract</em>. 021 * @return The extracted argument, if present, or a default. 022 */ 023 private static <T extends Args> T select(Args[] args, T defaultValue) { 024 T val = defaultValue; 025 for (var arg: args) { 026 if (arg.getClass() == val.getClass()) { 027 @SuppressWarnings("unchecked") 028 var thisVal = (T) arg; 029 val = thisVal; 030 } 031 } 032 return val; 033 } 034 035 /** 036 * Make an instance of the record. 037 * @param args The labelled non-default arguments to pass. 038 * @see ThingRecord.Args#foo(int) 039 * @see ThingRecord.Args#bar(int) 040 * @see ThingRecord.Args#grill(double) 041 * @see ThingRecord.Args#quux(String) 042 */ 043 public ThingRecord(Args... args) { 044 this(select(args, DEFAULT_FOO).foo(), 045 select(args, DEFAULT_BAR).bar(), 046 select(args, DEFAULT_GRILL).grill(), 047 select(args, DEFAULT_QUUX).quux()); 048 } 049 050 /** Argument labeller. */ 051 public sealed interface Args permits Foo, Bar, Grill, Quux { 052 /** 053 * Label a value as a {@link ThingRecord#foo()}. 054 * @param value The value to label. 055 * @return The labelled value. 056 */ 057 public static Args foo(int value) { 058 return new Foo(value); 059 } 060 061 /** 062 * Label a value as a {@link ThingRecord#bar()}. 063 * @param value The value to label. 064 * @return The labelled value. 065 */ 066 public static Args bar(int value) { 067 return new Bar(value); 068 } 069 070 /** 071 * Label a value as a {@link ThingRecord#grill()}. 072 * @param value The value to label. 073 * @return The labelled value. 074 */ 075 public static Args grill(double value) { 076 return new Grill(value); 077 } 078 079 /** 080 * Label a value as a {@link ThingRecord#quux()}. 081 * @param value The value to label. 082 * @return The labelled value. 083 */ 084 public static Args quux(String value) { 085 return new Quux(value); 086 } 087 } 088 089 private record Foo(int foo) implements Args {} 090 private record Bar(int bar) implements Args {} 091 private record Grill(double grill) implements Args {} 092 private record Quux(String quux) implements Args {} 093}